From 100e3d7702b8dcf545fb8c3cf9a040761390b8d2 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sat, 10 May 2025 19:01:15 +0900 Subject: [PATCH] Fix const-bit-op-tree with single-bit masks (#5993) (#5998) --- src/V3Const.cpp | 2 ++ test_regress/t/t_opt_const.v | 28 ++++++++++++++++++++++++++++ test_regress/t/t_opt_const_dfg.py | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 04ea33435..3ce2f1087 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -125,6 +125,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst { void updateBitRange(const AstShiftR* shiftp) { m_lsb += VN_AS(shiftp->rhsp(), Const)->toUInt(); } + void limitBitRangeToLsb() { m_msb = std::min(m_msb, m_lsb); } int wordIdx() const { return m_wordIdx; } void wordIdx(int i) { m_wordIdx = i; } bool polarity() const { return m_polarity; } @@ -538,6 +539,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst { Restorer restorer{*this}; incrOps(nodep, __LINE__); iterateConst(nodep->rhsp()); + if (m_leafp) m_leafp->limitBitRangeToLsb(); CONST_BITOP_RETURN_IF(m_failed, nodep->rhsp()); restorer.disableRestore(); // Now all checks passed } else if (nodep->type() == m_rootp->type()) { // And, Or, Xor diff --git a/test_regress/t/t_opt_const.v b/test_regress/t/t_opt_const.v index 5abf755f1..970774fe3 100644 --- a/test_regress/t/t_opt_const.v +++ b/test_regress/t/t_opt_const.v @@ -153,6 +153,7 @@ module Test(/*AUTOARG*/ bug4857 i_bug4857(.clk(clk), .in(d), .out(bug4857_out)); bug4864 i_bug4864(.clk(clk), .in(d), .out(bug4864_out)); bug5186 i_bug5186(.clk(clk), .in(d), .out(bug5186_out)); + bug5993 i_bug5993(.clk(clk), .in(d[10])); endmodule @@ -566,3 +567,30 @@ module bug5186(input wire clk, input wire [31:0] in, output out); result <= bad; assign out = result; endmodule + + +// See issue #5993 +// "in4[18]" is just one bit width, so " >> 8'd1" shifts out the bit. +// BitOpTree ignored implicit "& 1". It caused the bug" +module bug5993(input wire clk, input wire in); + + reg in3; + reg [23:16] in4; + + task automatic checkd(logic gotv, logic expv); + if ((gotv) !== (expv)) begin + $write("%%Error: got=%0d exp=%0d\n", gotv, expv); + $stop; + end + endtask + + // verilator lint_off WIDTH + wire wire_2 = in3 ? {4{14'b010111101}} : (in4[18] >> 8'b1); + // verilator lint_on WIDTH + + always @(posedge clk) begin + in3 <= '0; + in4 <= in ? 8'b00111__0__10 : 8'b00111__1__10; + checkd(wire_2, 1'b0); + end +endmodule diff --git a/test_regress/t/t_opt_const_dfg.py b/test_regress/t/t_opt_const_dfg.py index ffdca2c4f..6fd2ea9bc 100755 --- a/test_regress/t/t_opt_const_dfg.py +++ b/test_regress/t/t_opt_const_dfg.py @@ -18,7 +18,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", test.pli_filename test.execute() if test.vlt: - test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 39) + test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 43) test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1) test.passes()