Fix (const) ref default task argument handling (#7698)

This commit is contained in:
Nick Brereton 2026-06-03 22:31:21 -04:00 committed by GitHub
parent 4d5393c191
commit 81282c3d57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 103 additions and 0 deletions

View File

@ -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()};

View File

@ -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()

View File

@ -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

View File

@ -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()