Fix DfgPeephole miscompile of nested shifts with overflowing shift amount (#7977)

The REPLACE_SHIFTL_SHIFTL and REPLACE_SHIFTR_SHIFTR peephole optimizations
fold '(a << b) << c' into 'a << (b + c)' (and likewise for '>>'), but computed
'b + c' in the width of the shift-amount operand. When 'b + c' overflows that
width it wraps around, producing a too-small shift amount and a wrong result.

Compute the sum one bit wider than the amounts so it cannot overflow.

Fixes #7955
This commit is contained in:
spomatasmd 2026-07-28 11:42:51 +02:00 committed by GitHub
parent 73b3ca7d2c
commit a6f4dd031f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 22 additions and 2 deletions

View File

@ -345,3 +345,4 @@ Zubin Jain
Muzaffer Kal
Yilin Li
Shashvat Prabhu
spomatasmd

View File

@ -2548,7 +2548,13 @@ class V3DfgPeephole final : public DfgVisitor {
if (DfgShiftL* const lShiftLp = lhsp->cast<DfgShiftL>()) {
if (!lShiftLp->hasMultipleSinks() && rhsp->dtype() == lShiftLp->rhsp()->dtype()) {
APPLYING(REPLACE_SHIFTL_SHIFTL) {
DfgAdd* const addp = make<DfgAdd>(rhsp, rhsp, lShiftLp->rhsp());
// Fold '(a << b) << c' to 'a << (b + c)'. Compute 'b + c'
// one bit wider than the amounts so it cannot overflow.
FileLine* const flp = vtxp->fileline();
const DfgDataType& sumDType = DfgDataType::packed(rhsp->width() + 1);
DfgVertex* const bp = make<DfgExtend>(flp, sumDType, lShiftLp->rhsp());
DfgVertex* const cp = make<DfgExtend>(flp, sumDType, rhsp);
DfgAdd* const addp = make<DfgAdd>(flp, sumDType, bp, cp);
replace(make<DfgShiftL>(vtxp, lShiftLp->lhsp(), addp));
return;
}
@ -2637,7 +2643,13 @@ class V3DfgPeephole final : public DfgVisitor {
if (DfgShiftR* const lShiftRp = lhsp->cast<DfgShiftR>()) {
if (!lShiftRp->hasMultipleSinks() && rhsp->dtype() == lShiftRp->rhsp()->dtype()) {
APPLYING(REPLACE_SHIFTR_SHIFTR) {
DfgAdd* const addp = make<DfgAdd>(rhsp, rhsp, lShiftRp->rhsp());
// Fold '(a >> b) >> c' to 'a >> (b + c)'. Compute 'b + c'
// one bit wider than the amounts so it cannot overflow.
FileLine* const flp = vtxp->fileline();
const DfgDataType& sumDType = DfgDataType::packed(rhsp->width() + 1);
DfgVertex* const bp = make<DfgExtend>(flp, sumDType, lShiftRp->rhsp());
DfgVertex* const cp = make<DfgExtend>(flp, sumDType, rhsp);
DfgAdd* const addp = make<DfgAdd>(flp, sumDType, bp, cp);
replace(make<DfgShiftR>(vtxp, lShiftRp->lhsp(), addp));
return;
}

View File

@ -341,6 +341,13 @@ module t (
`signal(REPLACE_BITWISE_OF_REDUCTION_OF_SELS_WITH_REDUCTION_XOR_B, (^rand_a[12 +:2]) ^ (^rand_a[10 +: 2]));
`signal(REPLACE_SHIFTL_SHIFTL, rand_a << 2 << 3);
`signal(REPLACE_SHIFTR_SHIFTR, rand_a >> 2 >> 3);
// As above, but with 2-bit variable amounts whose sum can overflow the amount width (#7955).
wire [1:0] shl_shl_amt0 = rand_a[1:0];
wire [1:0] shl_shl_amt1 = rand_b[1:0];
`signal(REPLACE_SHIFTL_SHIFTL_OVERFLOW, (rand_a << shl_shl_amt0) << shl_shl_amt1);
wire [1:0] shr_shr_amt0 = rand_a[3:2];
wire [1:0] shr_shr_amt1 = rand_b[3:2];
`signal(REPLACE_SHIFTR_SHIFTR_OVERFLOW, (rand_a >> shr_shr_amt0) >> shr_shr_amt1);
`signal(PUSH_COMMUTATIVE_BINARY_THROUGH_COND, 58'h1 + (rand_a[0] ? rand_b[1 +: 58] : ~rand_b[1 +: 58]));
`signal(REMOVE_ADD_ZERO, rand_a + '0);
`signal(REPLACE_ADD_WITH_COUNT_ONES_A, 4'(rand_a[63]) + 4'(rand_a[62]) + 4'(rand_a[61]));