Fix of inline constraints with member selects (#6321)

This commit is contained in:
Igor Zaworski 2025-08-22 13:58:03 +02:00 committed by GitHub
parent b95a974ff1
commit f506aa878b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 152 additions and 1 deletions

View File

@ -2058,7 +2058,7 @@ AstMemberSel::AstMemberSel(FileLine* fl, AstNodeExpr* fromp, AstVar* varp)
bool AstMemberSel::sameNode(const AstNode* samep) const {
const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel);
return sp && access() == sp->access() && fromp()->isSame(sp->fromp()) && name() == sp->name()
&& (varp() && sp->varp() && varp()->sameNode(sp->varp()));
&& (varp() == sp->varp() || (varp() && sp->varp() && varp()->sameNode(sp->varp())));
}
void AstMemberSel::dump(std::ostream& str) const {

View File

@ -54,6 +54,8 @@ class LinkResolveVisitor final : public VNVisitor {
int m_senitemCvtNum = 0; // Temporary signal counter
std::deque<AstGenFor*> m_underGenFors; // Stack of GenFor underneath
bool m_underGenerate = false; // Under GenFor/GenIf
AstNodeExpr* m_currentRandomizeSelectp = nullptr; // fromp() of current `randomize()` call
bool m_inRandomizeWith = false; // If in randomize() with (and no other with afterwards)
// VISITORS
// TODO: Most of these visitors are here for historical reasons.
@ -185,6 +187,18 @@ class LinkResolveVisitor final : public VNVisitor {
if (nodep->dpiExport()) nodep->scopeNamep(new AstScopeName{nodep->fileline(), false});
}
void visit(AstNodeFTaskRef* nodep) override {
VL_RESTORER(m_currentRandomizeSelectp);
if (nodep->name() == "randomize") {
if (const AstMethodCall* const methodcallp = VN_CAST(nodep, MethodCall)) {
if (m_inRandomizeWith) {
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: randomize() nested in inline randomize() constraints");
}
m_currentRandomizeSelectp = methodcallp->fromp();
}
}
iterateChildren(nodep);
if (AstLet* letp = VN_CAST(nodep->taskp(), Let)) {
UINFO(7, "letSubstitute() " << nodep << " <- " << letp);
@ -525,6 +539,30 @@ class LinkResolveVisitor final : public VNVisitor {
iterateChildren(nodep);
}
void visit(AstMemberSel* nodep) override {
if (m_inRandomizeWith && nodep->fromp()->isSame(m_currentRandomizeSelectp)) {
// Replace member selects to the element
// on which the randomize() is called with LambdaArgRef
// This allows V3Randomize to work properly when
// constrained variables are referred using that object
AstNodeExpr* const prevFromp = nodep->fromp();
prevFromp->replaceWith(
new AstLambdaArgRef{prevFromp->fileline(), prevFromp->name(), false});
pushDeletep(prevFromp);
}
iterateChildren(nodep);
}
void visit(AstWith* nodep) override {
VL_RESTORER(m_inRandomizeWith);
if (const AstMethodCall* const methodCallp = VN_CAST(nodep->backp(), MethodCall)) {
m_inRandomizeWith = methodCallp->name() == "randomize";
} else {
m_inRandomizeWith = false;
}
iterateChildren(nodep);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
if not test.have_solver:
test.skip("No constraint solver installed")
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,50 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class B;
rand int insideB;
constraint i {
insideB inside {[0:10]};
};
endclass
class A;
rand logic[31:0] rdata;
rand int delay;
int i = 97;
rand B b;
function new();
b = new;
endfunction
constraint delay_bounds {
delay inside {[0:2]};
}
endclass
module t;
A a;
int i;
int delay;
logic[31:0] rdata;
int b;
initial begin
a = new;
i = 7;
repeat (120) begin
a.b.insideB = 3;
a.delay = 1;
a.rdata = 3;
if (a.randomize() with {if (a.delay == 1) a.rdata == i;} == 0) $stop;
if (a.b.randomize() with {a.b.insideB < 3;} == 0) $stop;
if (a.delay == 1 && a.rdata != 97) $stop;
if (a.b.insideB >= 3) $stop;
if (a.randomize() with {if (a.delay == 1) a.rdata == local::i;} == 0) $stop;
if (a.delay == 1 && a.rdata != 7) $stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,5 @@
%Error-UNSUPPORTED: t/t_randomize_neasted_unsup.v:17:41: Unsupported: randomize() nested in inline randomize() constraints
17 | if (a.randomize() with {rdata == aa.randomize();} == 0) $stop;
| ^~~~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('vlt')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,21 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Antmicro.
// SPDX-License-Identifier: CC0-1.0
class A;
rand logic[31:0] rdata;
endclass
module t;
A a;
A aa;
initial begin
a = new;
aa = new;
if (a.randomize() with {rdata == aa.randomize();} == 0) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule