[llvm] 4966d8e - [InstCombine] distribute div over add with matching mul-by-constant

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 20 11:06:03 PST 2023


Author: Sanjay Patel
Date: 2023-02-20T13:45:06-05:00
New Revision: 4966d8ebe1bbe5bd6a4d28b36efdbe6dd1659b3f

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

LOG: [InstCombine] distribute div over add with matching mul-by-constant

((X * C2) + C1) / C2 --> X + C1/C2
https://alive2.llvm.org/ce/z/P66io8
https://alive2.llvm.org/ce/z/vghegw

This could be made more general -- the multiplier could be a
multiple of the divisor -- but this is the pattern from
issue #60754.

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index fbf229386701e..8ca99db8f4761 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -976,9 +976,9 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
                                       ConstantInt::get(Ty, Product));
     }
 
+    APInt Quotient(C2->getBitWidth(), /*val=*/0ULL, IsSigned);
     if ((IsSigned && match(Op0, m_NSWMul(m_Value(X), m_APInt(C1)))) ||
         (!IsSigned && match(Op0, m_NUWMul(m_Value(X), m_APInt(C1))))) {
-      APInt Quotient(C1->getBitWidth(), /*val=*/0ULL, IsSigned);
 
       // (X * C1) / C2 -> X / (C2 / C1) if C2 is a multiple of C1.
       if (isMultiple(*C2, *C1, Quotient, IsSigned)) {
@@ -1003,7 +1003,6 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
          C1->ult(C1->getBitWidth() - 1)) ||
         (!IsSigned && match(Op0, m_NUWShl(m_Value(X), m_APInt(C1))) &&
          C1->ult(C1->getBitWidth()))) {
-      APInt Quotient(C1->getBitWidth(), /*val=*/0ULL, IsSigned);
       APInt C1Shifted = APInt::getOneBitSet(
           C1->getBitWidth(), static_cast<unsigned>(C1->getZExtValue()));
 
@@ -1026,6 +1025,19 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
       }
     }
 
+    // Distribute div over add to eliminate a matching div/mul pair:
+    // ((X * C2) + C1) / C2 --> X + C1/C2
+    if (IsSigned &&
+        match(Op0, m_NSWAdd(m_NSWMul(m_Value(X), m_SpecificInt(*C2)),
+                            m_APInt(C1))) &&
+        isMultiple(*C1, *C2, Quotient, IsSigned))
+      return BinaryOperator::CreateNSWAdd(X, ConstantInt::get(Ty, Quotient));
+    if (!IsSigned &&
+        match(Op0, m_NUWAdd(m_NUWMul(m_Value(X), m_SpecificInt(*C2)),
+                            m_APInt(C1))) &&
+        isMultiple(*C1, *C2, Quotient, IsSigned))
+      return BinaryOperator::CreateNUWAdd(X, ConstantInt::get(Ty, Quotient));
+
     if (!C2->isZero()) // avoid X udiv 0
       if (Instruction *FoldedDiv = foldBinOpIntoSelectOrPhi(I))
         return FoldedDiv;

diff  --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index a31e8db4bb621..3f0b593d85810 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1492,11 +1492,11 @@ define i8 @sdiv_udiv_mul_nsw(i8 %x, i8 %y, i8 %z) {
   ret i8 %r
 }
 
