[llvm] 24c2ba0 - [InstCombine] Drop NSW when converting `shl X, BW - 1` back into mul (#121633)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jan 4 09:20:57 PST 2025
Author: Yingwei Zheng
Date: 2025-01-05T01:20:54+08:00
New Revision: 24c2ba07ce65a5bf7d1113e05c517169d950b663
URL: https://github.com/llvm/llvm-project/commit/24c2ba07ce65a5bf7d1113e05c517169d950b663
DIFF: https://github.com/llvm/llvm-project/commit/24c2ba07ce65a5bf7d1113e05c517169d950b663.diff
LOG: [InstCombine] Drop NSW when converting `shl X, BW - 1` back into mul (#121633)
`X <<s BW - 1` and `X *s INT_MIN` are not equivalent.
Alive2: https://alive2.llvm.org/ce/z/MKKFrj
Closes https://github.com/llvm/llvm-project/issues/121584
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
llvm/test/Transforms/InstCombine/rem-mul-shl.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index f85a3c93651353..97a765ecfb6bd5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -2066,14 +2066,18 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
bool ShiftByX = false;
// If V is not nullptr, it will be matched using m_Specific.
- auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C) -> bool {
+ auto MatchShiftOrMulXC = [](Value *Op, Value *&V, APInt &C,
+ bool &PreserveNSW) -> bool {
const APInt *Tmp = nullptr;
if ((!V && match(Op, m_Mul(m_Value(V), m_APInt(Tmp)))) ||
(V && match(Op, m_Mul(m_Specific(V), m_APInt(Tmp)))))
C = *Tmp;
else if ((!V && match(Op, m_Shl(m_Value(V), m_APInt(Tmp)))) ||
- (V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp)))))
+ (V && match(Op, m_Shl(m_Specific(V), m_APInt(Tmp))))) {
C = APInt(Tmp->getBitWidth(), 1) << *Tmp;
+ // We cannot preserve NSW when shifting by BW - 1.
+ PreserveNSW = Tmp->ult(Tmp->getBitWidth() - 1);
+ }
if (Tmp != nullptr)
return true;
@@ -2095,7 +2099,9 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
return false;
};
- if (MatchShiftOrMulXC(Op0, X, Y) && MatchShiftOrMulXC(Op1, X, Z)) {
+ bool Op0PreserveNSW = true, Op1PreserveNSW = true;
+ if (MatchShiftOrMulXC(Op0, X, Y, Op0PreserveNSW) &&
+ MatchShiftOrMulXC(Op1, X, Z, Op1PreserveNSW)) {
// pass
} else if (MatchShiftCX(Op0, Y, X) && MatchShiftCX(Op1, Z, X)) {
ShiftByX = true;
@@ -2108,7 +2114,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
OverflowingBinaryOperator *BO0 = cast<OverflowingBinaryOperator>(Op0);
// TODO: We may be able to deduce more about nsw/nuw of BO0/BO1 based on Y >=
// Z or Z >= Y.
- bool BO0HasNSW = BO0->hasNoSignedWrap();
+ bool BO0HasNSW = Op0PreserveNSW && BO0->hasNoSignedWrap();
bool BO0HasNUW = BO0->hasNoUnsignedWrap();
bool BO0NoWrap = IsSRem ? BO0HasNSW : BO0HasNUW;
@@ -2131,7 +2137,7 @@ static Instruction *simplifyIRemMulShl(BinaryOperator &I,
};
OverflowingBinaryOperator *BO1 = cast<OverflowingBinaryOperator>(Op1);
- bool BO1HasNSW = BO1->hasNoSignedWrap();
+ bool BO1HasNSW = Op1PreserveNSW && BO1->hasNoSignedWrap();
bool BO1HasNUW = BO1->hasNoUnsignedWrap();
bool BO1NoWrap = IsSRem ? BO1HasNSW : BO1HasNUW;
// (rem (mul X, Y), (mul nuw/nsw X, Z))
diff --git a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll
index e7d6cc7102c713..920497c07e3804 100644
--- a/llvm/test/Transforms/InstCombine/rem-mul-shl.ll
+++ b/llvm/test/Transforms/InstCombine/rem-mul-shl.ll
@@ -372,6 +372,32 @@ define <2 x i8> @srem_XY_XZ_with_CY_gt_CZ_no_nuw_out(<2 x i8> %X) {
ret <2 x i8> %r
}
+define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(i8 noundef %X) {
+; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_drop_nsw(
+; CHECK-NEXT: [[BO0:%.*]] = mul nsw i8 [[X:%.*]], 127
+; CHECK-NEXT: [[BO1:%.*]] = shl nsw i8 [[X]], 7
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO1]], [[BO0]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %BO0 = mul nsw i8 %X, 127
+ %BO1 = shl nsw i8 %X, 7
+ %r = srem i8 %BO1, %BO0
+ ret i8 %r
+}
+
+define i8 @srem_XY_XZ_with_CY_gt_CZ_drop_nsw_commuted(i8 noundef %X) {
+; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_drop_nsw_commuted(
+; CHECK-NEXT: [[BO0:%.*]] = mul nsw i8 [[X:%.*]], 127
+; CHECK-NEXT: [[BO1:%.*]] = shl nsw i8 [[X]], 7
+; CHECK-NEXT: [[R:%.*]] = srem i8 [[BO0]], [[BO1]]
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %BO0 = mul nsw i8 %X, 127
+ %BO1 = shl nsw i8 %X, 7
+ %r = srem i8 %BO0, %BO1
+ ret i8 %r
+}
+
define i8 @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1(i8 %X) {
; CHECK-LABEL: @srem_XY_XZ_with_CY_gt_CZ_fail_missing_flag1(
; CHECK-NEXT: [[BO0:%.*]] = mul nuw nsw i8 [[X:%.*]], 10
More information about the llvm-commits
mailing list