Skip to content

Commit 24c2ba0

Browse files
authored
[InstCombine] Drop NSW when converting shl X, BW - 1 back into mul (llvm#121633)
`X <<s BW - 1` and `X *s INT_MIN` are not equivalent. Alive2: https://alive2.llvm.org/ce/z/MKKFrj Closes llvm#121584
1 parent 4a7c0b8 commit 24c2ba0

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,14 +2066,18 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
20662066
bool ShiftByX = false;
20672067

20682068
// If V is not nullptr, it will be matched using m_Specific.
2069-
auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C) -> bool {
2069+
auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C,
2070+
bool &PreserveNSW) -> bool {
20702071
const APInt *Tmp = nullptr;
20712072
if ((!V && match(Op, m_Mul(m_Value(V), m_APInt(Tmp)))) ||
20722073
(V && match(Op, m_Mul(m_Specific(V), m_APInt(Tmp)))))
20732074
C = *Tmp;
20742075
else if ((!V && match(Op, m_Shl(m_Value(V), m_APInt(Tmp)))) ||
2075-
(V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp)))))
2076+
(V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp))))) {
20762077
C = APInt(Tmp->getBitWidth(), 1) << *Tmp;
2078+
// We cannot preserve NSW when shifting by BW - 1.
2079+
PreserveNSW = Tmp->ult(Tmp->getBitWidth() - 1);
2080+
}
20772081
if (Tmp != nullptr)
20782082
return true;
20792083

@@ -2095,7 +2099,9 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
20952099
return false;
20962100
};
20972101

2098-
if (MatchShiftOrMulXC(Op0, X, Y) && MatchShiftOrMulXC(Op1, X, Z)) {
2102+
bool Op0PreserveNSW = true, Op1PreserveNSW = true;
2103+
if (MatchShiftOrMulXC(Op0, X, Y, Op0PreserveNSW) &&
2104+
MatchShiftOrMulXC(Op1, X, Z, Op1PreserveNSW)) {
20992105
// pass
21002106
} else if (MatchShiftCX(Op0, Y, X) && MatchShiftCX(Op1, Z, X)) {
21012107
ShiftByX = true;
@@ -2108,7 +2114,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
21082114
OverflowingBinaryOperator *BO0 = cast<OverflowingBinaryOperator>(Op0);
21092115
// TODO: We may be able to deduce more about nsw/nuw of BO0/BO1 based on Y >=
21102116
// Z or Z >= Y.
2111-
bool BO0HasNSW = BO0->hasNoSignedWrap();
2117+
bool BO0HasNSW = Op0PreserveNSW && BO0->hasNoSignedWrap();
21122118
bool BO0HasNUW = BO0->hasNoUnsignedWrap();
21132119
bool BO0NoWrap = IsSRem ? BO0HasNSW : BO0HasNUW;
21142120

@@ -2131,7 +2137,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
21312137
};
21322138

21332139
OverflowingBinaryOperator *BO1 = cast<OverflowingBinaryOperator>(Op1);
2134-
bool BO1HasNSW = BO1->hasNoSignedWrap();
2140+
bool BO1HasNSW = Op1PreserveNSW && BO1->hasNoSignedWrap();
21352141
bool BO1HasNUW = BO1->hasNoUnsignedWrap();
21362142
bool BO1NoWrap = IsSRem ? BO1HasNSW : BO1HasNUW;
21372143
// (rem (mul X, Y), (mul nuw/nsw X, Z))

llvm/test/Transforms/InstCombine/rem-mul-shl.ll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,32 @@ define <2 x i8> @srem_XY_XZ_with_CY_gt_CZ_no_nuw_out(<2 x i8> %X) {
372372
ret <2 x i8> %r
373373
}
374374

375+
define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(i8 noundef %X) {
376+
; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(
377+
; CHECK-NEXT: [[BO0:%.*]] = mul nsw i8 [[X:%.*]], 127
378+
; CHECK-NEXT: [[BO1:%.*]] = shl nsw i8 [[X]], 7
379+
; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO1]], [[BO0]]
380+
; CHECK-NEXT: ret i8 [[R]]
381+
;
382+
%BO0 = mul nsw i8 %X, 127
383+
%BO1 = shl nsw i8 %X, 7
384+
%r = srem i8 %BO1, %BO0
385+
ret i8 %r
386+
}
387+
388+
define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw_commuted(i8 noundef %X) {
389+
; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_drop_nsw_commuted(
390+
; CHECK-NEXT: [[BO0:%.*]] = mul nsw i8 [[X:%.*]], 127
391+
; CHECK-NEXT: [[BO1:%.*]] = shl nsw i8 [[X]], 7
392+
; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO0]], [[BO1]]
393+
; CHECK-NEXT: ret i8 [[R]]
394+
;
395+
%BO0 = mul nsw i8 %X, 127
396+
%BO1 = shl nsw i8 %X, 7
397+
%r = srem i8 %BO0, %BO1
398+
ret i8 %r
399+
}
400+
375401
define i8 @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1(i8 %X) {
376402
; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1(
377403
; CHECK-NEXT: [[BO0:%.*]] = mul nuw nsw i8 [[X:%.*]], 10

0 commit comments

Comments
 (0)