diff --git a/Changes b/Changes index e7f6f383a..34d1f36ce 100644 --- a/Changes +++ b/Changes @@ -30,6 +30,7 @@ Verilator 5.039 devel * Optimize 2 ** X to 1 << X if base is signed (#6203). [Max Wipfli] * Optimize more complex combinational assignments in DFG (#6205) (#6209). [Geza Lore] * Optimize combinational cycles through arrays in DFG (#6210). [Geza Lore] +* Fix loop initialization visibility outside loop (#4237). * Fix constructor parameters in inheritance hierarchies (#6036) (#6070). [Petr Nohavica] * Fix replicate of negative giving 'REPLICATE has no expected width' internal error (#6048) (#6229). * Fix cmake `-Wno` compiler flag testing (#6145). [Martin Stadler] diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index c344e819b..99e7aa89f 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -297,6 +297,17 @@ class UnrollVisitor final : public VNVisitor { ++m_statLoops; AstNode* newbodysp = nullptr; + if (initp && !m_generate) { // Set variable to initial value (may optimize away later) + AstNode* clonep = initp->cloneTree(true); + AstConst* varValuep = new AstConst{nodep->fileline(), loopValue}; + // Iteration requires a back, so put under temporary node + AstBegin* tempp = new AstBegin{nodep->fileline(), "[EditWrapper]", clonep}; + replaceVarRef(clonep, varValuep); + clonep = tempp->stmtsp()->unlinkFrBackWithNext(); + VL_DO_CLEAR(tempp->deleteTree(), tempp = nullptr); + VL_DO_DANGLING(pushDeletep(varValuep), varValuep); + newbodysp = clonep; + } if (stmtsp) { int times = 0; while (true) { diff --git a/test_regress/t/t_unroll_delay.out b/test_regress/t/t_unroll_delay.out index 1991fe349..a8d3a7b2e 100644 --- a/test_regress/t/t_unroll_delay.out +++ b/test_regress/t/t_unroll_delay.out @@ -1,14 +1,14 @@ [0] A 1 6 -[0] B 0 0 +[0] B 1 6 [1] C 1 6 [1] A 1 7 -[1] B 0 7 +[1] B 1 7 [2] C 1 7 -[2] B 0 8 +[2] B 1 8 [11] A 2 6 -[11] B 2 8 +[11] B 2 6 [12] C 2 6 [12] A 2 7 [12] B 2 7 diff --git a/test_regress/t/t_unroll_double.out b/test_regress/t/t_unroll_double.out new file mode 100644 index 000000000..e72040d3f --- /dev/null +++ b/test_regress/t/t_unroll_double.out @@ -0,0 +1,7 @@ +exit_a 0 0 A0 B0 C0 D0 B1 C1 D1 B2 C2 D2 Y3 Z3 A13 B10 C10 D10 B11 C11 D11 B12 C12 D12 Y13 Z13 A23 B20 C20 D20 B21 C21 D21 B22 C22 D22 Y23 Z23 +exit_a 0 1 A0 B0 C0 D0 B1 B2 C2 D2 Y3 Z3 A13 B10 C10 D10 B11 B12 C12 D12 Y13 Z13 A23 B20 C20 D20 B21 B22 C22 D22 Y23 Z23 +exit_a 0 2 A0 B0 C0 D0 B1 C1 D1 B2 C2 D2 Y3 Z3 A13 B10 C10 A20 B20 C20 D20 B21 C21 D21 B22 C22 D22 Y23 Z23 +exit_a 1 0 A0 B0 C0 D0 B1 C1 D1 B2 C2 D2 Y3 Z3 A13 B10 C10 D10 B11 C11 D11 B12 C12 D12 Y13 A23 B20 C20 D20 B21 C21 D21 B22 C22 D22 Y23 Z23 +exit_a 1 1 A0 B0 C0 D0 B1 B2 C2 D2 Y3 Z3 A13 B10 C10 D10 B11 B12 C12 D12 Y13 A23 B20 C20 D20 B21 B22 C22 D22 Y23 Z23 +exit_a 1 2 A0 B0 C0 D0 B1 C1 D1 B2 C2 D2 Y3 Z3 A13 B10 C10 A20 B20 C20 D20 B21 C21 D21 B22 C22 D22 Y23 Z23 +*-* All Finished *-* diff --git a/test_regress/t/t_unroll_double.py b/test_regress/t/t_unroll_double.py new file mode 100755 index 000000000..15f66fc8d --- /dev/null +++ b/test_regress/t/t_unroll_double.py @@ -0,0 +1,18 @@ +#!/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') + +test.compile(v_flags2=['+define+TEST_DISABLE']) + +test.execute(expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_unroll_double.v b/test_regress/t/t_unroll_double.v new file mode 100644 index 000000000..652568b22 --- /dev/null +++ b/test_regress/t/t_unroll_double.v @@ -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 Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`ifndef VERILATOR + `define PRAGMA +`elsif TEST_DISABLE + `define PRAGMA /*verilator unroll_disable*/ +`elsif TEST_FULL + `define PRAGMA /*verilator unroll_full*/ +`endif + +module t; + + int a, b; + int pos; + + initial begin + for (int exit_a = 0; exit_a < 2; ++exit_a) begin + `PRAGMA + for (int exit_b = 0; exit_b < 3; ++exit_b) begin + `PRAGMA + b = 0; + $write("exit_a %0d %0d", exit_a, exit_b); + for (a = 0; a < 3; ++a) begin : a_loop + `PRAGMA + $write(" A%0d", a * 10 + b); + for (b = 0; b < 3; ++b) begin : b_loop + `PRAGMA + $write(" B%0d", a * 10 + b); + if (exit_b == 1 && b == 1) disable b_loop; + $write(" C%0d", a * 10 + b); + if (exit_b == 2 && a == 1) disable a_loop; + $write(" D%0d", a * 10 + b); + end + $write(" Y%0d", a * 10 + b); + if (exit_a == 1 && a == 1) disable a_loop; + $write(" Z%0d", a * 10 + b); + end + $display; + end + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_unroll_double_unroll.py b/test_regress/t/t_unroll_double_unroll.py new file mode 100755 index 000000000..c6dcf1cdb --- /dev/null +++ b/test_regress/t/t_unroll_double_unroll.py @@ -0,0 +1,20 @@ +#!/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') +test.top_filename = 't/t_unroll_double.v' +test.golden_filename = 't/t_unroll_double.out' + +test.compile(v_flags2=['+define+TEST_FULL']) + +test.execute(expect_filename=test.golden_filename) + +test.passes()