[llvm] 8da2fa8 - [InstCombine] fold sdiv with hidden common factor

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 6 10:14:04 PDT 2022


Author: Sanjay Patel
Date: 2022-10-06T13:11:50-04:00
New Revision: 8da2fa856f1b7ddd079e7b0637082f1413d97ea2

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

LOG: [InstCombine] fold sdiv with hidden common factor

(X * Y) s/ (X << Z) --> Y s/ (1 << Z)

https://alive2.llvm.org/ce/z/yRSddG

issue #58137

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/test/Transforms/InstCombine/div-shift.ll
    llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 2267e00fee24..73afae663852 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -970,12 +970,17 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     auto *OBO0 = cast<OverflowingBinaryOperator>(Op0);
     auto *OBO1 = cast<OverflowingBinaryOperator>(Op1);
     bool HasNUW = OBO0->hasNoUnsignedWrap() && OBO1->hasNoUnsignedWrap();
+    bool HasNSW = OBO0->hasNoSignedWrap() && OBO1->hasNoSignedWrap();
 
     // (X * Y) u/ (X << Z) --> Y u>> Z
     if (!IsSigned && HasNUW)
       return BinaryOperator::CreateLShr(Y, Z);
 
-    // TODO: Handle signed division.
+    // (X * Y) s/ (X << Z) --> Y s/ (1 << Z)
+    if (IsSigned && HasNSW && (Op0->hasOneUse() || Op1->hasOneUse())) {
+      Value *Shl = Builder.CreateShl(ConstantInt::get(Ty, 1), Z);
+      return BinaryOperator::CreateSDiv(Y, Shl);
+    }
   }
 
   return nullptr;

diff  --git a/llvm/test/Transforms/InstCombine/div-shift.ll b/llvm/test/Transforms/InstCombine/div-shift.ll
index cfa8d55ff6d7..85c2fc3e53e1 100644
--- a/llvm/test/Transforms/InstCombine/div-shift.ll
+++ b/llvm/test/Transforms/InstCombine/div-shift.ll
@@ -295,11 +295,12 @@ define <2 x i32> @t16(<2 x i32> %x, <2 x i32> %y) {
   ret <2 x i32> %r
 }
 
