Support static function variables (#3830)

This commit is contained in:
Ryszard Rozak 2023-01-23 14:35:10 +01:00 committed by GitHub
parent 8a85cedaf5
commit b56e7f6910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 85 additions and 59 deletions

View File

@ -19,6 +19,7 @@
// Look for BEGINs
// BEGIN(VAR...) -> VAR ... {renamed}
// FOR -> WHILEs
// Move static function variables and their AstInitialStatic blocks before a function
//
// There are two scopes; named BEGINs change %m and variable scopes.
// Unnamed BEGINs change only variable, not $display("%m") scope.
@ -64,13 +65,14 @@ private:
// STATE
BeginState* const m_statep; // Current global state
AstNodeModule* m_modp = nullptr; // Current module
const AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp
string m_displayScope; // Name of %m in $display/AstScopeName
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_ifDepth = 0; // Current if depth
bool m_keepBegins = false; // True if begins should not be inlined
std::set<AstVar*> m_staticFuncVars; // Static variables from m_ftaskp
// METHODS
@ -121,6 +123,25 @@ private:
}
}
void renameAndStaticsRecurse(AstNode* const nodep) {
// Rename references and move InitialStatic items
if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) {
const auto it = m_staticFuncVars.find(varrefp->varp());
if (it != m_staticFuncVars.end()) varrefp->name((*it)->name());
}
if (nodep->op1p()) renameAndStaticsRecurse(nodep->op1p());
if (nodep->op2p()) renameAndStaticsRecurse(nodep->op2p());
if (nodep->op3p()) renameAndStaticsRecurse(nodep->op3p());
if (nodep->op4p()) renameAndStaticsRecurse(nodep->op4p());
if (nodep->nextp()) renameAndStaticsRecurse(nodep->nextp());
if (VN_IS(nodep, InitialStatic)) {
nodep->unlinkFrBack();
m_ftaskp->addHereThisAsNext(nodep);
}
}
// VISITORS
void visit(AstFork* nodep) override {
// Keep this begin to group its statements together
@ -165,6 +186,7 @@ private:
m_ftaskp = nodep;
m_liftedp = nullptr;
iterateChildren(nodep);
renameAndStaticsRecurse(nodep);
if (m_liftedp) {
// Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced
if (AstNode* const stmtsp = nodep->stmtsp()) {
@ -174,6 +196,7 @@ private:
nodep->addStmtsp(m_liftedp);
m_liftedp = nullptr;
}
m_staticFuncVars.clear();
m_ftaskp = nullptr;
}
}
@ -210,7 +233,15 @@ private:
}
}
void visit(AstVar* nodep) override {
if (m_unnamedScope != "") {
// If static variable, move it outside a function.
if (nodep->lifetime().isStatic() && m_ftaskp) {
const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name();
nodep->name(newName);
nodep->unlinkFrBack();
m_ftaskp->addHereThisAsNext(nodep);
m_staticFuncVars.insert(nodep);
nodep->funcLocal(false);
} else if (m_unnamedScope != "") {
// Rename it
nodep->name(dot(m_unnamedScope, nodep->name()));
m_statep->userMarkChanged(nodep);

View File

@ -1176,9 +1176,6 @@ class LinkDotFindVisitor final : public VNVisitor {
// Var: Remember its name for later resolution
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?");
iterateChildren(nodep);
if (nodep->isFuncLocal() && nodep->lifetime().isStatic()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' function/task variables");
}
if (!m_statep->forScopeCreation()) {
// Find under either a task or the module's vars
const VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());

View File

@ -148,8 +148,8 @@ private:
if (classPkgRefp && VN_IS(classPkgRefp->classOrPackageNodep(), Class)) {
// Class methods are automatic by default
m_lifetime = VLifetime::AUTOMATIC;
} else if (nodep->dpiImport()) {
// DPI-imported function don't have lifetime specifiers
} else if (nodep->dpiImport() || VN_IS(nodep, Property)) {
// DPI-imported functions and properties don't have lifetime specifiers
m_lifetime = VLifetime::NONE;
}
if (m_lifetime.isStatic() && hasStaticDeclAssignments(nodep)) {
@ -222,12 +222,8 @@ private:
void visit(AstVar* nodep) override {
cleanFileline(nodep);
if (nodep->lifetime().isNone()) {
if (m_ftaskp) {
nodep->lifetime(VLifetime::AUTOMATIC);
} else {
nodep->lifetime(m_lifetime);
}
if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) {
nodep->lifetime(m_lifetime);
}
if (nodep->isParam() && !nodep->valuep()
&& nodep->fileline()->language() < V3LangCode::L1800_2009) {

View File

@ -503,6 +503,15 @@ private:
checkNodeInfo(nodep);
iterateChildren(nodep);
}
void visit(AstInitialStatic* nodep) override {
if (jumpingOver(nodep)) return;
if (!m_params) {
badNodeType(nodep);
return;
}
checkNodeInfo(nodep);
iterateChildren(nodep);
}
void visit(AstNodeIf* nodep) override {
if (jumpingOver(nodep)) return;
UINFO(5, " IF " << nodep << endl);

View File

@ -3788,12 +3788,16 @@ for_initializationItem<nodep>: // IEEE: variable_assignment + for_varia
// // IEEE: for_variable_declaration
data_type idAny/*new*/ '=' expr
{ VARRESET_NONLIST(VAR); VARDTYPE($1);
$$ = VARDONEA($<fl>2, *$2, nullptr, nullptr);
AstVar* const varp = VARDONEA($<fl>2, *$2, nullptr, nullptr);
varp->lifetime(VLifetime::AUTOMATIC);
$$ = varp;
$$->addNext(new AstAssign{$3, new AstVarRef{$<fl>2, *$2, VAccess::WRITE}, $4}); }
// // IEEE-2012:
| yVAR data_type idAny/*new*/ '=' expr
{ VARRESET_NONLIST(VAR); VARDTYPE($2);
$$ = VARDONEA($<fl>3, *$3, nullptr, nullptr);
AstVar* const varp = VARDONEA($<fl>3, *$3, nullptr, nullptr);
varp->lifetime(VLifetime::AUTOMATIC);
$$ = varp;
$$->addNext(new AstAssign{$4, new AstVarRef{$<fl>3, *$3, VAccess::WRITE}, $5}); }
// // IEEE: variable_assignment
// // UNSUP variable_lvalue below

View File

@ -2066,7 +2066,7 @@ module t_case_write1_tasks ();
endcase
end
endtask
task ozonef3;
task automatic ozonef3;
input [ 31:0] foo;
inout [STRLEN*8: 1] foobar;
reg nacho;
@ -2475,7 +2475,7 @@ module t_case_write1_tasks ();
endcase
end
endtask
task dude;
task automatic dude;
inout [STRLEN*8: 1] foobar;
reg [ 7:0] temp;
integer i;
@ -2497,7 +2497,7 @@ module t_case_write1_tasks ();
end
endtask
task big_case;
task automatic big_case;
input [ 31:0] fd;
input [ 31:0] foo;
reg [STRLEN*8: 1] foobar;

View File

@ -2067,7 +2067,7 @@ module t_case_write2_tasks ();
endcase
end
endtask
task ozonef3;
task automatic ozonef3;
input [ 31:0] foo;
input [`FD_BITS] fd;
reg nacho;
@ -2482,7 +2482,7 @@ module t_case_write2_tasks ();
$fwrite(fd," dude");
endtask
task big_case;
task automatic big_case;
input [ `FD_BITS] fd;
input [ 31:0] foo;
// verilator no_inline_task

View File

@ -1,6 +0,0 @@
%Error-UNSUPPORTED: t/t_class_static.v:25:18: Unsupported: 'static' function/task variables
: ... In instance t
25 | static int st = 2; st++; return st;
| ^~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all}, # Verilator unsupported, bug546
expect_filename => $Self->{golden_filename},
);
execute(
check_finished => 1,
) if !$Self->{vlt_all};
);
ok(1);
1;

View File

@ -76,7 +76,7 @@ module Test (/*AUTOARG*/
input [31:0] inp;
output [31:0] outp;
function [31:0] no_inline_function;
function automatic [31:0] no_inline_function;
input [31:0] var1;
input [31:0] var2;
/*verilator no_inline_task*/

View File

@ -39,7 +39,7 @@ endmodule : mod_inner
module mod_a_mon;
bit y;
function void accessor;
function automatic void accessor;
begin : accessor_block
bit read_x = mod_a.u_inner.x;
y = read_x;

View File

@ -18,12 +18,18 @@ module t;
endfunction
parameter int SUMS[3:0] = calc_sums();
parameter int SUMS1[3:0] = calc_sums();
initial begin
if (SUMS[0] != 4) $stop;
if (SUMS[1] != 4+3) $stop;
if (SUMS[2] != 4+3+2) $stop;
if (SUMS[3] != 4+3+2+1) $stop;
// According to section 13.4.3 of IEEE Std 1800-2017,
// execution at elaboration has no effect on the initial values
// of the variables used either at simulation time or among
// multiple invocations of a function at elaboration time
if (SUMS1 != SUMS) $stop;
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -6,7 +6,7 @@
module t;
task t;
task automatic t;
// verilator no_inline_task
string trace;

View File

@ -67,7 +67,7 @@ module t (/*AUTOARG*/
$finish;
end
task tsk;
task automatic tsk;
integer t1;
$display("t1 {mod}.tsk %m");
begin

View File

@ -1,14 +0,0 @@
%Error-UNSUPPORTED: t/t_var_static.v:20:18: Unsupported: 'static' function/task variables
: ... In instance t
20 | static int st = 2; st++; return st;
| ^~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error-UNSUPPORTED: t/t_var_static.v:30:18: Unsupported: 'static' function/task variables
: ... In instance t
30 | static int st = 2; st++; return st;
| ^~
%Error-UNSUPPORTED: t/t_var_static.v:40:18: Unsupported: 'static' function/task variables
: ... In instance t
40 | static int st = 2; st++; return st;
| ^~
%Error: Exiting due to

View File

@ -12,13 +12,11 @@ scenarios(simulator => 1);
compile(
verilator_flags2 => ['-Wno-IMPLICITSTATIC'],
fails => $Self->{vlt_all}, # Verilator unsupported, bug546
expect_filename => $Self->{golden_filename},
);
execute(
check_finished => 1,
) if !$Self->{vlt_all};
);
ok(1);
1;

View File

@ -6,6 +6,16 @@
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
function automatic int f_au_st_global ();
static int st = 0; st++; return st;
endfunction
package my_pkg;
function int f_no_st_pkg ();
static int st = 0; st++; return st;
endfunction
endpackage
module t (/*AUTOARG*/
// Inputs
clk
@ -67,6 +77,11 @@ module t (/*AUTOARG*/
v = f_au_au(); `checkh(v, 3);
v = f_au_au(); `checkh(v, 3);
//
v = f_au_st_global(); `checkh(v, 1);
v = f_au_st_global(); `checkh(v, 2);
v = my_pkg::f_no_st_pkg(); `checkh(v, 1);
v = my_pkg::f_no_st_pkg(); `checkh(v, 2);
//
end
int cyc = 0;

View File

@ -1,6 +0,0 @@
%Error-UNSUPPORTED: t/t_var_static_param.v:33:18: Unsupported: 'static' function/task variables
: ... In instance t.subb
33 | static int st = 2; st += P; return st;
| ^~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1);
compile(
fails => $Self->{vlt_all}, # Verilator unsupported, bug546
expect_filename => $Self->{golden_filename},
);
execute(
check_finished => 1,
) if !$Self->{vlt_all};
);
ok(1);
1;