[llvm] 7ec604a - [InstCombine] try harder to cancel out mul/div

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 11 06:52:48 PDT 2022


Author: Sanjay Patel
Date: 2022-10-11T09:51:51-04:00
New Revision: 7ec604a317c765552e28626dc85d610f8ca20dc0

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

LOG: [InstCombine] try harder to cancel out mul/div

((Op1 * X) / Y) / Op1 --> X / Y
https://alive2.llvm.org/ce/z/JYxWjA

InstSimplify handles the more basic mul+div pattern with
shared operand, but we don't seem to have any reassociation
folds to handle cases where the common op is further away.

This is a generalization of 9cff4711ac72 and another
transform derived from issue #58137.

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 0bea26ac57cd0..1f34d6f6fb80e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -983,6 +983,26 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     }
   }
 
+  // With the appropriate no-wrap constraint, remove a multiply by the divisor
+  // after peeking through another divide:
+  // ((Op1 * X) / Y) / Op1 --> X / Y
+  if (match(Op0, m_BinOp(I.getOpcode(), m_c_Mul(m_Specific(Op1), m_Value(X)),
+                         m_Value(Y)))) {
+    auto *InnerDiv = cast<PossiblyExactOperator>(Op0);
+    auto *Mul = cast<OverflowingBinaryOperator>(InnerDiv->getOperand(0));
+    Instruction *NewDiv = nullptr;
+    if (!IsSigned && Mul->hasNoUnsignedWrap())
+      NewDiv = BinaryOperator::CreateUDiv(X, Y);
+    else if (IsSigned && Mul->hasNoSignedWrap())
+      NewDiv = BinaryOperator::CreateSDiv(X, Y);
+
+    // Exact propagates only if both of the original divides are exact.
+    if (NewDiv) {
+      NewDiv->setIsExact(I.isExact() && InnerDiv->isExact());
+      return NewDiv;
+    }
+  }
+
   return nullptr;
 }
 

diff  --git a/llvm/test/Transforms/InstCombine/div.ll b/llvm/test/Transforms/InstCombine/div.ll
index e0d6465f9e442..9d06337354963 100644
--- a/llvm/test/Transforms/InstCombine/div.ll
+++ b/llvm/test/Transforms/InstCombine/div.ll
@@ -1347,11 +1347,11 @@ define i1 @udiv_one_icmpne_one(i32 %x) {
   ret i1 %B
 }
 
