Fix wrong optimization result of shifted out variable (#6016) (#6019)

This commit is contained in:
Yutetsu TAKATSUKASA 2025-05-18 20:18:37 +09:00 committed by GitHub
parent 0c8c7fb03c
commit b26658fd96
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 4 deletions

View File

@ -119,13 +119,25 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
m_constp = constp;
m_msb = constp->widthMin() - 1;
}
// updateBitRange(), limitBitRangeToLsb(), and polarity() must be called during ascending
// back to the root.
void updateBitRange(int newLsb, int newMsb) {
if ((m_lsb <= m_msb && newLsb > newMsb) || (m_lsb > m_msb && m_lsb < newLsb)) {
// When the new bit range is out of m_refp, clear polarity because nodes below is
// shifted out to zero.
// This kind of clear may happen several times. e.g. (!(1'b1 >> 1)) >> 1
polarity(true);
}
m_lsb = newLsb;
m_msb = newMsb;
}
void updateBitRange(const AstCCast* castp) {
m_msb = std::min(m_msb, m_lsb + castp->width() - 1);
updateBitRange(m_lsb, std::min(m_msb, m_lsb + castp->width() - 1));
}
void updateBitRange(const AstShiftR* shiftp) {
m_lsb += VN_AS(shiftp->rhsp(), Const)->toUInt();
updateBitRange(m_lsb + VN_AS(shiftp->rhsp(), Const)->toUInt(), m_msb);
}
void limitBitRangeToLsb() { m_msb = std::min(m_msb, m_lsb); }
void limitBitRangeToLsb() { updateBitRange(m_lsb, 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; }
@ -467,6 +479,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
// Don't restore m_polarity for Xor as it counts parity of the entire tree
if (!isXorTree()) m_polarity = !m_polarity;
if (m_leafp && castp) m_leafp->updateBitRange(castp);
if (m_leafp) m_leafp->polarity(!m_leafp->polarity());
}
void visit(AstWordSel* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
@ -479,7 +492,6 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
void visit(AstVarRef* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep);
m_leafp->setLeaf(nodep);
m_leafp->polarity(m_polarity);
}
void visit(AstConst* nodep) override {
CONST_BITOP_RETURN_IF(!m_leafp, nodep);

View File

@ -154,6 +154,7 @@ module Test(/*AUTOARG*/
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]));
bug6016 i_bug6016(.clk(clk), .in(d[10]));
endmodule
@ -593,4 +594,32 @@ module bug5993(input wire clk, input wire in);
in4 <= in ? 8'b00111__0__10 : 8'b00111__1__10;
checkd(wire_2, 1'b0);
end
endmodule
// See issue #6016
// When traversing a tree, a signal may be shifted out.
// Then the polarity has to be cleared, but was not.
// "(!in[18]) > 1" should be 0, but was not.
module bug6016(input wire clk, input wire in);
reg in0;
reg signed [7:0] in4;
wire [1:0] wire_0;
wire out20;
// verilator lint_off WIDTH
assign wire_0 = in4[0:0] ? ({{7{in4[3:1]}}, 12'd201} & 2'h2) : (!(in0) >> 9'b1111);
// verilator lint_on WIDTH
assign out20 = wire_0[0:0];
logic in_s1 = 1'b0;
always @(posedge clk) begin
in_s1 <= in;
if (in) begin
in4 <= 8'b1111_1110;
in0 <= 1'b0;
end
if (in_s1) begin
if (out20 != 1'b0) $stop;
end
end
endmodule