From 2ebfda2417e9cead344b020c1b1b7d3344893291 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Fri, 22 Jul 2022 22:08:47 +0000 Subject: [PATCH] [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 --- .../InstCombine/InstCombineCompares.cpp | 40 ++++++++++++++++++- .../ValueTracking/known-power-of-two-urem.ll | 2 +- llvm/test/Transforms/InstCombine/icmp-mul.ll | 36 ++++++----------- 3 files changed, 51 insertions(+), 27 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 16ad5b97d5ccd2..158d2e8289e0b6 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 99644c36a9965a..88278e2cd9624d 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 9a29d59fa4d429..e07e2d05136a19 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