Skip to content

Commit e03a7c1

Browse files
authored
[InstCombine] Generalize foldAndOrOfICmpsUsingRanges to handle more cases. (#158498)
Closes #158326. Closes #59555. Proof for `(X & -Pow2) == C -> (X - C) < Pow2`: https://alive2.llvm.org/ce/z/HMgkuu
1 parent c78239e commit e03a7c1

File tree

3 files changed

+83
-70
lines changed

3 files changed

+83
-70
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 40 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,71 +1320,52 @@ static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1,
13201320
Value *InstCombinerImpl::foldAndOrOfICmpsUsingRanges(ICmpInst *ICmp1,
13211321
ICmpInst *ICmp2,
13221322
bool IsAnd) {
1323-
CmpPredicate Pred1, Pred2;
1324-
Value *V1, *V2;
1325-
const APInt *C1, *C2;
1326-
if (!match(ICmp1, m_ICmp(Pred1, m_Value(V1), m_APInt(C1))) ||
1327-
!match(ICmp2, m_ICmp(Pred2, m_Value(V2), m_APInt(C2))))
1328-
return nullptr;
1329-
1330-
// Look through add of a constant offset on V1, V2, or both operands. This
1331-
// allows us to interpret the V + C' < C'' range idiom into a proper range.
1332-
const APInt *Offset1 = nullptr, *Offset2 = nullptr;
1333-
if (V1 != V2) {
1334-
Value *X;
1335-
if (match(V1, m_Add(m_Value(X), m_APInt(Offset1))))
1336-
V1 = X;
1337-
if (match(V2, m_Add(m_Value(X), m_APInt(Offset2))))
1338-
V2 = X;
1339-
}
1340-
1341-
// Look through and with a negative power of 2 mask on V1 or V2. This
1342-
// detects idioms of the form `(x == A) || ((x & Mask) == A + 1)` where A + 1
1343-
// is aligned to the mask and A + 1 >= |Mask|. This pattern corresponds to a
1344-
// contiguous range check, which can be folded into an addition and compare.
1345-
// The same applies for `(x != A) && ((x & Mask) != A + 1)`.
1346-
auto AreContiguousRangePredicates = [](CmpPredicate Pred1, CmpPredicate Pred2,
1347-
bool IsAnd) {
1348-
if (IsAnd)
1349-
return Pred1 == ICmpInst::ICMP_NE && Pred2 == ICmpInst::ICMP_NE;
1350-
return Pred1 == ICmpInst::ICMP_EQ && Pred2 == ICmpInst::ICMP_EQ;
1351-
};
1352-
const APInt *Mask1 = nullptr, *Mask2 = nullptr;
1353-
bool MatchedAnd1 = false, MatchedAnd2 = false;
1354-
if (V1 != V2 && AreContiguousRangePredicates(Pred1, Pred2, IsAnd)) {
1323+
// Return (V, CR) for a range check idiom V in CR.
1324+
auto MatchExactRangeCheck =
1325+
[](ICmpInst *ICmp) -> std::optional<std::pair<Value *, ConstantRange>> {
1326+
const APInt *C;
1327+
if (!match(ICmp->getOperand(1), m_APInt(C)))
1328+
return std::nullopt;
1329+
Value *LHS = ICmp->getOperand(0);
1330+
CmpPredicate Pred = ICmp->getPredicate();
13551331
Value *X;
1356-
if (match(V1, m_OneUse(m_And(m_Value(X), m_NegatedPower2(Mask1)))) &&
1357-
C1->getBitWidth() == C2->getBitWidth() && *C1 == *C2 + 1 &&
1358-
C1->uge(Mask1->abs()) && C1->isPowerOf2()) {
1359-
MatchedAnd1 = true;
1360-
V1 = X;
1332+
// Match (x & NegPow2) ==/!= C
1333+
const APInt *Mask;
1334+
if (ICmpInst::isEquality(Pred) &&
1335+
match(LHS, m_OneUse(m_And(m_Value(X), m_NegatedPower2(Mask)))) &&
1336+
C->countr_zero() >= Mask->countr_zero()) {
1337+
ConstantRange CR(*C, *C - *Mask);
1338+
if (Pred == ICmpInst::ICMP_NE)
1339+
CR = CR.inverse();
1340+
return std::make_pair(X, CR);
13611341
}
1362-
if (match(V2, m_OneUse(m_And(m_Value(X), m_NegatedPower2(Mask2)))) &&
1363-
C1->getBitWidth() == C2->getBitWidth() && *C2 == *C1 + 1 &&
1364-
C2->uge(Mask2->abs()) && C2->isPowerOf2()) {
1365-
MatchedAnd2 = true;
1366-
V2 = X;
1367-
}
1368-
}
1342+
ConstantRange CR = ConstantRange::makeExactICmpRegion(Pred, *C);
1343+
// Match (add X, C1) pred C
1344+
// TODO: investigate whether we should apply the one-use check on m_AddLike.
1345+
const APInt *C1;
1346+
if (match(LHS, m_AddLike(m_Value(X), m_APInt(C1))))
1347+
return std::make_pair(X, CR.subtract(*C1));
1348+
return std::make_pair(LHS, CR);
1349+
};
1350+
1351+
auto RC1 = MatchExactRangeCheck(ICmp1);
1352+
if (!RC1)
1353+
return nullptr;
1354+
1355+
auto RC2 = MatchExactRangeCheck(ICmp2);
1356+
if (!RC2)
1357+
return nullptr;
13691358

1359+
auto &[V1, CR1] = *RC1;
1360+
auto &[V2, CR2] = *RC2;
13701361
if (V1 != V2)
13711362
return nullptr;
13721363

1373-
ConstantRange CR1 =
1374-
MatchedAnd1
1375-
? ConstantRange(*C1, *C1 - *Mask1)
1376-
: ConstantRange::makeExactICmpRegion(
1377-
IsAnd ? ICmpInst::getInverseCmpPredicate(Pred1) : Pred1, *C1);
1378-
if (Offset1)
1379-
CR1 = CR1.subtract(*Offset1);
1380-
1381-
ConstantRange CR2 =
1382-
MatchedAnd2
1383-
? ConstantRange(*C2, *C2 - *Mask2)
1384-
: ConstantRange::makeExactICmpRegion(
1385-
IsAnd ? ICmpInst::getInverseCmpPredicate(Pred2) : Pred2, *C2);
1386-
if (Offset2)
1387-
CR2 = CR2.subtract(*Offset2);
1364+
// For 'and', we use the De Morgan's Laws to simplify the implementation.
1365+
if (IsAnd) {
1366+
CR1 = CR1.inverse();
1367+
CR2 = CR2.inverse();
1368+
}
13881369

13891370
Type *Ty = V1->getType();
13901371
Value *NewV = V1;

llvm/test/Transforms/InstCombine/and-or-icmps.ll

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3672,17 +3672,52 @@ define i1 @neg_or_icmp_eq_double_and_pow2(i32 %x) {
36723672
ret i1 %ret
36733673
}
36743674

3675-
define i1 @neg_select_icmp_eq_and_pow2(i32 %x) {
3676-
; CHECK-LABEL: @neg_select_icmp_eq_and_pow2(
3677-
; CHECK-NEXT: [[ICMP1:%.*]] = icmp sgt i32 [[X:%.*]], 127
3678-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], -32
3679-
; CHECK-NEXT: [[ICMP2:%.*]] = icmp eq i32 [[AND]], 128
3680-
; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[ICMP1]], [[ICMP2]]
3681-
; CHECK-NEXT: ret i1 [[TMP1]]
3675+
define i1 @implied_select_icmp_eq_and_pow2(i32 %x) {
3676+
; CHECK-LABEL: @implied_select_icmp_eq_and_pow2(
3677+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], -32
3678+
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 128
3679+
; CHECK-NEXT: ret i1 [[TMP2]]
36823680
;
36833681
%icmp1 = icmp sgt i32 %x, 127
36843682
%and = and i32 %x, -32
36853683
%icmp2 = icmp eq i32 %and, 128
36863684
%1 = select i1 %icmp1, i1 %icmp2, i1 false
36873685
ret i1 %1
36883686
}
3687+
3688+
define i1 @implied_range_check(i8 %a) {
3689+
; CHECK-LABEL: @implied_range_check(
3690+
; CHECK-NEXT: [[MASKED:%.*]] = and i8 [[A:%.*]], -2
3691+
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[MASKED]], 2
3692+
; CHECK-NEXT: ret i1 [[CMP2]]
3693+
;
3694+
%cmp1 = icmp ult i8 %a, 5
3695+
%masked = and i8 %a, -2
3696+
%cmp2 = icmp eq i8 %masked, 2
3697+
%and = and i1 %cmp1, %cmp2
3698+
ret i1 %and
3699+
}
3700+
3701+
define i1 @merge_range_check_and(i8 %a) {
3702+
; CHECK-LABEL: @merge_range_check_and(
3703+
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[MASKED:%.*]], 2
3704+
; CHECK-NEXT: ret i1 [[CMP2]]
3705+
;
3706+
%cmp1 = icmp ult i8 %a, 3
3707+
%masked = and i8 %a, -2
3708+
%cmp2 = icmp eq i8 %masked, 2
3709+
%and = and i1 %cmp1, %cmp2
3710+
ret i1 %and
3711+
}
3712+
3713+
define i1 @merge_range_check_or(i8 %a) {
3714+
; CHECK-LABEL: @merge_range_check_or(
3715+
; CHECK-NEXT: [[AND:%.*]] = icmp ult i8 [[A:%.*]], 4
3716+
; CHECK-NEXT: ret i1 [[AND]]
3717+
;
3718+
%cmp1 = icmp ult i8 %a, 3
3719+
%masked = and i8 %a, -2
3720+
%cmp2 = icmp eq i8 %masked, 2
3721+
%and = or i1 %cmp1, %cmp2
3722+
ret i1 %and
3723+
}

llvm/test/Transforms/InstCombine/icmp-range.ll

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,10 +1678,7 @@ define i1 @icmp_slt_sext_ne_otherwise_nofold(i32 %a) {
16781678
; tests from PR59555
16791679
define i1 @isFloat(i64 %0) {
16801680
; CHECK-LABEL: @isFloat(
1681-
; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i64 [[TMP0:%.*]], 281474976710655
1682-
; CHECK-NEXT: [[TMP3:%.*]] = and i64 [[TMP0]], -281474976710656
1683-
; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], 281474976710656
1684-
; CHECK-NEXT: [[TMP5:%.*]] = and i1 [[TMP2]], [[TMP4]]
1681+
; CHECK-NEXT: [[TMP5:%.*]] = icmp ugt i64 [[TMP0:%.*]], 562949953421311
16851682
; CHECK-NEXT: ret i1 [[TMP5]]
16861683
;
16871684
%2 = icmp ugt i64 %0, 281474976710655

0 commit comments

Comments
 (0)