From eff2d977c1483e6f18ff2b64a083ceeaae15e475 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Nov 2023 07:32:08 -0500 Subject: [PATCH] Fix mis-elimination of variables across randomize() --- src/V3Life.cpp | 6 +- test_regress/t/t_randomize_rand_mode.v | 90 ++++++++++--- .../t/t_randomize_rand_mode_warn_bad.out | 122 +++++++++++++++--- 3 files changed, 176 insertions(+), 42 deletions(-) diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 821365623..7091436ce 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -301,6 +301,7 @@ private: } // Collect any used variables first, as lhs may also be on rhs // Similar code in V3Dead + VL_RESTORER(m_sideEffect); m_sideEffect = false; m_lifep->clearReplaced(); iterateAndNextNull(nodep->rhsp()); @@ -407,7 +408,9 @@ private: iterateChildren(nodep); // Enter the function and trace it // else is non-inline or public function we optimize separately - if (!nodep->funcp()->entryPoint()) { + if (nodep->funcp()->entryPoint()) { + setNoopt(); + } else { m_tracingCall = true; iterate(nodep->funcp()); } @@ -416,6 +419,7 @@ private: // UINFO(4, " CFUNC " << nodep << endl); if (!m_tracingCall && !nodep->entryPoint()) return; m_tracingCall = false; + if (nodep->recursive()) setNoopt(); if (nodep->dpiImportPrototype() && !nodep->dpiPure()) { m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment } diff --git a/test_regress/t/t_randomize_rand_mode.v b/test_regress/t/t_randomize_rand_mode.v index e6f7f3241..1b4f4f12a 100644 --- a/test_regress/t/t_randomize_rand_mode.v +++ b/test_regress/t/t_randomize_rand_mode.v @@ -4,17 +4,63 @@ // any use, without warranty, 2023 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +// TODO Verilator ignores this setting currently, always returning 1 (rand on) +`ifdef VERILATOR + `define checkh_vlt1(gotv,expv) `checkh(gotv,1) +`else + `define checkh_vlt1(gotv,expv) `checkh(gotv,expv) +`endif + class Packet; rand int m_one; - - Packet other; + rand int m_two; task test1; - // TODO Verilator ignores this setting currently, always returning 1 (rand on) - // TODO test that these control randomization as specified m_one.rand_mode(0); - m_one.rand_mode(1); + `checkh_vlt1(m_one.rand_mode(), 0); + m_two.rand_mode(0); + `checkh_vlt1(m_two.rand_mode(), 0); + verify(0, 0); + + m_one.rand_mode(0); + `checkh_vlt1(m_one.rand_mode(), 0); + m_two.rand_mode(1); + `checkh_vlt1(m_two.rand_mode(), 1); + verify(0, 1); + endtask + + task verify(int mode_one, int mode_two); + bit one_ne10 = '0; + bit two_ne10 = '0; + int v; + // TODO Verilator ignores this setting currently, always returning 1 (rand on) +`ifndef VERILATOR + if (m_one.rand_mode() != mode_one) $stop; + if (m_two.rand_mode() != mode_two) $stop; +`else if (m_one.rand_mode() != 1) $stop; + if (m_two.rand_mode() != 1) $stop; +`endif + for (int i = 0; i < 20; ++i) begin + m_one = 10; + m_two = 10; + v = randomize(); + if (m_one != 10) one_ne10 = 1'b1; + if (m_two != 10) two_ne10 = 1'b1; +`ifdef TEST_VERBOSE + $display("one=%0d(rand_mode=%0d) two=%0d(rand_mode=%0d)", + m_one, mode_one, m_two, mode_two); +`endif + end + if (mode_one != 0 && !one_ne10) $stop; + if (mode_two != 0 && !two_ne10) $stop; +`ifndef VERILATOR + if (mode_one == 0 && one_ne10) $stop; + if (mode_two == 0 && two_ne10) $stop; +`endif endtask endclass @@ -27,28 +73,32 @@ module t (/*AUTOARG*/); initial begin p = new; - v = p.randomize(); - if (v != 1) $stop; -`ifndef VERILATOR - if (p.m_one != 1) $stop; -`endif + + p.test1(); // IEEE: function void object[.random_variable].rand_mode(bit on_off); // IEEE: function int object.random_variable.rand_mode(); - - // TODO Verilator ignores this setting currently, always returning 1 (rand on) - // TODO test that these control randomization as specified - p.rand_mode(0); - p.rand_mode(1); // Not legal to get current rand() value on a class-only call - // TODO Verilator ignores this setting currently, always returning 1 (rand on) - // TODO test that these control randomization as specified + // We call rand_mode here too becuase the parsing is different from that + // called from the class itself p.m_one.rand_mode(0); - p.m_one.rand_mode(1); - if (p.m_one.rand_mode() != 1) $stop; + `checkh_vlt1(p.m_one.rand_mode(), 0); + p.m_two.rand_mode(0); + `checkh_vlt1(p.m_two.rand_mode(), 0); + p.verify(0, 0); - // TODO test can't redefine rand_mode + p.m_one.rand_mode(0); + `checkh_vlt1(p.m_one.rand_mode(), 0); + p.m_two.rand_mode(1); + `checkh_vlt1(p.m_two.rand_mode(), 1); + p.verify(0, 1); + + p.rand_mode(1); + p.verify(1, 1); + + p.rand_mode(0); + p.verify(0, 0); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_randomize_rand_mode_warn_bad.out b/test_regress/t/t_randomize_rand_mode_warn_bad.out index d8f42a152..55728b85c 100644 --- a/test_regress/t/t_randomize_rand_mode_warn_bad.out +++ b/test_regress/t/t_randomize_rand_mode_warn_bad.out @@ -1,35 +1,115 @@ -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:15:13: rand_mode ignored (unsupported) +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:22:13: rand_mode ignored (unsupported) : ... note: In instance 't' - 15 | m_one.rand_mode(0); + 22 | m_one.rand_mode(0); | ^~~~~~~~~ ... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message. -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:16:13: rand_mode ignored (unsupported) +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:23:136: rand_mode ignored (unsupported) + : ... note: In instance 't' + 23 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",23, (m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:23:21: rand_mode ignored (unsupported) : ... note: In instance 't' - 16 | m_one.rand_mode(1); + 23 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",23, (m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:24:13: rand_mode ignored (unsupported) + : ... note: In instance 't' + 24 | m_two.rand_mode(0); | ^~~~~~~~~ -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:17:17: rand_mode ignored (unsupported) +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:25:136: rand_mode ignored (unsupported) + : ... note: In instance 't' + 25 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",25, (m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:25:21: rand_mode ignored (unsupported) : ... note: In instance 't' - 17 | if (m_one.rand_mode() != 1) $stop; + 25 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",25, (m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:44:17: rand_mode ignored (unsupported) + : ... note: In instance 't' + 44 | if (m_one.rand_mode() != 1) $stop; | ^~~~~~~~~ -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:41:9: rand_mode ignored (unsupported) - : ... note: In instance 't' - 41 | p.rand_mode(0); - | ^~~~~~~~~ -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:42:9: rand_mode ignored (unsupported) - : ... note: In instance 't' - 42 | p.rand_mode(1); - | ^~~~~~~~~ -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:47:15: rand_mode ignored (unsupported) +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:45:17: rand_mode ignored (unsupported) : ... note: In instance 't' - 47 | p.m_one.rand_mode(0); + 45 | if (m_two.rand_mode() != 1) $stop; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:28:13: rand_mode ignored (unsupported) + : ... note: In instance 't' + 28 | m_one.rand_mode(0); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:29:136: rand_mode ignored (unsupported) + : ... note: In instance 't' + 29 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",29, (m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:29:21: rand_mode ignored (unsupported) + : ... note: In instance 't' + 29 | do if ((m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",29, (m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:30:13: rand_mode ignored (unsupported) + : ... note: In instance 't' + 30 | m_two.rand_mode(1); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:31:136: rand_mode ignored (unsupported) + : ... note: In instance 't' + 31 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",31, (m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:31:21: rand_mode ignored (unsupported) + : ... note: In instance 't' + 31 | do if ((m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",31, (m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:85:15: rand_mode ignored (unsupported) + : ... note: In instance 't' + 85 | p.m_one.rand_mode(0); | ^~~~~~~~~ -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:48:15: rand_mode ignored (unsupported) +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:86:140: rand_mode ignored (unsupported) + : ... note: In instance 't' + 86 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",86, (p.m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:86:23: rand_mode ignored (unsupported) : ... note: In instance 't' - 48 | p.m_one.rand_mode(1); + 86 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",86, (p.m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:87:15: rand_mode ignored (unsupported) + : ... note: In instance 't' + 87 | p.m_two.rand_mode(0); | ^~~~~~~~~ -%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:49:19: rand_mode ignored (unsupported) +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:88:140: rand_mode ignored (unsupported) + : ... note: In instance 't' + 88 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",88, (p.m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:88:23: rand_mode ignored (unsupported) : ... note: In instance 't' - 49 | if (p.m_one.rand_mode() != 1) $stop; - | ^~~~~~~~~ + 88 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",88, (p.m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:91:15: rand_mode ignored (unsupported) + : ... note: In instance 't' + 91 | p.m_one.rand_mode(0); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:92:140: rand_mode ignored (unsupported) + : ... note: In instance 't' + 92 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",92, (p.m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:92:23: rand_mode ignored (unsupported) + : ... note: In instance 't' + 92 | do if ((p.m_one.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",92, (p.m_one.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:93:15: rand_mode ignored (unsupported) + : ... note: In instance 't' + 93 | p.m_two.rand_mode(1); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:94:140: rand_mode ignored (unsupported) + : ... note: In instance 't' + 94 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",94, (p.m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:94:23: rand_mode ignored (unsupported) + : ... note: In instance 't' + 94 | do if ((p.m_two.rand_mode()) !== (1)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_randomize_rand_mode.v",94, (p.m_two.rand_mode()), (1)); $stop; end while(0);; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:97:9: rand_mode ignored (unsupported) + : ... note: In instance 't' + 97 | p.rand_mode(1); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize_rand_mode.v:100:9: rand_mode ignored (unsupported) + : ... note: In instance 't' + 100 | p.rand_mode(0); + | ^~~~~~~~~ %Error: Exiting due to