diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 90cd1ee2e..c2f9b3d60 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -560,9 +560,13 @@ class ConstBitOpTreeVisitor final : public VNVisitor { if (leafInfo.lsb() <= leafInfo.msb()) { m_bitPolarities.emplace_back(leafInfo, isXorTree() || leafInfo.polarity(), leafInfo.lsb()); - } else if (isAndTree() && leafInfo.polarity()) { - // If there is a constant 0 term in an And tree, we must include it. Fudge - // this by adding a bit with both polarities, which will simplify to zero + } else if ((isAndTree() && leafInfo.polarity()) + || (isOrTree() && !leafInfo.polarity())) { + // If there is a constant 0 term in an And tree or 1 term in an Or tree, we + // must include it. Fudge this by adding a bit with both polarities, which + // will simplify to zero or one respectively. + // Note that Xor tree does not need this kind of care, polarity of Xor tree + // is already cared when visitin AstNot. Taking xor with 1'b0 is nop. m_bitPolarities.emplace_back(leafInfo, true, 0); m_bitPolarities.emplace_back(leafInfo, false, 0); } diff --git a/test_regress/t/t_const_opt.pl b/test_regress/t/t_const_opt.pl index 1ee302ca7..bf8d4b3a3 100755 --- a/test_regress/t/t_const_opt.pl +++ b/test_regress/t/t_const_opt.pl @@ -20,7 +20,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 15); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 16); } ok(1); 1; diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index 8ebb397b3..38eb31bb9 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -62,7 +62,7 @@ module t(/*AUTOARG*/ $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'h94c0495e8e279723 +`define EXPECTED_SUM 64'he65eec57cf769267 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); @@ -91,10 +91,11 @@ module Test(/*AUTOARG*/ wire bug3399_out0; wire bug3399_out1; logic bug3786_out; + logic bug3824_out; output logic o; - logic [12:0] tmp; + logic [13:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -123,6 +124,7 @@ module Test(/*AUTOARG*/ tmp[10]<= bug3399_out0; tmp[11]<= bug3399_out1; tmp[12]<= bug3786_out; + tmp[13]<= bug3824_out; end bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out)); @@ -132,6 +134,7 @@ module Test(/*AUTOARG*/ bug3509 i_bug3509(.clk(clk), .in(d), .out(bug3509_out)); bug3399 i_bug3399(.clk(clk), .in(d), .out0(bug3399_out0), .out1(bug3399_out1)); bug3786 i_bug3786(.clk(clk), .in(d), .out(bug3786_out)); + bug3824 i_bug3824(.clk(clk), .in(d), .out(bug3824_out)); endmodule @@ -331,3 +334,33 @@ module bug3786(input wire clk, input wire [31:0] in, inout wire out); assign out = ^{d1, d0}; endmodule + +// Bug3824 +// When a variable is shift-out, the term becomes 0. +// Such behavior was not considered in Or-tree. +module bug3824(input wire clk, input wire [31:0] in, output wire out); + logic [5:0] a; + always_ff @(posedge clk) a <= in[5:0]; + logic [6:0] b; + assign b = {1'b0, a}; + + logic c_and; + assign c_and = (b[6]); // c_and is always 1'b0 + always_comb if (c_and != 1'b0) $stop; + logic d_and; + always_ff @(posedge clk) d_and <= (&a) & c_and; + + logic c_or; + assign c_or = ~(b[6]); // c_or is always 1'b1 as b[6] is 1'b0 + always_comb if (c_or != 1'b1) $stop; + logic d_or; + always_ff @(posedge clk) d_or <= (|a) | c_or; + + logic c_xor; + assign c_xor = ^(b[6]); // c_xor is always 1'b0 + always_comb if (c_xor != 1'b0) $stop; + logic d_xor; + always_ff @(posedge clk) d_xor <= (^a) ^ c_xor; + + assign out = d_and ^ d_or ^ d_xor; +endmodule