[llvm] afa3d58 - [InstCombine] Fold `(mul (div exact X, C0), C1)` -> `(div exact X, C0/C1)`

Noah Goldstein via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 28 01:52:23 PDT 2024


Author: Noah Goldstein
Date: 2024-06-28T16:52:03+08:00
New Revision: afa3d58ee2224f1037116f4cab44a23bd232a416

URL: https://github.com/llvm/llvm-project/commit/afa3d58ee2224f1037116f4cab44a23bd232a416
DIFF: https://github.com/llvm/llvm-project/commit/afa3d58ee2224f1037116f4cab44a23bd232a416.diff

LOG: [InstCombine] Fold `(mul (div exact X, C0), C1)` -> `(div exact X, C0/C1)`

We can do this if `C0 % C1 == 0` and if we avoid UB in the signed
case.

Proofs: https://alive2.llvm.org/ce/z/HHWHDg

Closes #96915

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/test/Transforms/InstCombine/exact.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 0824ca02c1289..3a2620db1f042 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -365,6 +365,28 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
       return BinaryOperator::CreateMul(NegOp0, X);
   }
 
+  if (Op0->hasOneUse()) {
+    // (mul (div exact X, C0), C1)
+    //    -> (div exact X, C0 / C1)
+    // iff C0 % C1 == 0 and X / (C0 / C1) doesn't create UB.
+    const APInt *C1;
+    auto UDivCheck = [&C1](const APInt &C) { return C.urem(*C1).isZero(); };
+    auto SDivCheck = [&C1](const APInt &C) {
+      APInt Quot, Rem;
+      APInt::sdivrem(C, *C1, Quot, Rem);
+      return Rem.isZero() && !Quot.isAllOnes();
+    };
+    if (match(Op1, m_APInt(C1)) &&
+        (match(Op0, m_Exact(m_UDiv(m_Value(X), m_CheckedInt(UDivCheck)))) ||
+         match(Op0, m_Exact(m_SDiv(m_Value(X), m_CheckedInt(SDivCheck)))))) {
+      auto BOpc = cast<BinaryOperator>(Op0)->getOpcode();
+      return BinaryOperator::CreateExact(
+          BOpc, X,
+          Builder.CreateBinOp(BOpc, cast<BinaryOperator>(Op0)->getOperand(1),
+                              Op1));
+    }
+  }
+
   // (X / Y) *  Y = X - (X % Y)
   // (X / Y) * -Y = (X % Y) - X
   {

diff  --git a/llvm/test/Transforms/InstCombine/exact.ll b/llvm/test/Transforms/InstCombine/exact.ll
index f4eb86cadc70a..ccad6f974ffb1 100644
--- a/llvm/test/Transforms/InstCombine/exact.ll
+++ b/llvm/test/Transforms/InstCombine/exact.ll
@@ -338,9 +338,8 @@ define <2 x i1> @sdiv_icmp6_vec(<2 x i64> %X) {
 
 define i8 @mul_of_udiv(i8 %x) {
 ; CHECK-LABEL: @mul_of_udiv(
-; CHECK-NEXT:    [[DIV:%.*]] = udiv exact i8 [[X:%.*]], 12
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i8 [[DIV]], 6
-; CHECK-NEXT:    ret i8 [[MUL]]
+; CHECK-NEXT:    [[MUL1:%.*]] = lshr exact i8 [[X:%.*]], 1
+; CHECK-NEXT:    ret i8 [[MUL1]]
 ;
   %div = udiv exact i8 %x, 12
   %mul = mul i8 %div, 6
@@ -349,8 +348,8 @@ define i8 @mul_of_udiv(i8 %x) {
 
 define i8 @mul_of_sdiv(i8 %x) {
 ; CHECK-LABEL: @mul_of_sdiv(
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv exact i8 [[X:%.*]], 12
-; CHECK-NEXT:    [[MUL:%.*]] = mul i8 [[DIV]], -6
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = ashr exact i8 [[X:%.*]], 1
+; CHECK-NEXT:    [[MUL:%.*]] = sub nsw i8 0, [[MUL_NEG]]
 ; CHECK-NEXT:    ret i8 [[MUL]]
 ;
   %div = sdiv exact i8 %x, 12
@@ -360,8 +359,7 @@ define i8 @mul_of_sdiv(i8 %x) {
 
 define <2 x i8> @mul_of_sdiv_non_splat(<2 x i8> %x) {
 ; CHECK-LABEL: @mul_of_sdiv_non_splat(
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv exact <2 x i8> [[X:%.*]], <i8 6, i8 -12>
-; CHECK-NEXT:    [[MUL:%.*]] = mul <2 x i8> [[DIV]], <i8 6, i8 6>
+; CHECK-NEXT:    [[MUL:%.*]] = sdiv exact <2 x i8> [[X:%.*]], <i8 1, i8 -2>
 ; CHECK-NEXT:    ret <2 x i8> [[MUL]]
 ;
   %div = sdiv exact <2 x i8> %x, <i8 6, i8 -12>


        


More information about the llvm-commits mailing list