[llvm] [InstCombine] simplify `(X * C0) / (X * C1)` into `C0 / C1`. (PR #73204)

via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 10 23:07:59 PST 2023


https://github.com/Z572 updated https://github.com/llvm/llvm-project/pull/73204

>From 9b1f6debf81f376cab47440716880fd407c144d1 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Thu, 23 Nov 2023 11:30:54 +0800
Subject: [PATCH 1/6] [InstCombine] Simplify `(X * C0) / (X * C1)` into `C0 /
 C1`.

proof: https://alive2.llvm.org/ce/z/IIEKgf
---
 .../InstCombine/InstCombineMulDivRem.cpp      | 41 +++++++++----
 llvm/test/Transforms/InstCombine/div.ll       | 61 +++++++++++++++++++
 2 files changed, 89 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 40156726c7038..fe6ae9cefd511 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1207,6 +1207,34 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     }
   }
 
+  // (X * Y) / (X * Z) --> Y / X (and commuted variants)
+  if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
+    auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
+    auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
+
+    auto CreateDivOrNull = [&](Value *A, Value *B) -> Instruction * {
+      auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
+      auto OB1HasNUW =
+          cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
+      const APInt *C;
+      if (IsSigned && OB0HasNSW && OB1HasNSW && (match(B, m_APInt(C))) &&
+          (*C != -1))
+        return BinaryOperator::CreateSDiv(A, B);
+      if (!IsSigned && OB0HasNUW && OB1HasNUW) {
+        return BinaryOperator::CreateUDiv(A, B);
+      };
+      return nullptr;
+    };
+
+    if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
+      if (auto *Val = CreateDivOrNull(Y, Z))
+        return Val;
+    };
+    if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
+      if (auto *Val = CreateDivOrNull(X, Z))
+        return Val;
+    }
+  }
   return nullptr;
 }
 
@@ -1377,20 +1405,7 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) {
   if (Instruction *NarrowDiv = narrowUDivURem(I, *this))
     return NarrowDiv;
 
-  // If the udiv operands are non-overflowing multiplies with a common operand,
-  // then eliminate the common factor:
-  // (A * B) / (A * X) --> B / X (and commuted variants)
-  // TODO: The code would be reduced if we had m_c_NUWMul pattern matching.
-  // TODO: If -reassociation handled this generally, we could remove this.
   Value *A, *B;
-  if (match(Op0, m_NUWMul(m_Value(A), m_Value(B)))) {
-    if (match(Op1, m_NUWMul(m_Specific(A), m_Value(X))) ||
-        match(Op1, m_NUWMul(m_Value(X), m_Specific(A))))
-      return BinaryOperator::CreateUDiv(B, X);
-    if (match(Op1, m_NUWMul(m_Specific(B), m_Value(X))) ||
-        match(Op1, m_NUWMul(m_Value(X), m_Specific(B))))
-      return BinaryOperator::CreateUDiv(A, X);
-  }
 
   // Look through a right-shift to find the common factor:
   // ((Op1 *nuw A) >> B) / Op1 --> A >> B
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index cd17d10d0e1de..4e926f55681f9 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1432,6 +1432,67 @@ define <2 x i8> @sdiv_sdiv_mul_nsw(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
   ret <2 x i8> %r
 }
 
+; (X * C0) / (X * C1) --> C0 / C1
+define i8 @sdiv_mul_nsw_mul_nsw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = mul nsw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul nsw i8 %x, %z
+  %add5 = mul nsw i8 %x, %y
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul_nuw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul nuw i8 %x, %z
+  %add5 = mul nuw i8 %x, %y
+  %div = udiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @sdiv_mul_nsw_constant_mul_nsw_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_nsw_constant(
+; CHECK-NEXT:    ret i8 2
+;
+  %add4 = mul nsw i8 %x, 5
+  %add5 = mul nsw i8 %x, 10
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+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:    ret i4 [[DIV]]
+;
+  %add4 = mul nsw i4 %a, -1
+  %add5 = mul nsw i4 %a, -8
+  %div = sdiv i4 %add5, %add4
+  ret i4 %div
+}
+
+define i4 @sdiv_mul_nsw_mul_signmask(i4 %a, i4 %c2) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul_signmask(
+; CHECK-NEXT:    [[ADD4:%.*]] = shl i4 [[A:%.*]], 3
+; CHECK-NEXT:    [[ADD5:%.*]] = mul nsw i4 [[A]], [[C2:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i4 [[DIV]]
+;
+  %add4 = mul nsw i4 %a, -8
+  %add5 = mul nsw i4 %a, %c2
+  %div = sdiv i4 %add5, %add4
+  ret i4 %div
+}
+
 define i32 @sdiv_sub1(i32 %arg) {
 ; CHECK-LABEL: @sdiv_sub1(
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], -2147483648

>From fe9f30620420d1efb3f6323c0c64f4319999956e Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Wed, 29 Nov 2023 23:27:01 +0800
Subject: [PATCH 2/6] fixup! [InstCombine] Simplify `(X * C0) / (X * C1)` into
 `C0 / C1`.

---
 .../Transforms/InstCombine/InstCombineMulDivRem.cpp    | 10 ++++++++--
 llvm/test/Transforms/InstCombine/div.ll                | 10 ++++++++++
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index fe6ae9cefd511..a66461847ebc3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1220,8 +1220,14 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
       if (IsSigned && OB0HasNSW && OB1HasNSW && (match(B, m_APInt(C))) &&
           (*C != -1))
         return BinaryOperator::CreateSDiv(A, B);
-      if (!IsSigned && OB0HasNUW && OB1HasNUW) {
-        return BinaryOperator::CreateUDiv(A, B);
+      if (!IsSigned && OB0HasNUW) {
+        if (OB1HasNUW)
+          return BinaryOperator::CreateUDiv(A, B);
+        if (auto *SV = simplifyUDivInst(A, B, /*IsExact*/ true,
+                                        SQ.getWithInstruction(&I)))
+          if (auto *CV = dyn_cast<Constant>(SV);
+              CV && !(isa<PoisonValue>(CV) || CV->containsPoisonElement()))
+            return replaceInstUsesWith(I, CV);
       };
       return nullptr;
     };
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 4e926f55681f9..f8a71767ad411 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1467,6 +1467,16 @@ define i8 @sdiv_mul_nsw_constant_mul_nsw_constant(i8 %x) {
   ret i8 %div
 }
 
+define i4 @udiv_mul_nuw_constant_mul_constant(i4 %a) {
+; CHECK-LABEL: @udiv_mul_nuw_constant_mul_constant(
+; CHECK-NEXT:    ret i4 2
+;
+  %add4 = mul i4 %a, 3
+  %add5 = mul nuw i4 %a, 6
+  %div = udiv i4 %add5, %add4
+  ret i4 %div
+}
+
 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:%.*]]

>From 9c9520722d65a3b8ed35db0c5de5687f0d9b77ec Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Mon, 4 Dec 2023 21:46:26 +0800
Subject: [PATCH 3/6] fixup! fixup! [InstCombine] Simplify `(X * C0) / (X *
 C1)` into `C0 / C1`.

---
 .../InstCombine/InstCombineMulDivRem.cpp      | 16 +++++--
 llvm/test/Transforms/InstCombine/div.ll       | 47 +++++++++++++++++++
 2 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index a66461847ebc3..0805a05fabd88 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1217,9 +1217,19 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
       auto OB1HasNUW =
           cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
       const APInt *C;
-      if (IsSigned && OB0HasNSW && OB1HasNSW && (match(B, m_APInt(C))) &&
-          (*C != -1))
-        return BinaryOperator::CreateSDiv(A, B);
+      if (IsSigned && OB0HasNSW) {
+        if (OB1HasNSW && (match(B, m_APInt(C))) && (*C != -1))
+          return BinaryOperator::CreateSDiv(A, B);
+        if (auto *SV = simplifySDivInst(A, B, /*IsExact*/ true,
+                                        SQ.getWithInstruction(&I))) {
+          if (auto *CV = dyn_cast<Constant>(SV);
+              CV && !(isa<PoisonValue>(CV) || CV->containsPoisonElement()))
+            if (match(B, m_APInt(C)) && !C->abs().isPowerOf2() &&
+                C->abs().sqrt().sle((Ty->getScalarSizeInBits() - 2))) {
+              return replaceInstUsesWith(I, SV);
+            }
+        }
+      }
       if (!IsSigned && OB0HasNUW) {
         if (OB1HasNUW)
           return BinaryOperator::CreateUDiv(A, B);
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index f8a71767ad411..1684e6c40f746 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1467,6 +1467,53 @@ define i8 @sdiv_mul_nsw_constant_mul_nsw_constant(i8 %x) {
   ret i8 %div
 }
 
+define i4 @sdiv_mul_nsw_constant_mul_constant(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant(
+; CHECK-NEXT:    ret i4 2
+;
+  %add4 = mul i4 %a, 3
+  %add5 = mul nsw i4 %a, 6
+  %div = sdiv i4 %add5, %add4
+  ret i4 %div
+}
+define i4 @sdiv_mul_nsw_constant_mul_constant2(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant2(
+; CHECK-NEXT:    [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = shl i4 [[A]], 3
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i4 [[DIV]]
+;
+  %add4 = mul i4 %a, 15
+  %add5 = mul nsw i4 %a, 8
+  %div = sdiv i4 %add5, %add4
+  ret i4 %div
+}
+
+define i4 @sdiv_mul_nsw_constant_mul_constant3(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant3(
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i4 [[A:%.*]], -8
+; CHECK-NEXT:    [[DIV:%.*]] = select i1 [[TMP1]], i4 1, i4 -1
+; CHECK-NEXT:    ret i4 [[DIV]]
+;
+  %add4 = mul i4 %a, 15
+  %add5 = mul nsw i4 %a, 1
+  %div = sdiv i4 %add5, %add4
+  ret i4 %div
+}
+
+define i4 @sdiv_mul_nsw_mul(i4 %a) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul(
+; CHECK-NEXT:    [[ADD4:%.*]] = sub i4 0, [[A:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = shl i4 [[A]], 3
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i4 [[DIV]]
+;
+  %add4 = mul i4 %a, -1
+  %add5 = mul nsw i4 %a, -8
+  %div = sdiv i4 %add5, %add4
+  ret i4 %div
+}
+
 define i4 @udiv_mul_nuw_constant_mul_constant(i4 %a) {
 ; CHECK-LABEL: @udiv_mul_nuw_constant_mul_constant(
 ; CHECK-NEXT:    ret i4 2

>From 339617e6f32fea57d5f9b574352fba62a4249a2d Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Thu, 7 Dec 2023 14:08:48 +0800
Subject: [PATCH 4/6] fixup! fixup! fixup! [InstCombine] Simplify `(X * C0) /
 (X * C1)` into `C0 / C1`.

---
 llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 0805a05fabd88..e1c0a9758402d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1218,16 +1218,14 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
           cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
       const APInt *C;
       if (IsSigned && OB0HasNSW) {
-        if (OB1HasNSW && (match(B, m_APInt(C))) && (*C != -1))
+        if (OB1HasNSW && (match(B, m_APInt(C))) && (!C->isAllOnes()))
           return BinaryOperator::CreateSDiv(A, B);
         if (auto *SV = simplifySDivInst(A, B, /*IsExact*/ true,
                                         SQ.getWithInstruction(&I))) {
           if (auto *CV = dyn_cast<Constant>(SV);
               CV && !(isa<PoisonValue>(CV) || CV->containsPoisonElement()))
-            if (match(B, m_APInt(C)) && !C->abs().isPowerOf2() &&
-                C->abs().sqrt().sle((Ty->getScalarSizeInBits() - 2))) {
+            if (match(B, m_APInt(C)) && !C->isSignMask())
               return replaceInstUsesWith(I, SV);
-            }
         }
       }
       if (!IsSigned && OB0HasNUW) {

>From ba88681a59d478e0ffa600506e4e5c8066a1cd56 Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Fri, 8 Dec 2023 14:58:12 +0800
Subject: [PATCH 5/6] fixup! fixup! fixup! fixup! [InstCombine] Simplify `(X *
 C0) / (X * C1)` into `C0 / C1`.

---
 .../InstCombine/InstCombineMulDivRem.cpp      | 33 ++++++++++---------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index e1c0a9758402d..7e77e305b5755 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1207,7 +1207,7 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     }
   }
 
-  // (X * Y) / (X * Z) --> Y / X (and commuted variants)
+  // (X * Y) / (X * Z) --> Y / Z (and commuted variants)
   if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
     auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
     auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
@@ -1216,34 +1216,35 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
       auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
       auto OB1HasNUW =
           cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
-      const APInt *C;
+      const APInt *C1, *C2;
       if (IsSigned && OB0HasNSW) {
-        if (OB1HasNSW && (match(B, m_APInt(C))) && (!C->isAllOnes()))
+        if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
           return BinaryOperator::CreateSDiv(A, B);
-        if (auto *SV = simplifySDivInst(A, B, /*IsExact*/ true,
-                                        SQ.getWithInstruction(&I))) {
-          if (auto *CV = dyn_cast<Constant>(SV);
-              CV && !(isa<PoisonValue>(CV) || CV->containsPoisonElement()))
-            if (match(B, m_APInt(C)) && !C->isSignMask())
-              return replaceInstUsesWith(I, SV);
+        if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) &&
+            !C2->isSignMask()) {
+          APInt Q, R;
+          APInt::sdivrem(*C1, *C2, Q, R);
+          if (R.isZero())
+            return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
         }
       }
       if (!IsSigned && OB0HasNUW) {
         if (OB1HasNUW)
           return BinaryOperator::CreateUDiv(A, B);
-        if (auto *SV = simplifyUDivInst(A, B, /*IsExact*/ true,
-                                        SQ.getWithInstruction(&I)))
-          if (auto *CV = dyn_cast<Constant>(SV);
-              CV && !(isa<PoisonValue>(CV) || CV->containsPoisonElement()))
-            return replaceInstUsesWith(I, CV);
-      };
+        if (match(A, m_APInt(C1)) && match(B, m_APInt(C2))) {
+          APInt Q, R;
+          APInt::udivrem(*C1, *C2, Q, R);
+          if (R.isZero())
+            return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
+        }
+      }
       return nullptr;
     };
 
     if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
       if (auto *Val = CreateDivOrNull(Y, Z))
         return Val;
-    };
+    }
     if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
       if (auto *Val = CreateDivOrNull(X, Z))
         return Val;

>From 2a6611698c6e2cf68cba59f2aabe11e6b3bd067c Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Mon, 11 Dec 2023 14:57:25 +0800
Subject: [PATCH 6/6] fixup! fixup! fixup! fixup! fixup! [InstCombine] Simplify
 `(X * C0) / (X * C1)` into `C0 / C1`.

---
 .../InstCombine/InstCombineMulDivRem.cpp      | 30 +++++++++----------
 llvm/test/Transforms/InstCombine/div.ll       |  5 +++-
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 7e77e305b5755..f127e7d0df646 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1212,7 +1212,7 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
     auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
 
-    auto CreateDivOrNull = [&](Value *A, Value *B) -> Instruction * {
+    auto CreateDivOrNull = [&](Value *A, Value *B, Value *C) -> Instruction * {
       auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
       auto OB1HasNUW =
           cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
@@ -1220,33 +1220,31 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
       if (IsSigned && OB0HasNSW) {
         if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
           return BinaryOperator::CreateSDiv(A, B);
-        if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) &&
-            !C2->isSignMask()) {
-          APInt Q, R;
-          APInt::sdivrem(*C1, *C2, Q, R);
-          if (R.isZero())
-            return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
-        }
+        if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)))
+          if (auto *V = simplifyMulInst(C, B, OB1HasNSW, OB1HasNUW,
+                                        SQ.getWithInstruction(&I))) {
+            const APInt *AV;
+            APInt Q, R;
+            APInt::sdivrem(*C1, *C2, Q, R);
+            if (match(V, m_APInt(AV)) && !AV->isMinSignedValue() && R.isZero())
+              return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
+          }
       }
       if (!IsSigned && OB0HasNUW) {
         if (OB1HasNUW)
           return BinaryOperator::CreateUDiv(A, B);
-        if (match(A, m_APInt(C1)) && match(B, m_APInt(C2))) {
-          APInt Q, R;
-          APInt::udivrem(*C1, *C2, Q, R);
-          if (R.isZero())
-            return replaceInstUsesWith(I, ConstantInt::get(A->getType(), Q));
-        }
+        if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) && C2->ule(*C1))
+          return BinaryOperator::CreateUDiv(A, B);
       }
       return nullptr;
     };
 
     if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
-      if (auto *Val = CreateDivOrNull(Y, Z))
+      if (auto *Val = CreateDivOrNull(Y, Z, X))
         return Val;
     }
     if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
-      if (auto *Val = CreateDivOrNull(X, Z))
+      if (auto *Val = CreateDivOrNull(X, Z, Y))
         return Val;
     }
   }
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index 1684e6c40f746..f2ba36bb8dec8 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1469,7 +1469,10 @@ define i8 @sdiv_mul_nsw_constant_mul_nsw_constant(i8 %x) {
 
 define i4 @sdiv_mul_nsw_constant_mul_constant(i4 %a) {
 ; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant(
-; CHECK-NEXT:    ret i4 2
+; CHECK-NEXT:    [[ADD4:%.*]] = mul i4 [[A:%.*]], 3
+; CHECK-NEXT:    [[ADD5:%.*]] = mul nsw i4 [[A]], 6
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i4 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i4 [[DIV]]
 ;
   %add4 = mul i4 %a, 3
   %add5 = mul nsw i4 %a, 6



More information about the llvm-commits mailing list