[llvm] 2ebfda2 - [InstCombine] Improve folding of mul + icmp

Alexander Shaposhnikov via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 22 15:09:34 PDT 2022


Author: Alexander Shaposhnikov
Date: 2022-07-22T22:08:53Z
New Revision: 2ebfda2417e9cead344b020c1b1b7d3344893291

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

LOG: [InstCombine] Improve folding of mul + icmp

This diff adds folds for patterns like X * A < B
where A, B are constants and "mul" has either "nsw" or "nuw".
(to address https://github.com/llvm/llvm-project/issues/56563).

Test plan:
1/ ninja check-llvm check-clang
2/ Bootstrapped LLVM/Clang pass tests

Differential revision: https://reviews.llvm.org/D130039

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Analysis/ValueTracking/known-power-of-two-urem.ll
    llvm/test/Transforms/InstCombine/icmp-mul.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 16ad5b97d5ccd..158d2e8289e0b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2002,9 +2002,12 @@ Instruction *InstCombinerImpl::foldICmpMulConstant(ICmpInst &Cmp,
                         Constant::getNullValue(Mul->getType()));
   }
 
+  if (MulC->isZero() || !(Mul->hasNoSignedWrap() || Mul->hasNoUnsignedWrap()))
+    return nullptr;
+
   // If the multiply does not wrap, try to divide the compare constant by the
   // multiplication factor.
-  if (Cmp.isEquality() && !MulC->isZero()) {
+  if (Cmp.isEquality()) {
     // (mul nsw X, MulC) == C --> X == C /s MulC
     if (Mul->hasNoSignedWrap() && C.srem(*MulC).isZero()) {
       Constant *NewC = ConstantInt::get(Mul->getType(), C.sdiv(*MulC));
@@ -2017,7 +2020,40 @@ Instruction *InstCombinerImpl::foldICmpMulConstant(ICmpInst &Cmp,
     }
   }
 
-  return nullptr;
+  Constant *NewC = nullptr;
+
+  // FIXME: Add assert that Pred is not equal to ICMP_SGE, ICMP_SLE,
+  // ICMP_UGE, ICMP_ULE.
+
+  if (Mul->hasNoSignedWrap()) {
+    if (MulC->isNegative()) {
+      // MININT / -1 --> overflow.
+      if (C.isMinSignedValue() && MulC->isAllOnes())
+        return nullptr;
+      Pred = ICmpInst::getSwappedPredicate(Pred);
+    }
+    if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE)
+      NewC = ConstantInt::get(
+          Mul->getType(),
+          APIntOps::RoundingSDiv(C, *MulC, APInt::Rounding::UP));
+    if (Pred == ICmpInst::ICMP_SLE || Pred == ICmpInst::ICMP_SGT)
+      NewC = ConstantInt::get(
+          Mul->getType(),
+          APIntOps::RoundingSDiv(C, *MulC, APInt::Rounding::DOWN));
+  }
+
+  if (Mul->hasNoUnsignedWrap()) {
+    if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE)
+      NewC = ConstantInt::get(
+          Mul->getType(),
+          APIntOps::RoundingUDiv(C, *MulC, APInt::Rounding::UP));
+    if (Pred == ICmpInst::ICMP_ULE || Pred == ICmpInst::ICMP_UGT)
+      NewC = ConstantInt::get(
+          Mul->getType(),
+          APIntOps::RoundingUDiv(C, *MulC, APInt::Rounding::DOWN));
+  }
+
+  return NewC ? new ICmpInst(Pred, Mul->getOperand(0), NewC) : nullptr;
 }
 
 /// Fold icmp (shl 1, Y), C.

diff  --git a/llvm/test/Analysis/ValueTracking/known-power-of-two-urem.ll b/llvm/test/Analysis/ValueTracking/known-power-of-two-urem.ll
index 99644c36a9965..88278e2cd9624 100644
--- a/llvm/test/Analysis/ValueTracking/known-power-of-two-urem.ll
+++ b/llvm/test/Analysis/ValueTracking/known-power-of-two-urem.ll
@@ -159,7 +159,7 @@ define i64 @known_power_of_two_urem_loop_mul_negative(i64 %size, i64 %a) {
 ; CHECK-NEXT:    [[UREM:%.*]] = urem i64 [[SIZE:%.*]], [[PHI]]
 ; CHECK-NEXT:    [[ADD]] = add nuw i64 [[SUM]], [[UREM]]
 ; CHECK-NEXT:    [[I]] = mul nuw i64 [[PHI]], 3
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp ult i64 [[I]], 100000000
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ult i64 [[PHI]], 33333334
 ; CHECK-NEXT:    br i1 [[ICMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
 ; CHECK:       for.end:
 ; CHECK-NEXT:    ret i64 [[SUM]]

diff  --git a/llvm/test/Transforms/InstCombine/icmp-mul.ll b/llvm/test/Transforms/InstCombine/icmp-mul.ll
index 9a29d59fa4d42..e07e2d05136a1 100644
--- a/llvm/test/Transforms/InstCombine/icmp-mul.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-mul.ll
@@ -7,8 +7,7 @@ declare void @use(i8)
 
 define i1 @slt_positive_multip_rem_zero(i8 %x) {
 ; CHECK-LABEL: @slt_positive_multip_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 7
-; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[X:%.*]], 3
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, 7
@@ -18,8 +17,7 @@ define i1 @slt_positive_multip_rem_zero(i8 %x) {
 
 define i1 @slt_negative_multip_rem_zero(i8 %x) {
 ; CHECK-LABEL: @slt_negative_multip_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], -7
-; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[X:%.*]], -3
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, -7
@@ -29,8 +27,7 @@ define i1 @slt_negative_multip_rem_zero(i8 %x) {
 
 define i1 @slt_positive_multip_rem_nz(i8 %x) {
 ; CHECK-LABEL: @slt_positive_multip_rem_nz(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 5
-; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[X:%.*]], 5
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, 5
@@ -40,8 +37,7 @@ define i1 @slt_positive_multip_rem_nz(i8 %x) {
 
 define i1 @ult_rem_zero(i8 %x) {
 ; CHECK-LABEL: @ult_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 7
-; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[X:%.*]], 3
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nuw i8 %x, 7
@@ -51,8 +47,7 @@ define i1 @ult_rem_zero(i8 %x) {
 
 define i1 @ult_rem_nz(i8 %x) {
 ; CHECK-LABEL: @ult_rem_nz(
-; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
-; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp ult i8 [[X:%.*]], 5
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nuw i8 %x, 5
@@ -64,8 +59,7 @@ define i1 @ult_rem_nz(i8 %x) {
 
 define i1 @sgt_positive_multip_rem_zero(i8 %x) {
 ; CHECK-LABEL: @sgt_positive_multip_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 7
-; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[X:%.*]], 3
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, 7
@@ -75,8 +69,7 @@ define i1 @sgt_positive_multip_rem_zero(i8 %x) {
 
 define i1 @sgt_negative_multip_rem_zero(i8 %x) {
 ; CHECK-LABEL: @sgt_negative_multip_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], -7
-; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp slt i8 [[X:%.*]], -3
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, -7
@@ -86,8 +79,7 @@ define i1 @sgt_negative_multip_rem_zero(i8 %x) {
 
 define i1 @sgt_positive_multip_rem_nz(i8 %x) {
 ; CHECK-LABEL: @sgt_positive_multip_rem_nz(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], 5
-; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp sgt i8 [[X:%.*]], 4
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, 5
@@ -97,8 +89,7 @@ define i1 @sgt_positive_multip_rem_nz(i8 %x) {
 
 define i1 @ugt_rem_zero(i8 %x) {
 ; CHECK-LABEL: @ugt_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 7
-; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[X:%.*]], 3
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nuw i8 %x, 7
@@ -108,8 +99,7 @@ define i1 @ugt_rem_zero(i8 %x) {
 
 define i1 @ugt_rem_nz(i8 %x) {
 ; CHECK-LABEL: @ugt_rem_nz(
-; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
-; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[A]], 21
+; CHECK-NEXT:    [[B:%.*]] = icmp ugt i8 [[X:%.*]], 4
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nuw i8 %x, 5
@@ -866,13 +856,11 @@ define i1 @splat_mul_known_lz(i32 %x) {
   ret i1 %r
 }
 
-; Negative test - the 33rd bit could be set.
+; The 33rd bit can only be set when MSB of x is set.
 
 define i1 @splat_mul_unknown_lz(i32 %x) {
 ; CHECK-LABEL: @splat_mul_unknown_lz(
-; CHECK-NEXT:    [[Z:%.*]] = zext i32 [[X:%.*]] to i128
-; CHECK-NEXT:    [[M:%.*]] = mul nuw nsw i128 [[Z]], 18446744078004518913
-; CHECK-NEXT:    [[R:%.*]] = icmp ult i128 [[M]], 39614081257132168796771975168
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i32 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %z = zext i32 %x to i128


        


More information about the llvm-commits mailing list