From 280cff06f31f0a3bf7f8d89116eb79545941a991 Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Tue, 21 Apr 2026 17:37:58 +0200 Subject: [PATCH] Fix std::randomize `inside` corrupting class-member queue operand (#7449) (#7456) Fixes #7449 --- src/V3Randomize.cpp | 4 +- .../t/t_randomize_std_inside_queue.py | 21 +++++++ test_regress/t/t_randomize_std_inside_queue.v | 57 +++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_randomize_std_inside_queue.py create mode 100644 test_regress/t/t_randomize_std_inside_queue.v diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index caea970f0..993ba2207 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -2760,7 +2760,9 @@ class CaptureVisitor final : public VNVisitor { m_ignore.emplace(thisRefp); AstMemberSel* const memberSelp = new AstMemberSel{nodep->fileline(), thisRefp, nodep->varp()}; - if (!m_targetp) memberSelp->user1(true); + // Propagate random-dependence marking; forcing it on read-only operands + // would route them through the solver write path. + if (!m_targetp && nodep->user1()) memberSelp->user1(true); memberSelp->user2p(m_targetp); nodep->replaceWith(memberSelp); VL_DO_DANGLING(pushDeletep(nodep), nodep); diff --git a/test_regress/t/t_randomize_std_inside_queue.py b/test_regress/t/t_randomize_std_inside_queue.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_randomize_std_inside_queue.py @@ -0,0 +1,21 @@ +#!/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') + +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_randomize_std_inside_queue.v b/test_regress/t/t_randomize_std_inside_queue.v new file mode 100644 index 000000000..763cf0fe3 --- /dev/null +++ b/test_regress/t/t_randomize_std_inside_queue.v @@ -0,0 +1,57 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +class Cls; + int x; + int int_q[$]; + int dyn[]; + + function new(); + x = 0; + int_q = '{12, 13, 17, 19}; + dyn = '{21, 22, 23}; + endfunction + + task rand_with_queue(); + int ok; + ok = std::randomize(x) with {x inside {int_q};}; + `checkd(ok, 1); + `checkd(int_q.size(), 4); + `checkd(int_q[0], 12); + `checkd(int_q[1], 13); + `checkd(int_q[2], 17); + `checkd(int_q[3], 19); + if (!(x inside {int_q})) `stop; + endtask + + task rand_with_dyn(); + int ok; + ok = std::randomize(x) with {x inside {dyn};}; + `checkd(ok, 1); + `checkd(dyn.size(), 3); + `checkd(dyn[0], 21); + `checkd(dyn[1], 22); + `checkd(dyn[2], 23); + if (!(x inside {dyn})) `stop; + endtask +endclass + +module t; + Cls obj; + + initial begin + obj = new(); + repeat (20) obj.rand_with_queue(); + repeat (20) obj.rand_with_dyn(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule