Skip to content

Commit 3a8018c

Browse files
committed
[InstCombine] Fold icmp pred X + K, Y -> icmp pred2 X, Y if both X and Y is divisible by K
1 parent 3830f4c commit 3a8018c

File tree

2 files changed

+64
-63
lines changed

2 files changed

+64
-63
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 60 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5120,6 +5120,15 @@ static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
51205120
return nullptr;
51215121
}
51225122

5123+
/// Return true if X is a multiple of C.
5124+
/// TODO: Handle non-power-of-2 factors.
5125+
static bool isMultipleOf(Value *X, const APInt &C, const SimplifyQuery &Q) {
5126+
if (!C.isPowerOf2())
5127+
return false;
5128+
5129+
return MaskedValueIsZero(X, C - 1, Q);
5130+
}
5131+
51235132
/// Try to fold icmp (binop), X or icmp X, (binop).
51245133
/// TODO: A large part of this logic is duplicated in InstSimplify's
51255134
/// simplifyICmpWithBinOp(). We should be able to share that and avoid the code
@@ -5278,66 +5287,62 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
52785287
return new ICmpInst(Pred, Y, Z);
52795288
}
52805289

5281-
// icmp slt (A + -1), Op1 -> icmp sle A, Op1
5282-
if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SLT &&
5283-
match(B, m_AllOnes()))
5284-
return new ICmpInst(CmpInst::ICMP_SLE, A, Op1);
5285-
5286-
// icmp sge (A + -1), Op1 -> icmp sgt A, Op1
5287-
if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SGE &&
5288-
match(B, m_AllOnes()))
5289-
return new ICmpInst(CmpInst::ICMP_SGT, A, Op1);
5290-
5291-
// icmp sle (A + 1), Op1 -> icmp slt A, Op1
5292-
if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SLE && match(B, m_One()))
5293-
return new ICmpInst(CmpInst::ICMP_SLT, A, Op1);
5294-
5295-
// icmp sgt (A + 1), Op1 -> icmp sge A, Op1
5296-
if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SGT && match(B, m_One()))
5297-
return new ICmpInst(CmpInst::ICMP_SGE, A, Op1);
5290+
if (ICmpInst::isRelational(Pred)) {
5291+
// Return if both X and Y is divisible by Z/-Z.
5292+
// TODO: Generalize to check if (X - Y) is divisible by Z/-Z.
5293+
auto ShareCommonDivisor = [&Q](Value *X, Value *Y, Value *Z,
5294+
bool IsNegative) -> bool {
5295+
const APInt *OffsetC;
5296+
if (!match(Z, m_APInt(OffsetC)))
5297+
return false;
52985298

5299-
// icmp sgt Op0, (C + -1) -> icmp sge Op0, C
5300-
if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SGT &&
5301-
match(D, m_AllOnes()))
5302-
return new ICmpInst(CmpInst::ICMP_SGE, Op0, C);
5299+
// Fast path for Z == 1/-1.
5300+
if (IsNegative ? OffsetC->isAllOnes() : OffsetC->isOne())
5301+
return true;
53035302

5304-
// icmp sle Op0, (C + -1) -> icmp slt Op0, C
5305-
if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SLE &&
5306-
match(D, m_AllOnes()))
5307-
return new ICmpInst(CmpInst::ICMP_SLT, Op0, C);
5303+
APInt C = *OffsetC;
5304+
if (IsNegative)
5305+
C.negate();
5306+
// Note: -INT_MIN is also negative.
5307+
if (!C.isStrictlyPositive())
5308+
return false;
53085309

5309-
// icmp sge Op0, (C + 1) -> icmp sgt Op0, C
5310-
if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SGE && match(D, m_One()))
5311-
return new ICmpInst(CmpInst::ICMP_SGT, Op0, C);
5310+
return isMultipleOf(X, C, Q) && isMultipleOf(Y, C, Q);
5311+
};
53125312

5313-
// icmp slt Op0, (C + 1) -> icmp sle Op0, C
5314-
if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SLT && match(D, m_One()))
5315-
return new ICmpInst(CmpInst::ICMP_SLE, Op0, C);
5313+
// TODO: The subtraction-related identities shown below also hold, but
5314+
// canonicalization from (X -nuw 1) to (X + -1) means that the combinations
5315+
// wouldn't happen even if they were implemented.
5316+
//
5317+
// icmp ult (A - 1), Op1 -> icmp ule A, Op1
5318+
// icmp uge (A - 1), Op1 -> icmp ugt A, Op1
5319+
// icmp ugt Op0, (C - 1) -> icmp uge Op0, C
5320+
// icmp ule Op0, (C - 1) -> icmp ult Op0, C
5321+
5322+
// icmp slt (A + -1), Op1 -> icmp sle A, Op1
5323+
// icmp sge (A + -1), Op1 -> icmp sgt A, Op1
5324+
// icmp sle (A + 1), Op1 -> icmp slt A, Op1
5325+
// icmp sgt (A + 1), Op1 -> icmp sge A, Op1
5326+
// icmp ule (A + 1), Op0 -> icmp ult A, Op1
5327+
// icmp ugt (A + 1), Op0 -> icmp uge A, Op1
5328+
if (A && NoOp0WrapProblem &&
5329+
ShareCommonDivisor(A, Op1, B,
5330+
ICmpInst::isLT(Pred) || ICmpInst::isGE(Pred)))
5331+
return new ICmpInst(ICmpInst::getFlippedStrictnessPredicate(Pred), A,
5332+
Op1);
53165333

5317-
// TODO: The subtraction-related identities shown below also hold, but
5318-
// canonicalization from (X -nuw 1) to (X + -1) means that the combinations
5319-
// wouldn't happen even if they were implemented.
5320-
//
5321-
// icmp ult (A - 1), Op1 -> icmp ule A, Op1
5322-
// icmp uge (A - 1), Op1 -> icmp ugt A, Op1
5323-
// icmp ugt Op0, (C - 1) -> icmp uge Op0, C
5324-
// icmp ule Op0, (C - 1) -> icmp ult Op0, C
5325-
5326-
// icmp ule (A + 1), Op0 -> icmp ult A, Op1
5327-
if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_ULE && match(B, m_One()))
5328-
return new ICmpInst(CmpInst::ICMP_ULT, A, Op1);
5329-
5330-
// icmp ugt (A + 1), Op0 -> icmp uge A, Op1
5331-
if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_UGT && match(B, m_One()))
5332-
return new ICmpInst(CmpInst::ICMP_UGE, A, Op1);
5333-
5334-
// icmp uge Op0, (C + 1) -> icmp ugt Op0, C
5335-
if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_UGE && match(D, m_One()))
5336-
return new ICmpInst(CmpInst::ICMP_UGT, Op0, C);
5337-
5338-
// icmp ult Op0, (C + 1) -> icmp ule Op0, C
5339-
if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_ULT && match(D, m_One()))
5340-
return new ICmpInst(CmpInst::ICMP_ULE, Op0, C);
5334+
// icmp sgt Op0, (C + -1) -> icmp sge Op0, C
5335+
// icmp sle Op0, (C + -1) -> icmp slt Op0, C
5336+
// icmp sge Op0, (C + 1) -> icmp sgt Op0, C
5337+
// icmp slt Op0, (C + 1) -> icmp sle Op0, C
5338+
// icmp uge Op0, (C + 1) -> icmp ugt Op0, C
5339+
// icmp ult Op0, (C + 1) -> icmp ule Op0, C
5340+
if (C && NoOp1WrapProblem &&
5341+
ShareCommonDivisor(Op0, C, D,
5342+
ICmpInst::isGT(Pred) || ICmpInst::isLE(Pred)))
5343+
return new ICmpInst(ICmpInst::getFlippedStrictnessPredicate(Pred), Op0,
5344+
C);
5345+
}
53415346

53425347
// if C1 has greater magnitude than C2:
53435348
// icmp (A + C1), (C + C2) -> icmp (A + C3), C

llvm/test/Transforms/InstCombine/icmp.ll

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,8 +1904,7 @@ define i1 @icmp_slt_offset_with_common_divisor(i64 %x, i64 %y) {
19041904
; CHECK-LABEL: @icmp_slt_offset_with_common_divisor(
19051905
; CHECK-NEXT: [[SHLX:%.*]] = shl i64 [[X:%.*]], 4
19061906
; CHECK-NEXT: [[SHLY:%.*]] = shl i64 [[Y:%.*]], 4
1907-
; CHECK-NEXT: [[SHLX_OFFSET:%.*]] = add nsw i64 [[SHLX]], -16
1908-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[SHLX_OFFSET]], [[SHLY]]
1907+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i64 [[SHLX]], [[SHLY]]
19091908
; CHECK-NEXT: ret i1 [[CMP]]
19101909
;
19111910
%shlx = shl i64 %x, 4
@@ -1919,8 +1918,7 @@ define i1 @icmp_slt_offset_with_smaller_common_divisor(i64 %x, i64 %y) {
19191918
; CHECK-LABEL: @icmp_slt_offset_with_smaller_common_divisor(
19201919
; CHECK-NEXT: [[SHLX:%.*]] = shl i64 [[X:%.*]], 4
19211920
; CHECK-NEXT: [[SHLY:%.*]] = shl i64 [[Y:%.*]], 4
1922-
; CHECK-NEXT: [[SHLX_OFFSET:%.*]] = add nsw i64 [[SHLX]], -8
1923-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[SHLX_OFFSET]], [[SHLY]]
1921+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i64 [[SHLX]], [[SHLY]]
19241922
; CHECK-NEXT: ret i1 [[CMP]]
19251923
;
19261924
%shlx = shl i64 %x, 4
@@ -1934,8 +1932,7 @@ define i1 @icmp_sle_offset_with_common_divisor(i64 %x, i64 %y) {
19341932
; CHECK-LABEL: @icmp_sle_offset_with_common_divisor(
19351933
; CHECK-NEXT: [[SHLX:%.*]] = shl i64 [[X:%.*]], 4
19361934
; CHECK-NEXT: [[SHLY:%.*]] = shl i64 [[Y:%.*]], 4
1937-
; CHECK-NEXT: [[SHLX_OFFSET:%.*]] = add nsw i64 [[SHLX]], 16
1938-
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i64 [[SHLX_OFFSET]], [[SHLY]]
1935+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[SHLX]], [[SHLY]]
19391936
; CHECK-NEXT: ret i1 [[CMP]]
19401937
;
19411938
%shlx = shl i64 %x, 4
@@ -1949,8 +1946,7 @@ define i1 @icmp_ule_offset_with_common_divisor(i64 %x, i64 %y) {
19491946
; CHECK-LABEL: @icmp_ule_offset_with_common_divisor(
19501947
; CHECK-NEXT: [[SHLX:%.*]] = shl i64 [[X:%.*]], 4
19511948
; CHECK-NEXT: [[SHLY:%.*]] = shl i64 [[Y:%.*]], 4
1952-
; CHECK-NEXT: [[SHLX_OFFSET:%.*]] = add nuw i64 [[SHLX]], 16
1953-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i64 [[SHLX_OFFSET]], [[SHLY]]
1949+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[SHLX]], [[SHLY]]
19541950
; CHECK-NEXT: ret i1 [[CMP]]
19551951
;
19561952
%shlx = shl i64 %x, 4

0 commit comments

Comments
 (0)