forked from OSchip/llvm-project
[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
This commit is contained in:
parent
8f0c901c1a
commit
2ebfda2417
|
@ -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.
|
||||
|
|
|
@ -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]]
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue