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

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 23 22:03:56 PST 2023


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

>From 6a4b73675ea03e85ff2ba1f46620b9f2da8a0381 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/2] [InstCombine] Simplify `(X * C0) / (X * C1)` into `C0 /
 C1`.

proof: https://alive2.llvm.org/ce/z/IIEKgf
---
 .../InstCombine/InstCombineMulDivRem.cpp      | 12 +++
 llvm/test/Transforms/InstCombine/div.ll       | 93 +++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 40156726c7038b9..0032422cd3ce7c7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1207,6 +1207,18 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     }
   }
 
+  // (X * C0) / (X * C1) --> C0 / C1
+  Constant *C0, *C1;
+  if (match(Op0, m_c_Mul(m_Value(X), m_Constant(C0))) &&
+      match(Op1, m_c_Mul(m_Specific(X), m_Constant(C1)))) {
+    auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
+    auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
+    if ((IsSigned && OB0HasNSW) || (!IsSigned && OB0HasNUW)) {
+      replaceOperand(I, 0, C0);
+      replaceOperand(I, 1, C1);
+      return &I;
+    };
+  }
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index cd17d10d0e1de07..2fb4873c72f5832 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1432,6 +1432,99 @@ 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(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul(
+; CHECK-NEXT:    ret i8 2
+;
+  %add4 = mul i8 %x, 6
+  %add5 = mul nsw i8 %x, 12
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @sdiv_mul_nsw_mul_nsw(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
+; 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 i8 @sdiv_mul_mul_nsw(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_mul_nsw(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], 10
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul nsw i8 %x, 10
+  %add5 = mul i8 %x, 20
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @sdiv_mul_mul(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_mul(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul i8 %x, 10
+  %add5 = mul i8 %x, 20
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @udiv_mul_mul(i8 %x) {
+; CHECK-LABEL: @udiv_mul_mul(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul i8 %x, 10
+  %add5 = mul i8 %x, 20
+  %div = udiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul_nuw(i8 %x) {
+; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
+; CHECK-NEXT:    ret i8 1
+;
+  %add4 = mul nuw i8 %x, 10
+  %add5 = mul nuw i8 %x, 10
+  %div = udiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @udiv_mul_mul_nuw(i8 %x) {
+; CHECK-LABEL: @udiv_mul_mul_nuw(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul nuw i8 [[X:%.*]], 10
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul nuw i8 %x, 10
+  %add5 = mul i8 %x, 20
+  %div = udiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul(i8 %x) {
+; CHECK-LABEL: @udiv_mul_nuw_mul(
+; CHECK-NEXT:    ret i8 2
+;
+  %add4 = mul i8 %x, 10
+  %add5 = mul nuw i8 %x, 20
+  %div = udiv i8 %add5, %add4
+  ret i8 %div
+}
+
 define i32 @sdiv_sub1(i32 %arg) {
 ; CHECK-LABEL: @sdiv_sub1(
 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[ARG:%.*]], -2147483648

>From 3d5abb4a9cd981ec31d9659a5b2e959f62a5a3cd Mon Sep 17 00:00:00 2001
From: Zheng Junjie <zhengjunjie at iscas.ac.cn>
Date: Fri, 24 Nov 2023 13:07:51 +0800
Subject: [PATCH 2/2] fixup! [InstCombine] Simplify `(X * C0) / (X * C1)` into
 `C0 / C1`.

---
 .../InstCombine/InstCombineMulDivRem.cpp      |  56 +++++---
 llvm/test/Transforms/InstCombine/div.ll       | 132 ++++++++++++++++--
 2 files changed, 152 insertions(+), 36 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 0032422cd3ce7c7..c6b0fc9b884cf10 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -1207,17 +1207,44 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     }
   }
 
-  // (X * C0) / (X * C1) --> C0 / C1
-  Constant *C0, *C1;
-  if (match(Op0, m_c_Mul(m_Value(X), m_Constant(C0))) &&
-      match(Op1, m_c_Mul(m_Specific(X), m_Constant(C1)))) {
+
+  // (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();
-    if ((IsSigned && OB0HasNSW) || (!IsSigned && OB0HasNUW)) {
-      replaceOperand(I, 0, C0);
-      replaceOperand(I, 1, C1);
-      return &I;
+
+    auto CreateDivOrNull = [&](Value *A) -> Instruction * {
+      auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
+      auto OB1HasNUW =
+          cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
+
+      // if (IsSigned && OB0HasNSW && OB1HasNSW) {
+      //   return BinaryOperator::CreateSDiv(A, Z);
+      // }
+      if (!IsSigned && OB0HasNUW && OB1HasNUW) {
+        return BinaryOperator::CreateUDiv(A, Z);
+      };
+      if (isa<Constant>(A) && isa<Constant>(Z)) {
+        if (IsSigned && OB0HasNSW) {
+          return BinaryOperator::CreateSDiv(A, Z);
+        }
+        if (!IsSigned && OB0HasNUW) {
+          return BinaryOperator::CreateUDiv(A, Z);
+        };
+      };
+      return nullptr;
     };
+
+    if (match(Op1, m_c_Mul(m_Specific(X), m_Value(Z)))) {
+      auto *Val = CreateDivOrNull(Y);
+      if (Val)
+        return Val;
+    };
+    if (match(Op1, m_c_Mul(m_Specific(Y), m_Value(Z)))) {
+      auto *Val = CreateDivOrNull(X);
+      if (Val)
+        return Val;
+    }
   }
   return nullptr;
 }
@@ -1389,20 +1416,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 2fb4873c72f5832..cd4a09e7f4dedb9 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1433,8 +1433,110 @@ define <2 x i8> @sdiv_sdiv_mul_nsw(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
 }
 
 ; (X * C0) / (X * C1) --> C0 / C1
-define i8 @sdiv_mul_nsw_mul(i8 %x) {
+define i8 @sdiv_mul_nsw_mul(i8 %x,i8 %y,i8 %z) {
 ; CHECK-LABEL: @sdiv_mul_nsw_mul(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul 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 i8 %x, %z
+  %add5 = mul nsw i8 %x, %y
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+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 @sdiv_mul_mul_nsw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @sdiv_mul_mul_nsw(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul nsw i8 %x, %z
+  %add5 = mul i8 %x, %y
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @sdiv_mul_mul(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @sdiv_mul_mul(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul i8 %x, %z
+  %add5 = mul i8 %x, %y
+  %div = sdiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @udiv_mul_mul(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_mul(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul i8 %x, %z
+  %add5 = mul i8 %x, %y
+  %div = udiv 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 @udiv_mul_mul_nuw(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_mul_nuw(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul nuw i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul nuw i8 %x, %z
+  %add5 = mul i8 %x, %y
+  %div = udiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @udiv_mul_nuw_mul(i8 %x,i8 %y,i8 %z) {
+; CHECK-LABEL: @udiv_mul_nuw_mul(
+; CHECK-NEXT:    [[ADD4:%.*]] = mul i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[ADD5:%.*]] = mul nuw i8 [[X]], [[Y:%.*]]
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
+; CHECK-NEXT:    ret i8 [[DIV]]
+;
+  %add4 = mul i8 %x, %z
+  %add5 = mul nuw i8 %x, %y
+  %div = udiv i8 %add5, %add4
+  ret i8 %div
+}
+
+define i8 @sdiv_mul_nsw_constant_mul_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_nsw_constant_mul_constant(
 ; CHECK-NEXT:    ret i8 2
 ;
   %add4 = mul i8 %x, 6
@@ -1443,8 +1545,8 @@ define i8 @sdiv_mul_nsw_mul(i8 %x) {
   ret i8 %div
 }
 
-define i8 @sdiv_mul_nsw_mul_nsw(i8 %x) {
-; CHECK-LABEL: @sdiv_mul_nsw_mul_nsw(
+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
@@ -1453,8 +1555,8 @@ define i8 @sdiv_mul_nsw_mul_nsw(i8 %x) {
   ret i8 %div
 }
 
-define i8 @sdiv_mul_mul_nsw(i8 %x) {
-; CHECK-LABEL: @sdiv_mul_mul_nsw(
+define i8 @sdiv_mul_constant_mul_nsw_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_constant_mul_nsw_constant(
 ; CHECK-NEXT:    [[ADD4:%.*]] = mul nsw i8 [[X:%.*]], 10
 ; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
 ; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
@@ -1466,8 +1568,8 @@ define i8 @sdiv_mul_mul_nsw(i8 %x) {
   ret i8 %div
 }
 
-define i8 @sdiv_mul_mul(i8 %x) {
-; CHECK-LABEL: @sdiv_mul_mul(
+define i8 @sdiv_mul_constant_mul_constant(i8 %x) {
+; CHECK-LABEL: @sdiv_mul_constant_mul_constant(
 ; CHECK-NEXT:    [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
 ; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
 ; CHECK-NEXT:    [[DIV:%.*]] = sdiv i8 [[ADD5]], [[ADD4]]
@@ -1479,8 +1581,8 @@ define i8 @sdiv_mul_mul(i8 %x) {
   ret i8 %div
 }
 
-define i8 @udiv_mul_mul(i8 %x) {
-; CHECK-LABEL: @udiv_mul_mul(
+define i8 @udiv_mul_constant_mul_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_constant_mul_constant(
 ; CHECK-NEXT:    [[ADD4:%.*]] = mul i8 [[X:%.*]], 10
 ; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
 ; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
@@ -1492,8 +1594,8 @@ define i8 @udiv_mul_mul(i8 %x) {
   ret i8 %div
 }
 
-define i8 @udiv_mul_nuw_mul_nuw(i8 %x) {
-; CHECK-LABEL: @udiv_mul_nuw_mul_nuw(
+define i8 @udiv_mul_nuw_constant_mul_nuw_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_nuw_constant_mul_nuw_constant(
 ; CHECK-NEXT:    ret i8 1
 ;
   %add4 = mul nuw i8 %x, 10
@@ -1502,8 +1604,8 @@ define i8 @udiv_mul_nuw_mul_nuw(i8 %x) {
   ret i8 %div
 }
 
-define i8 @udiv_mul_mul_nuw(i8 %x) {
-; CHECK-LABEL: @udiv_mul_mul_nuw(
+define i8 @udiv_mul_constant_mul_nuw_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_constant_mul_nuw_constant(
 ; CHECK-NEXT:    [[ADD4:%.*]] = mul nuw i8 [[X:%.*]], 10
 ; CHECK-NEXT:    [[ADD5:%.*]] = mul i8 [[X]], 20
 ; CHECK-NEXT:    [[DIV:%.*]] = udiv i8 [[ADD5]], [[ADD4]]
@@ -1515,8 +1617,8 @@ define i8 @udiv_mul_mul_nuw(i8 %x) {
   ret i8 %div
 }
 
-define i8 @udiv_mul_nuw_mul(i8 %x) {
-; CHECK-LABEL: @udiv_mul_nuw_mul(
+define i8 @udiv_mul_constant_nuw_mul_constant(i8 %x) {
+; CHECK-LABEL: @udiv_mul_constant_nuw_mul_constant(
 ; CHECK-NEXT:    ret i8 2
 ;
   %add4 = mul i8 %x, 10



More information about the llvm-commits mailing list