[llvm] 1eb155e - [InstCombine] Fold `-X / -Y` to `X / Y` when it cannot overflow (#224025)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 18:43:42 PDT 2026
Author: Harrison Hao
Date: 2026-09-30T09:43:34+08:00
New Revision: 1eb155e606fa9bde58c48fe1248f7ad4d6d0c8bc
URL: https://github.com/llvm/llvm-project/commit/1eb155e606fa9bde58c48fe1248f7ad4d6d0c8bc
DIFF: https://github.com/llvm/llvm-project/commit/1eb155e606fa9bde58c48fe1248f7ad4d6d0c8bc.diff
LOG: [InstCombine] Fold `-X / -Y` to `X / Y` when it cannot overflow (#224025)
Fold:
```
(-X) / (-Y) -> X / Y
```
Do not combine when X may be INT_MIN and Y may be -1, as the result
could introduce signed division overflow.
For AMDGPU example:
https://godbolt.org/z/6jj6E8T5T
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
llvm/test/Transforms/InstCombine/div.ll
llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 16a7b98666d74..fb412b35f00ae 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1962,8 +1962,21 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) {
}
}
- // -X / Y --> -(X / Y)
Value *Y;
+ // -X / -Y --> X / Y, unless X == INT_MIN and Y == -1.
+ if (Value *NegOp0 = dyn_castNegVal(Op0))
+ if (Value *NegOp1 = dyn_castNegVal(Op1))
+ if (!computeKnownBits(NegOp0, &I)
+ .getSignedMinValue()
+ .isMinSignedValue() ||
+ (match(Op0, m_NSWNeg(m_Value())) &&
+ !computeKnownBits(NegOp1, &I).Zero.isZero())) {
+ auto *BO = BinaryOperator::CreateSDiv(NegOp0, NegOp1);
+ BO->setIsExact(I.isExact());
+ return BO;
+ }
+
+ // -X / Y --> -(X / Y)
if (match(&I, m_SDiv(m_OneUse(m_NSWNeg(m_Value(X))), m_Value(Y))))
return BinaryOperator::CreateNSWNeg(
Builder.CreateSDiv(X, Y, I.getName(), I.isExact()));
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 75a6c897e6133..65f2f37bdd2b8 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -539,12 +539,12 @@ define <2 x i64> @sdiv_exact_negated_dividend_constant_divisor_vec(<2 x i64> %x)
ret <2 x i64> %div
}
-; Can't negate signed min vector element.
-
+; Negating the signed min divisor wraps back to itself. If the dividend is
+; signed min, the source is poison due to the nsw negation, so producing 1
+; in the result is a valid refinement.
define <2 x i8> @sdiv_exact_negated_dividend_constant_divisor_vec_overflow(<2 x i8> %x) {
; CHECK-LABEL: @sdiv_exact_negated_dividend_constant_divisor_vec_overflow(
-; CHECK-NEXT: [[DIV1:%.*]] = sdiv exact <2 x i8> [[X:%.*]], <i8 -128, i8 42>
-; CHECK-NEXT: [[DIV:%.*]] = sub nsw <2 x i8> zeroinitializer, [[DIV1]]
+; CHECK-NEXT: [[DIV:%.*]] = sdiv exact <2 x i8> [[X:%.*]], <i8 -128, i8 -42>
; CHECK-NEXT: ret <2 x i8> [[DIV]]
;
%neg = sub nsw <2 x i8> zeroinitializer, %x
diff --git a/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll b/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
index f427dbd1ac97b..ba8712bbb7902 100644
--- a/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
+++ b/llvm/test/Transforms/InstCombine/sdiv-canonicalize.ll
@@ -147,6 +147,86 @@ define i32 @sdiv_abs_extra_use(i32 %x) {
ret i32 %r
}
+define i32 @sdiv_neg_neg_unknown(i32 %x, i32 %y) {
+; CHECK-LABEL: @sdiv_neg_neg_unknown(
+; CHECK-NEXT: [[NEG_Y:%.*]] = sub nsw i32 0, [[Y:%.*]]
+; CHECK-NEXT: [[SDIV1:%.*]] = sdiv i32 [[X:%.*]], [[NEG_Y]]
+; CHECK-NEXT: [[SDIV:%.*]] = sub nsw i32 0, [[SDIV1]]
+; CHECK-NEXT: ret i32 [[SDIV]]
+;
+ %neg.x = sub nsw i32 0, %x
+ %neg.y = sub nsw i32 0, %y
+ %sdiv = sdiv i32 %neg.x, %neg.y
+ ret i32 %sdiv
+}
+
+define i32 @sdiv_neg_neg_x_not_signmask(i32 %a, i32 %y) {
+; CHECK-LABEL: @sdiv_neg_neg_x_not_signmask(
+; CHECK-NEXT: [[X:%.*]] = and i32 [[A:%.*]], 2147483647
+; CHECK-NEXT: [[SDIV:%.*]] = sdiv i32 [[X]], [[Y:%.*]]
+; CHECK-NEXT: ret i32 [[SDIV]]
+;
+ %x = and i32 %a, 2147483647
+ %neg.x = sub nsw i32 0, %x
+ %neg.y = sub nsw i32 0, %y
+ %sdiv = sdiv i32 %neg.x, %neg.y
+ ret i32 %sdiv
+}
+
+define i32 @sdiv_neg_neg_y_not_allones(i32 %x, i32 %b) {
+; CHECK-LABEL: @sdiv_neg_neg_y_not_allones(
+; CHECK-NEXT: [[Y:%.*]] = and i32 [[B:%.*]], -2
+; CHECK-NEXT: [[SDIV:%.*]] = sdiv i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT: ret i32 [[SDIV]]
+;
+ %y = and i32 %b, -2
+ %neg.x = sub nsw i32 0, %x
+ %neg.y = sub nsw i32 0, %y
+ %sdiv = sdiv i32 %neg.x, %neg.y
+ ret i32 %sdiv
+}
+
+define i32 @sdiv_neg_neg_exact(i32 %x, i32 %b) {
+; CHECK-LABEL: @sdiv_neg_neg_exact(
+; CHECK-NEXT: [[Y:%.*]] = and i32 [[B:%.*]], -2
+; CHECK-NEXT: [[SDIV:%.*]] = sdiv exact i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT: ret i32 [[SDIV]]
+;
+ %y = and i32 %b, -2
+ %neg.x = sub nsw i32 0, %x
+ %neg.y = sub nsw i32 0, %y
+ %sdiv = sdiv exact i32 %neg.x, %neg.y
+ ret i32 %sdiv
+}
+
+define <2 x i32> @sdiv_neg_neg_vec(<2 x i32> %x, <2 x i32> %b) {
+; CHECK-LABEL: @sdiv_neg_neg_vec(
+; CHECK-NEXT: [[Y:%.*]] = and <2 x i32> [[B:%.*]], splat (i32 -2)
+; CHECK-NEXT: [[SDIV:%.*]] = sdiv <2 x i32> [[X:%.*]], [[Y]]
+; CHECK-NEXT: ret <2 x i32> [[SDIV]]
+;
+ %y = and <2 x i32> %b, splat (i32 -2)
+ %neg.x = sub nsw <2 x i32> zeroinitializer, %x
+ %neg.y = sub nsw <2 x i32> zeroinitializer, %y
+ %sdiv = sdiv <2 x i32> %neg.x, %neg.y
+ ret <2 x i32> %sdiv
+}
+
+define i32 @sdiv_neg_neg_missing_nsw(i32 %x, i32 %b) {
+; CHECK-LABEL: @sdiv_neg_neg_missing_nsw(
+; CHECK-NEXT: [[Y:%.*]] = and i32 [[B:%.*]], -2
+; CHECK-NEXT: [[NEG_X:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT: [[NEG_Y:%.*]] = sub i32 0, [[Y]]
+; CHECK-NEXT: [[SDIV:%.*]] = sdiv i32 [[NEG_X]], [[NEG_Y]]
+; CHECK-NEXT: ret i32 [[SDIV]]
+;
+ %y = and i32 %b, -2
+ %neg.x = sub i32 0, %x
+ %neg.y = sub i32 0, %y
+ %sdiv = sdiv i32 %neg.x, %neg.y
+ ret i32 %sdiv
+}
+
!0 = !{!"function_entry_count", i64 1000}
;.
; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
More information about the llvm-commits
mailing list