[llvm] [InstCombine] Fold -X / -Y -> X / Y (PR #88422)

via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 11 12:10:38 PDT 2024


https://github.com/AtariDreams updated https://github.com/llvm/llvm-project/pull/88422

>From c1c7ea5bb85683f1021da28626da3578708d7e71 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Thu, 11 Apr 2024 13:56:36 -0400
Subject: [PATCH 1/2] [InstCombine] Pre-commit tests (NFC)

---
 llvm/test/Transforms/InstCombine/div.ll | 46 +++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index e8a25ff44d0296..ff46965bf584e8 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1648,6 +1648,52 @@ define i32 @sdiv_mul_nsw_sub_nsw(i32 %x, i32 %y) {
   ret i32 %d
 }
 
+define i32 @sdiv_neg_divisor_known_non_min(i32 %x, i32 %z) {
+; CHECK-LABEL: @sdiv_neg_divisor_known_non_min(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Z:%.*]], 1
+; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 0, [[Z1:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[OR]], [[SUB]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+entry:
+  %or = or i32 %x, 1
+  %sub = sub nsw i32 0, %z
+  %div = sdiv i32 %or, %sub
+  ret i32 %div
+}
+
+define i32 @double_negative_division(i32 %x, i32 %z) {
+; CHECK-LABEL: @double_negative_division(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 0, [[Z:%.*]]
+; CHECK-NEXT:    [[DIV21:%.*]] = sdiv i32 [[X:%.*]], [[SUB1]]
+; CHECK-NEXT:    [[DIV2:%.*]] = sub nsw i32 0, [[DIV21]]
+; CHECK-NEXT:    ret i32 [[DIV2]]
+;
+entry:
+  %sub2 = sub nsw i32 0, %x
+  %sub1 = sub nsw i32 0, %z
+  %div2 = sdiv i32 %sub2, %sub1
+  ret i32 %div2
+}
+
+; Negative test
+
+define i32 @negative_divisior_only(i32 %x, i32 %z) {
+; CHECK-LABEL: @negative_divisior_only(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 0, [[Z:%.*]]
+; CHECK-NEXT:    [[DIV2:%.*]] = sdiv i32 [[X:%.*]], [[SUB1]]
+; CHECK-NEXT:    ret i32 [[DIV2]]
+;
+entry:
+  %sub1 = sub nsw i32 0, %z
+  %div2 = sdiv i32 %x, %sub1
+  ret i32 %div2
+}
+
+
 ; exact propagates
 
 define i8 @sdiv_sdiv_mul_nsw_exact_exact(i8 %x, i8 %y, i8 %z) {

>From 78462df3b78c579ab4afe3b78aefb30916fc8f50 Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Thu, 11 Apr 2024 13:58:15 -0400
Subject: [PATCH 2/2] [InstCombine] Fold -X / -Y -> X / Y, and X / -Y -> -(X /
 Y) if X is known to not be INT_MIN

Alive Proofs:

https://alive2.llvm.org/ce/z/zLMokH
https://alive2.llvm.org/ce/z/xviNg3
https://alive2.llvm.org/ce/z/4rdGvf
---
 .../InstCombine/InstCombineMulDivRem.cpp      | 23 +++++++++++++++----
 llvm/test/Transforms/InstCombine/div.ll       | 22 ++++++++----------
 2 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 8c698e52b5a0e6..1340c6250970a6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1572,8 +1572,7 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) {
     // -X / C --> X / -C (if the negation doesn't overflow).
     // TODO: This could be enhanced to handle arbitrary vector constants by
     //       checking if all elements are not the min-signed-val.
-    if (!Op1C->isMinSignedValue() &&
-        match(Op0, m_NSWSub(m_Zero(), m_Value(X)))) {
+    if (!Op1C->isMinSignedValue() && match(Op0, m_NSWNeg(m_Value(X)))) {
       Constant *NegC = ConstantInt::get(Ty, -(*Op1C));
       Instruction *BO = BinaryOperator::CreateSDiv(X, NegC);
       BO->setIsExact(I.isExact());
@@ -1581,12 +1580,27 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) {
     }
   }
 
-  // -X / Y --> -(X / Y)
+  KnownBits KnownDividend = computeKnownBits(Op0, 0, &I);
   Value *Y;
-  if (match(&I, m_SDiv(m_OneUse(m_NSWSub(m_Zero(), m_Value(X))), m_Value(Y))))
+  // -X / -Y --> (X / Y)
+  if (!KnownDividend.getSignedMinValue().isMinSignedValue() && match(&I, m_SDiv(m_NSWNeg(m_Value(X)), m_NSWNeg(m_Value(Y))))) {
+    auto *NewDiv = BinaryOperator::CreateSDiv(X, Y);
+    NewDiv->setIsExact(I.isExact());
+    return NewDiv;
+  }
+
+  // -X / Y --> -(X / Y)
+  if (match(&I, m_SDiv(m_OneUse(m_Value(X)), m_Value(Y))))
     return BinaryOperator::CreateNSWNeg(
         Builder.CreateSDiv(X, Y, I.getName(), I.isExact()));
 
+  // X / -Y --> -(X / Y), if X is known to not be INT_MIN
+  if (!KnownDividend.getSignedMinValue().isMinSignedValue() &&
+      match(&I, m_SDiv(m_Value(X), m_OneUse(m_NSWNeg(m_Value(Y)))))) {
+    return BinaryOperator::CreateNSWNeg(
+        Builder.CreateSDiv(X, Y, I.getName(), I.isExact()));
+  }
+
   // abs(X) / X --> X > -1 ? 1 : -1
   // X / abs(X) --> X > -1 ? 1 : -1
   if (match(&I, m_c_BinOp(
@@ -1597,7 +1611,6 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) {
                               ConstantInt::getAllOnesValue(Ty));
   }
 
-  KnownBits KnownDividend = computeKnownBits(Op0, 0, &I);
   if (!I.isExact() &&
       (match(Op1, m_Power2(Op1C)) || match(Op1, m_NegatedPower2(Op1C))) &&
       KnownDividend.countMinTrailingZeros() >= Op1C->countr_zero()) {
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index ff46965bf584e8..b25b91f4a2948c 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1542,9 +1542,9 @@ define i4 @udiv_mul_nuw_mul_negative(i4 %a) {
 
 define i4 @sdiv_mul_nsw_mul_nsw_allones(i4 %a) {
 ; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw_allones(
-; CHECK-NEXT:    [[ADD4:%.*]] = sub nsw i4 0, [[A:%.*]]
-; CHECK-NEXT:    [[ADD5:%.*]] = shl i4 [[A]], 3
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    [[ADD5:%.*]] = shl i4 [[A:%.*]], 3
+; CHECK-NEXT:    [[DIV1:%.*]] = sdiv i4 [[ADD5]], [[A]]
+; CHECK-NEXT:    [[DIV:%.*]] = sub nsw i4 0, [[DIV1]]
 ; CHECK-NEXT:    ret i4 [[DIV]]
 ;
   %add4 = mul nsw i4 %a, -1
@@ -1651,9 +1651,9 @@ define i32 @sdiv_mul_nsw_sub_nsw(i32 %x, i32 %y) {
 define i32 @sdiv_neg_divisor_known_non_min(i32 %x, i32 %z) {
 ; CHECK-LABEL: @sdiv_neg_divisor_known_non_min(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[Z:%.*]], 1
-; CHECK-NEXT:    [[SUB:%.*]] = sub nsw i32 0, [[Z1:%.*]]
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[OR]], [[SUB]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[X:%.*]], 1
+; CHECK-NEXT:    [[DIV1:%.*]] = sdiv i32 [[OR]], [[Z:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = sub nsw i32 0, [[DIV1]]
 ; CHECK-NEXT:    ret i32 [[DIV]]
 ;
 entry:
@@ -1666,10 +1666,8 @@ entry:
 define i32 @double_negative_division(i32 %x, i32 %z) {
 ; CHECK-LABEL: @double_negative_division(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 0, [[Z:%.*]]
-; CHECK-NEXT:    [[DIV21:%.*]] = sdiv i32 [[X:%.*]], [[SUB1]]
-; CHECK-NEXT:    [[DIV2:%.*]] = sub nsw i32 0, [[DIV21]]
-; CHECK-NEXT:    ret i32 [[DIV2]]
+; CHECK-NEXT:    [[DIV21:%.*]] = sdiv i32 [[X:%.*]], [[SUB1:%.*]]
+; CHECK-NEXT:    ret i32 [[DIV21]]
 ;
 entry:
   %sub2 = sub nsw i32 0, %x
@@ -1683,8 +1681,8 @@ entry:
 define i32 @negative_divisior_only(i32 %x, i32 %z) {
 ; CHECK-LABEL: @negative_divisior_only(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[SUB1:%.*]] = sub nsw i32 0, [[Z:%.*]]
-; CHECK-NEXT:    [[DIV2:%.*]] = sdiv i32 [[X:%.*]], [[SUB1]]
+; CHECK-NEXT:    [[DIV21:%.*]] = sdiv i32 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[DIV2:%.*]] = sub nsw i32 0, [[DIV21]]
 ; CHECK-NEXT:    ret i32 [[DIV2]]
 ;
 entry:



More information about the llvm-commits mailing list