Fix (const) ref default task argument handling (#7698)
This commit is contained in:
parent
4d5393c191
commit
81282c3d57
|
|
@ -119,6 +119,8 @@ class TaskStateVisitor final : public VNVisitor {
|
|||
V3Graph m_callGraph; // Task call graph
|
||||
TaskBaseVertex* m_curVxp; // Current vertex we're adding to
|
||||
std::vector<AstInitialAutomatic*> m_initialps; // Initial blocks to move
|
||||
bool m_underPortVar = false; // Visiting under a port AstVar; any expression there
|
||||
// is a default value, evaluated at call sites only
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
|
|
@ -289,11 +291,14 @@ private:
|
|||
}
|
||||
}
|
||||
void visit(AstVar* nodep) override {
|
||||
VL_RESTORER(m_underPortVar);
|
||||
if (nodep->isIO()) m_underPortVar = true;
|
||||
iterateChildren(nodep);
|
||||
nodep->user4p(m_curVxp); // Remember what task it's under
|
||||
}
|
||||
void visit(AstVarRef* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (m_underPortVar) return;
|
||||
AstVar* const varp = nodep->varp();
|
||||
if (varp->user4u().toGraphVertex() != m_curVxp) {
|
||||
if (m_curVxp->pure() && !varp->isXTemp() && !varp->isParam()) m_curVxp->impure(nodep);
|
||||
|
|
@ -1404,6 +1409,7 @@ class TaskVisitor final : public VNVisitor {
|
|||
// Move it to new function
|
||||
unlinkAndClone(nodep, portp, false);
|
||||
portp->funcLocal(true);
|
||||
if (portp->valuep()) pushDeletep(portp->valuep()->unlinkFrBack());
|
||||
cfuncp->addArgsp(portp);
|
||||
// Pass inputs to DPI import wrappers by reference, unless fits in register
|
||||
if (cfuncp->dpiImportWrapper() && portp->isReadOnly()) {
|
||||
|
|
@ -2139,6 +2145,14 @@ AstNodeFTask* V3Task::taskConnectWrapNew(AstNodeFTask* taskp, const string& newn
|
|||
newTaskp->addStmtsp(newPortp);
|
||||
} else { // Defaulting arg
|
||||
AstNodeExpr* const valuep = VN_AS(portp->valuep(), NodeExpr);
|
||||
if ((portp->isRef() || portp->isConstRef()) && VN_IS(valuep, VarRef)) {
|
||||
const VAccess refAccess = portp->isWritable() ? VAccess::WRITE : VAccess::READ;
|
||||
AstVarRef* const refp = VN_AS(valuep->cloneTree(false), VarRef);
|
||||
refp->access(refAccess);
|
||||
AstArg* const newArgp = new AstArg{portp->fileline(), portp->name(), refp};
|
||||
newCallp->addArgsp(newArgp);
|
||||
continue;
|
||||
}
|
||||
// Create local temporary
|
||||
newPortp = new AstVar{portp->fileline(), VVarType::BLOCKTEMP, portp->name(),
|
||||
portp->dtypep()};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(verilator_flags2=["--binary"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// A task argument that defaults to a plain variable must alias that variable,
|
||||
// not a copy of it: a write through a 'ref' default must propagate back, and a
|
||||
// 'const ref' default must observe later updates to the variable.
|
||||
|
||||
module t;
|
||||
int shared = 5;
|
||||
logic flag = 0;
|
||||
logic done = 0;
|
||||
|
||||
// writable 'ref' default: a write through it must reach 'shared'
|
||||
task automatic incr(ref int r = shared);
|
||||
`ifdef TEST_NOINLINE
|
||||
// verilator no_inline_task
|
||||
`endif
|
||||
r = r + 10;
|
||||
endtask
|
||||
|
||||
// 'const ref' default: must observe a later update to 'flag'
|
||||
task automatic waitflag(output logic odone, const ref logic r = flag);
|
||||
`ifdef TEST_NOINLINE
|
||||
// verilator no_inline_task
|
||||
`endif
|
||||
while (!r) #1;
|
||||
odone = 1'b1;
|
||||
endtask
|
||||
|
||||
initial begin
|
||||
incr();
|
||||
if (shared !== 15) begin
|
||||
$write("%%Error: write through default 'ref' lost (shared=%0d)\n", shared);
|
||||
$stop;
|
||||
end
|
||||
fork
|
||||
waitflag(done);
|
||||
join_none
|
||||
#5;
|
||||
flag = 1'b1;
|
||||
#5;
|
||||
if (done !== 1'b1) begin
|
||||
$write("%%Error: default 'const ref' did not observe update\n");
|
||||
$stop;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.top_filename = "t/t_func_ref_arg_default.v"
|
||||
|
||||
test.compile(verilator_flags2=["--binary"], v_flags2=["+define+TEST_NOINLINE"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
Loading…
Reference in New Issue