+; (X * Y) s/ (X << Z) --> Y s/ (1 << Z)
+
 define i5 @sdiv_mul_shl_nsw(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_nsw(
-; CHECK-NEXT:    [[M1:%.*]] = mul nsw i5 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[M2:%.*]] = shl nsw i5 [[X]], [[Z:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sdiv i5 [[M1]], [[M2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw i5 1, [[Z:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = sdiv i5 [[Y:%.*]], [[TMP1]]
 ; CHECK-NEXT:    ret i5 [[D]]
 ;
   %m1 = mul nsw i5 %x, %y
@@ -308,11 +309,12 @@ define i5 @sdiv_mul_shl_nsw(i5 %x, i5 %y, i5 %z) {
   ret i5 %d
 }
 
+; (Y * Z) s/ (X << Z) --> Y s/ (1 << Z)
+
 define i5 @sdiv_mul_shl_nsw_commute1(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_nsw_commute1(
-; CHECK-NEXT:    [[M1:%.*]] = mul nsw i5 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT:    [[M2:%.*]] = shl nsw i5 [[X]], [[Z:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sdiv i5 [[M1]], [[M2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw i5 1, [[Z:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = sdiv i5 [[Y:%.*]], [[TMP1]]
 ; CHECK-NEXT:    ret i5 [[D]]
 ;
   %m1 = mul nsw i5 %y, %x
@@ -321,6 +323,8 @@ define i5 @sdiv_mul_shl_nsw_commute1(i5 %x, i5 %y, i5 %z) {
   ret i5 %d
 }
 
+; negative test - shl is not commutative
+
 define i5 @sdiv_mul_shl_nsw_commute2(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_nsw_commute2(
 ; CHECK-NEXT:    [[M1:%.*]] = mul nsw i5 [[Y:%.*]], [[X:%.*]]
@@ -334,12 +338,14 @@ define i5 @sdiv_mul_shl_nsw_commute2(i5 %x, i5 %y, i5 %z) {
   ret i5 %d
 }
 
+; extra use is ok
+
 define i8 @sdiv_mul_shl_nsw_use1(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_nsw_use1(
 ; CHECK-NEXT:    [[M1:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @use(i8 [[M1]])
-; CHECK-NEXT:    [[M2:%.*]] = shl nsw i8 [[X]], [[Z:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[M1]], [[M2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw i8 1, [[Z:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[Y]], [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[D]]
 ;
   %m1 = mul nsw i8 %x, %y
@@ -349,12 +355,14 @@ define i8 @sdiv_mul_shl_nsw_use1(i8 %x, i8 %y, i8 %z) {
   ret i8 %d
 }
 
+; extra use is ok
+
 define i8 @sdiv_mul_shl_nsw_use2(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_nsw_use2(
-; CHECK-NEXT:    [[M1:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[M2:%.*]] = shl nsw i8 [[X]], [[Z:%.*]]
+; CHECK-NEXT:    [[M2:%.*]] = shl nsw i8 [[X:%.*]], [[Z:%.*]]
 ; CHECK-NEXT:    call void @use(i8 [[M2]])
-; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[M1]], [[M2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw i8 1, [[Z]]
+; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[Y:%.*]], [[TMP1]]
 ; CHECK-NEXT:    ret i8 [[D]]
 ;
   %m1 = mul nsw i8 %x, %y
@@ -364,6 +372,8 @@ define i8 @sdiv_mul_shl_nsw_use2(i8 %x, i8 %y, i8 %z) {
   ret i8 %d
 }
 
+; negative test - both operands can't have extra uses
+
 define i8 @sdiv_mul_shl_nsw_use3(i8 %x, i8 %y, i8 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_nsw_use3(
 ; CHECK-NEXT:    [[M1:%.*]] = mul nsw i8 [[X:%.*]], [[Y:%.*]]
@@ -381,6 +391,8 @@ define i8 @sdiv_mul_shl_nsw_use3(i8 %x, i8 %y, i8 %z) {
   ret i8 %d
 }
 
+; negative test - shl must be divisor
+
 define i5 @sdiv_shl_mul_nsw(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @sdiv_shl_mul_nsw(
 ; CHECK-NEXT:    [[M1:%.*]] = shl nsw i5 [[Z:%.*]], [[X:%.*]]
@@ -394,6 +406,8 @@ define i5 @sdiv_shl_mul_nsw(i5 %x, i5 %y, i5 %z) {
   ret i5 %d
 }
 
+; negative test - wrong no-wrap
+
 define i5 @sdiv_mul_shl_missing_nsw1(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_missing_nsw1(
 ; CHECK-NEXT:    [[M1:%.*]] = mul nsw i5 [[X:%.*]], [[Y:%.*]]
@@ -407,6 +421,8 @@ define i5 @sdiv_mul_shl_missing_nsw1(i5 %x, i5 %y, i5 %z) {
   ret i5 %d
 }
 
+; negative test - wrong no-wrap
+
 define i5 @sdiv_mul_shl_missing_nsw2(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_missing_nsw2(
 ; CHECK-NEXT:    [[M1:%.*]] = mul nuw i5 [[X:%.*]], [[Y:%.*]]

diff  --git a/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll b/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll
index 2fc37b79e529..fb9e5d0f5694 100644
--- a/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll
+++ b/llvm/test/Transforms/PhaseOrdering/reassociate-instcombine.ll
@@ -39,11 +39,7 @@ define i32 @not_reassociate_or_or_not(i32 %a, i32 %b, i32 %c, i32 %d) {
 
 define i32 @PR58137(i32 %a, i32 %b) {
 ; CHECK-LABEL: @PR58137(
-; CHECK-NEXT:    [[MUL:%.*]] = shl i32 [[A:%.*]], 1
-; CHECK-NEXT:    [[MUL1:%.*]] = mul i32 [[MUL]], [[B:%.*]]
-; CHECK-NEXT:    [[MUL2:%.*]] = shl nsw i32 [[A]], 1
-; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 [[MUL1]], [[MUL2]]
-; CHECK-NEXT:    ret i32 [[DIV]]
+; CHECK-NEXT:    ret i32 [[B:%.*]]
 ;
   %mul = mul nsw i32 2, %b
   %mul1 = mul nsw i32 %mul, %a


        


More information about the llvm-commits mailing list