+; ((X * C2) + C1) / C2 --> X + C1/C2
+
 define i6 @sdiv_distribute_mul_nsw_add_nsw(i6 %x) {
 ; CHECK-LABEL: @sdiv_distribute_mul_nsw_add_nsw(
-; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i6 [[X:%.*]], 3
-; CHECK-NEXT:    [[ADD:%.*]] = add nsw i6 [[MUL]], -15
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i6 [[ADD]], 3
+; CHECK-NEXT:    [[DIV:%.*]] = add nsw i6 [[X:%.*]], -5
 ; CHECK-NEXT:    ret i6 [[DIV]]
 ;
   %mul = mul nsw i6 %x, 3
@@ -1505,13 +1505,15 @@ define i6 @sdiv_distribute_mul_nsw_add_nsw(i6 %x) {
   ret i6 %div
 }
 
+; extra uses are ok
+
 define i32 @sdiv_distribute_mul_nsw_add_nsw_uses(i32 %x) {
 ; CHECK-LABEL: @sdiv_distribute_mul_nsw_add_nsw_uses(
 ; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[X:%.*]], 42
 ; CHECK-NEXT:    call void @use(i32 [[MUL]])
 ; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[MUL]], 126
 ; CHECK-NEXT:    call void @use(i32 [[ADD]])
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[ADD]], 42
+; CHECK-NEXT:    [[DIV:%.*]] = add nsw i32 [[X]], 3
 ; CHECK-NEXT:    ret i32 [[DIV]]
 ;
   %mul = mul nsw i32 %x, 42
@@ -1522,11 +1524,11 @@ define i32 @sdiv_distribute_mul_nsw_add_nsw_uses(i32 %x) {
   ret i32 %div
 }
 
+; vector splats work
+
 define <2 x i6> @udiv_distribute_mul_nuw_add_nuw(<2 x i6> %x) {
 ; CHECK-LABEL: @udiv_distribute_mul_nuw_add_nuw(
-; CHECK-NEXT:    [[MUL:%.*]] = mul nuw <2 x i6> [[X:%.*]], <i6 3, i6 3>
-; CHECK-NEXT:    [[ADD:%.*]] = add nuw <2 x i6> [[MUL]], <i6 15, i6 15>
-; CHECK-NEXT:    [[DIV:%.*]] = udiv <2 x i6> [[ADD]], <i6 3, i6 3>
+; CHECK-NEXT:    [[DIV:%.*]] = add nuw <2 x i6> [[X:%.*]], <i6 5, i6 5>
 ; CHECK-NEXT:    ret <2 x i6> [[DIV]]
 ;
   %mul = mul nuw <2 x i6> %x, <i6 3, i6 3>
@@ -1535,6 +1537,8 @@ define <2 x i6> @udiv_distribute_mul_nuw_add_nuw(<2 x i6> %x) {
   ret <2 x i6> %div
 }
 
+; negative test - constants must be evenly divisible
+
 define i6 @sdiv_distribute_mul_nsw_add_nsw_not_multiple_offset(i6 %x) {
 ; CHECK-LABEL: @sdiv_distribute_mul_nsw_add_nsw_not_multiple_offset(
 ; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i6 [[X:%.*]], 3
@@ -1548,6 +1552,8 @@ define i6 @sdiv_distribute_mul_nsw_add_nsw_not_multiple_offset(i6 %x) {
   ret i6 %div
 }
 
+; negative test - constants must be evenly divisible
+
 define i6 @udiv_distribute_mul_nuw_add_nuw_not_multiple_offset(i6 %x) {
 ; CHECK-LABEL: @udiv_distribute_mul_nuw_add_nuw_not_multiple_offset(
 ; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i6 [[X:%.*]], 3
@@ -1561,6 +1567,8 @@ define i6 @udiv_distribute_mul_nuw_add_nuw_not_multiple_offset(i6 %x) {
   ret i6 %div
 }
 
+; negative test - wrong no-wrap
+
 define i6 @sdiv_distribute_mul_nuw_add_nsw(i6 %x) {
 ; CHECK-LABEL: @sdiv_distribute_mul_nuw_add_nsw(
 ; CHECK-NEXT:    [[MUL:%.*]] = mul nuw i6 [[X:%.*]], 3
@@ -1574,6 +1582,8 @@ define i6 @sdiv_distribute_mul_nuw_add_nsw(i6 %x) {
   ret i6 %div
 }
 
+; negative test - wrong no-wrap
+
 define i6 @udiv_distribute_mul_nsw_add_nuw(i6 %x) {
 ; CHECK-LABEL: @udiv_distribute_mul_nsw_add_nuw(
 ; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i6 [[X:%.*]], 3


        


More information about the llvm-commits mailing list