+; ((X * Y) / Z) / X --> Y / Z
+
 define i8 @udiv_udiv_mul_nuw(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @udiv_udiv_mul_nuw(
-; CHECK-NEXT:    [[M:%.*]] = mul nuw i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = udiv i8 [[M]], [[Z:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = udiv i8 [[D]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = udiv i8 [[Y:%.*]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %m = mul nuw i8 %x, %y
@@ -1360,11 +1360,11 @@ define i8 @udiv_udiv_mul_nuw(i8 %x, i8 %y, i8 %z) {
   ret i8 %r
 }
 
+; exact propagates and commute is ok
+
 define i8 @udiv_udiv_mul_nuw_exact_exact(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @udiv_udiv_mul_nuw_exact_exact(
-; CHECK-NEXT:    [[M:%.*]] = mul nuw i8 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = udiv exact i8 [[M]], [[Z:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = udiv exact i8 [[D]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = udiv exact i8 [[Y:%.*]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %m = mul nuw i8 %y, %x
@@ -1373,12 +1373,13 @@ define i8 @udiv_udiv_mul_nuw_exact_exact(i8 %x, i8 %y, i8 %z) {
   ret i8 %r
 }
 
+; extra uses are ok
+
 define i32 @udiv_udiv_mul_nuw_exact_use(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @udiv_udiv_mul_nuw_exact_use(
 ; CHECK-NEXT:    [[M:%.*]] = mul nuw i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[M]])
-; CHECK-NEXT:    [[D:%.*]] = udiv exact i32 [[M]], [[Z:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[D]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = udiv i32 [[Y]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %m = mul nuw i32 %x, %y
@@ -1388,6 +1389,8 @@ define i32 @udiv_udiv_mul_nuw_exact_use(i32 %x, i32 %y, i32 %z) {
   ret i32 %r
 }
 
+; negative test - must have nuw
+
 define i8 @udiv_udiv_mul_nsw(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @udiv_udiv_mul_nsw(
 ; CHECK-NEXT:    [[M:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]]
@@ -1401,6 +1404,8 @@ define i8 @udiv_udiv_mul_nsw(i8 %x, i8 %y, i8 %z) {
   ret i8 %r
 }
 
+; negative test - opcode mismatch
+
 define i8 @udiv_sdiv_mul_nuw(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @udiv_sdiv_mul_nuw(
 ; CHECK-NEXT:    [[M:%.*]] = mul nuw i8 [[X:%.*]], [[Y:%.*]]
@@ -1414,11 +1419,11 @@ define i8 @udiv_sdiv_mul_nuw(i8 %x, i8 %y, i8 %z) {
   ret i8 %r
 }
 
+; ((Y * X) / Z) / X --> Y / Z
+
 define <2 x i8> @sdiv_sdiv_mul_nsw(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
 ; CHECK-LABEL: @sdiv_sdiv_mul_nsw(
-; CHECK-NEXT:    [[M:%.*]] = mul nsw <2 x i8> [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sdiv <2 x i8> [[M]], [[Z:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = sdiv <2 x i8> [[D]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = sdiv <2 x i8> [[Y:%.*]], [[Z:%.*]]
 ; CHECK-NEXT:    ret <2 x i8> [[R]]
 ;
   %m = mul nsw <2 x i8> %y, %x
@@ -1427,11 +1432,11 @@ 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
 }
 
+; exact propagates
+
 define i8 @sdiv_sdiv_mul_nsw_exact_exact(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @sdiv_sdiv_mul_nsw_exact_exact(
-; CHECK-NEXT:    [[M:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sdiv exact i8 [[M]], [[Z:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = sdiv exact i8 [[D]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = sdiv exact i8 [[Y:%.*]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
   %m = mul nsw i8 %x, %y
@@ -1440,12 +1445,14 @@ define i8 @sdiv_sdiv_mul_nsw_exact_exact(i8 %x, i8 %y, i8 %z) {
   ret i8 %r
 }
 
+; extra uses are ok
+
 define i32 @sdiv_sdiv_mul_nsw_exact_use(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @sdiv_sdiv_mul_nsw_exact_use(
 ; CHECK-NEXT:    [[M:%.*]] = mul nsw i32 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i32 [[M]], [[Z:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[D]])
-; CHECK-NEXT:    [[R:%.*]] = sdiv exact i32 [[D]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = sdiv i32 [[Y]], [[Z]]
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
   %m = mul nsw i32 %x, %y
@@ -1455,6 +1462,8 @@ define i32 @sdiv_sdiv_mul_nsw_exact_use(i32 %x, i32 %y, i32 %z) {
   ret i32 %r
 }
 
+; negative test - must have nsw
+
 define i8 @sdiv_sdiv_mul_nuw(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @sdiv_sdiv_mul_nuw(
 ; CHECK-NEXT:    [[M:%.*]] = mul nuw i8 [[X:%.*]], [[Y:%.*]]
@@ -1468,6 +1477,8 @@ define i8 @sdiv_sdiv_mul_nuw(i8 %x, i8 %y, i8 %z) {
   ret i8 %r
 }
 
+; negative test - opcode mismatch
+
 define i8 @sdiv_udiv_mul_nsw(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @sdiv_udiv_mul_nsw(
 ; CHECK-NEXT:    [[M:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]]


        


More information about the llvm-commits mailing list