Skip to content

Commit d5ee20f

Browse files
committed
[InstCombine] Switch an or of icmps fold to use constant ranges
We can express this fold more naturally when working on the constant range implementation. This change is not entirely NFC, because the code now also handles cases that don't match the precise pattern this previously looked for, e.g. we can omit an add on one of the ranges.
1 parent cf90233 commit d5ee20f

File tree

2 files changed

+27
-62
lines changed

2 files changed

+27
-62
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 25 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,7 +1172,7 @@ static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1,
11721172
static Value *foldAndOrOfICmpsUsingRanges(
11731173
ICmpInst::Predicate Pred1, Value *V1, const APInt &C1,
11741174
ICmpInst::Predicate Pred2, Value *V2, const APInt &C2,
1175-
IRBuilderBase &Builder, bool IsAnd) {
1175+
IRBuilderBase &Builder, bool IsAnd, bool BothHaveOneUse) {
11761176
// Look through add of a constant offset on V1, V2, or both operands. This
11771177
// allows us to interpret the V + C' < C'' range idiom into a proper range.
11781178
const APInt *Offset1 = nullptr, *Offset2 = nullptr;
@@ -1195,17 +1195,35 @@ static Value *foldAndOrOfICmpsUsingRanges(
11951195
if (Offset2)
11961196
CR2 = CR2.subtract(*Offset2);
11971197

1198+
Type *Ty = V1->getType();
1199+
Value *NewV = V1;
11981200
Optional<ConstantRange> CR =
11991201
IsAnd ? CR1.exactIntersectWith(CR2) : CR1.exactUnionWith(CR2);
1200-
if (!CR)
1201-
return nullptr;
1202+
if (!CR) {
1203+
// TODO: Support and.
1204+
if (IsAnd)
1205+
return nullptr;
1206+
1207+
if (!BothHaveOneUse || CR1.isWrappedSet() || CR2.isWrappedSet())
1208+
return nullptr;
1209+
1210+
// Check whether we have equal-size ranges that only differ by one bit.
1211+
// In that case we can apply a mask to map one range onto the other.
1212+
APInt LowerDiff = CR1.getLower() ^ CR2.getLower();
1213+
APInt UpperDiff = (CR1.getUpper() - 1) ^ (CR2.getUpper() - 1);
1214+
APInt CR1Size = CR1.getUpper() - CR1.getLower();
1215+
if (!LowerDiff.isPowerOf2() || LowerDiff != UpperDiff ||
1216+
CR1Size != CR2.getUpper() - CR2.getLower())
1217+
return nullptr;
1218+
1219+
CR = CR1.getLower().ult(CR2.getLower()) ? CR1 : CR2;
1220+
NewV = Builder.CreateAnd(NewV, ConstantInt::get(Ty, ~LowerDiff));
1221+
}
12021222

12031223
CmpInst::Predicate NewPred;
12041224
APInt NewC, Offset;
12051225
CR->getEquivalentICmp(NewPred, NewC, Offset);
12061226

1207-
Type *Ty = V1->getType();
1208-
Value *NewV = V1;
12091227
if (Offset != 0)
12101228
NewV = Builder.CreateAdd(NewV, ConstantInt::get(Ty, Offset));
12111229
return Builder.CreateICmp(NewPred, NewV, ConstantInt::get(Ty, NewC));
@@ -2418,58 +2436,6 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
24182436
match(LHS1, m_APInt(LHSC));
24192437
match(RHS1, m_APInt(RHSC));
24202438

2421-
// Fold (icmp ult/ule (A + C1), C3) | (icmp ult/ule (A + C2), C3)
2422-
// --> (icmp ult/ule ((A & ~(C1 ^ C2)) + max(C1, C2)), C3)
2423-
// The original condition actually refers to the following two ranges:
2424-
// [MAX_UINT-C1+1, MAX_UINT-C1+1+C3] and [MAX_UINT-C2+1, MAX_UINT-C2+1+C3]
2425-
// We can fold these two ranges if:
2426-
// 1) C1 and C2 is unsigned greater than C3.
2427-
// 2) The two ranges are separated.
2428-
// 3) C1 ^ C2 is one-bit mask.
2429-
// 4) LowRange1 ^ LowRange2 and HighRange1 ^ HighRange2 are one-bit mask.
2430-
// This implies all values in the two ranges differ by exactly one bit.
2431-
if (!IsAnd && (PredL == ICmpInst::ICMP_ULT || PredL == ICmpInst::ICMP_ULE) &&
2432-
PredL == PredR && LHSC && RHSC && LHS->hasOneUse() && RHS->hasOneUse() &&
2433-
LHSC->getBitWidth() == RHSC->getBitWidth() && *LHSC == *RHSC) {
2434-
2435-
Value *AddOpnd;
2436-
const APInt *LAddC, *RAddC;
2437-
if (match(LHS0, m_Add(m_Value(AddOpnd), m_APInt(LAddC))) &&
2438-
match(RHS0, m_Add(m_Specific(AddOpnd), m_APInt(RAddC))) &&
2439-
LAddC->ugt(*LHSC) && RAddC->ugt(*LHSC)) {
2440-
2441-
APInt DiffC = *LAddC ^ *RAddC;
2442-
if (DiffC.isPowerOf2()) {
2443-
const APInt *MaxAddC = nullptr;
2444-
if (LAddC->ult(*RAddC))
2445-
MaxAddC = RAddC;
2446-
else
2447-
MaxAddC = LAddC;
2448-
2449-
APInt RRangeLow = -*RAddC;
2450-
APInt RRangeHigh = RRangeLow + *LHSC;
2451-
APInt LRangeLow = -*LAddC;
2452-
APInt LRangeHigh = LRangeLow + *LHSC;
2453-
APInt LowRangeDiff = RRangeLow ^ LRangeLow;
2454-
APInt HighRangeDiff = RRangeHigh ^ LRangeHigh;
2455-
APInt RangeDiff = LRangeLow.sgt(RRangeLow) ? LRangeLow - RRangeLow
2456-
: RRangeLow - LRangeLow;
2457-
2458-
if (LowRangeDiff.isPowerOf2() && LowRangeDiff == HighRangeDiff &&
2459-
RangeDiff.ugt(*LHSC)) {
2460-
Type *Ty = AddOpnd->getType();
2461-
Value *MaskC = ConstantInt::get(Ty, ~DiffC);
2462-
2463-
Value *NewAnd = Builder.CreateAnd(AddOpnd, MaskC);
2464-
Value *NewAdd = Builder.CreateAdd(NewAnd,
2465-
ConstantInt::get(Ty, *MaxAddC));
2466-
return Builder.CreateICmp(LHS->getPredicate(), NewAdd,
2467-
ConstantInt::get(Ty, *LHSC));
2468-
}
2469-
}
2470-
}
2471-
}
2472-
24732439
// (icmp1 A, B) | (icmp2 A, B) --> (icmp3 A, B)
24742440
// (icmp1 A, B) & (icmp2 A, B) --> (icmp3 A, B)
24752441
if (predicatesFoldable(PredL, PredR)) {
@@ -2586,7 +2552,8 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
25862552
}
25872553

25882554
return foldAndOrOfICmpsUsingRanges(PredL, LHS0, *LHSC, PredR, RHS0, *RHSC,
2589-
Builder, IsAnd);
2555+
Builder, IsAnd,
2556+
LHS->hasOneUse() && RHS->hasOneUse());
25902557
}
25912558

25922559
// FIXME: We use commutative matchers (m_c_*) for some, but not all, matches

llvm/test/Transforms/InstCombine/or.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -817,11 +817,9 @@ define <2 x i1> @test46_undef(<2 x i8> %c) {
817817
; represented with an add.
818818
define i1 @two_ranges_to_mask_and_range_degenerate(i16 %x) {
819819
; CHECK-LABEL: @two_ranges_to_mask_and_range_degenerate(
820-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i16 [[X:%.*]], 12
821-
; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[X]], -16
820+
; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[X:%.*]], -20
822821
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i16 [[TMP1]], 12
823-
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP1]], [[TMP2]]
824-
; CHECK-NEXT: ret i1 [[OR]]
822+
; CHECK-NEXT: ret i1 [[TMP2]]
825823
;
826824
%cmp1 = icmp ult i16 %x, 12
827825
%cmp2 = icmp uge i16 %x, 16

0 commit comments

Comments
 (0)