From 27e7fdc9eb2a81cc563bb45b05c05f7627bb9f0a Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Thu, 23 Apr 2026 17:16:24 +0200 Subject: [PATCH] Fix std::randomize inside {typedef array} internal error (#7481) Fixes #7481. --- src/V3Randomize.cpp | 4 +- .../t/t_constraint_inside_typedef_array.py | 21 ++++++ .../t/t_constraint_inside_typedef_array.v | 72 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_constraint_inside_typedef_array.py create mode 100644 test_regress/t/t_constraint_inside_typedef_array.v diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 44a3e8d79..b012a9c89 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -964,7 +964,9 @@ class ConstraintExprVisitor final : public VNVisitor { AstNodeExpr* newSel(FileLine* fl, AstNodeExpr* arrayp, AstNodeExpr* idxp) { // similar to V3WidthSel.cpp - AstNodeDType* const arrDtp = arrayp->unlinkFrBack()->dtypep(); + // skipRefp() unwraps typedef wrappers (AstRefDType) so the dtype kind + // checks below recognize types spelled as `typedef [$]`. + AstNodeDType* const arrDtp = arrayp->unlinkFrBack()->dtypep()->skipRefp(); AstNodeExpr* selp = nullptr; if (VN_IS(arrDtp, QueueDType) || VN_IS(arrDtp, DynArrayDType)) selp = new AstCMethodHard{fl, arrayp, VCMethod::ARRAY_AT, idxp}; diff --git a/test_regress/t/t_constraint_inside_typedef_array.py b/test_regress/t/t_constraint_inside_typedef_array.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_constraint_inside_typedef_array.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_constraint_inside_typedef_array.v b/test_regress/t/t_constraint_inside_typedef_array.v new file mode 100644 index 000000000..04459fb2d --- /dev/null +++ b/test_regress/t/t_constraint_inside_typedef_array.v @@ -0,0 +1,72 @@ +// 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 + +package pkg; + typedef int int_q[$]; + typedef int int_da[]; + typedef int int_up[4]; + typedef int_q alias_q; + + class Bundle; + int_q q; + int_da d; + int_up u; + endclass +endpackage + +module t(/*AUTOARG*/); + import pkg::*; + + initial begin + automatic Bundle b = new(); + automatic int t_l = 0; + automatic int rv; + automatic alias_q a = '{32'd1, 32'd2, 32'd3}; + + b.q = '{32'd10, 32'd20, 32'd30}; + b.d = new[3]; + b.d = '{32'd40, 32'd50, 32'd60}; + b.u = '{32'd70, 32'd80, 32'd90, 32'd100}; + + // Original reported shape: typedef queue member of a class, + // used as the array in `inside {...}` of a with-constraint. + repeat (20) begin + rv = std::randomize(t_l) with { t_l inside {b.q}; }; + `checkd(rv, 1); + `checkd((t_l == 10 || t_l == 20 || t_l == 30), 1'b1); + end + + // Typedef dynamic array. + repeat (20) begin + rv = std::randomize(t_l) with { t_l inside {b.d}; }; + `checkd(rv, 1); + `checkd((t_l == 40 || t_l == 50 || t_l == 60), 1'b1); + end + + // Typedef unpacked (fixed-size) array. + repeat (20) begin + rv = std::randomize(t_l) with { t_l inside {b.u}; }; + `checkd(rv, 1); + `checkd((t_l == 70 || t_l == 80 || t_l == 90 || t_l == 100), 1'b1); + end + + // Chained typedef (AstRefDType -> AstRefDType -> QueueDType) must + // also be unwrapped by skipRefp(). + repeat (20) begin + rv = std::randomize(t_l) with { t_l inside {a}; }; + `checkd(rv, 1); + `checkd((t_l == 1 || t_l == 2 || t_l == 3), 1'b1); + end + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule