Skip to content

Commit 24a5cb4

Browse files
committed
[InstCombine] Fold (x == A) || (x & -Pow2) == A + 1 into range check
Extends `foldAndOrOfICmpsUsingRanges` to recognize and fold idioms of the form `(x == A) || (x & -Pow2) == A + 1`, where A + 1 is aligned to the mask and A > |mask|. These patterns represent a special case of contiguous range checks and can be optimized into an addition and comparison. ```llvm define i1 @src(i32 %x) { %icmp1 = icmp eq i32 %x, 127 %and = and i32 %x, -32 %icmp2 = icmp eq i32 %and, 128 %ret = or i1 %icmp1, %icmp2 ret i1 %ret } define i1 @tgt(i32 %x) { %1 = add i32 %x, -127 %2 = icmp ult i32 %1, 33 ret i1 %2 } ``` Alive2 Proof: https://alive2.llvm.org/ce/z/gwELqs
1 parent af28ad0 commit 24a5cb4

File tree

2 files changed

+40
-20
lines changed

2 files changed

+40
-20
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,16 +1338,44 @@ Value *InstCombinerImpl::foldAndOrOfICmpsUsingRanges(ICmpInst *ICmp1,
13381338
V2 = X;
13391339
}
13401340

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+
const APInt *Mask1 = nullptr, *Mask2 = nullptr;
1346+
bool matchedAnd1 = false, matchedAnd2 = false;
1347+
if (V1 != V2) {
1348+
Value *X;
1349+
if (match(V1, m_OneUse(m_And(m_Value(X), m_NegatedPower2(Mask1)))) &&
1350+
*C1 - *C2 == 1 && C1->uge(Mask1->abs()) && C1->isPowerOf2() &&
1351+
Pred1 == ICmpInst::ICMP_EQ) {
1352+
matchedAnd1 = true;
1353+
V1 = X;
1354+
}
1355+
if (match(V2, m_OneUse(m_And(m_Value(X), m_NegatedPower2(Mask2)))) &&
1356+
*C2 - *C1 == 1 && C2->uge(Mask2->abs()) && C2->isPowerOf2() &&
1357+
Pred2 == ICmpInst::ICMP_EQ) {
1358+
matchedAnd2 = true;
1359+
V2 = X;
1360+
}
1361+
}
1362+
13411363
if (V1 != V2)
13421364
return nullptr;
13431365

1344-
ConstantRange CR1 = ConstantRange::makeExactICmpRegion(
1345-
IsAnd ? ICmpInst::getInverseCmpPredicate(Pred1) : Pred1, *C1);
1366+
ConstantRange CR1 =
1367+
matchedAnd1
1368+
? ConstantRange(*C1, *C1 - *Mask1)
1369+
: ConstantRange::makeExactICmpRegion(
1370+
IsAnd ? ICmpInst::getInverseCmpPredicate(Pred1) : Pred1, *C1);
13461371
if (Offset1)
13471372
CR1 = CR1.subtract(*Offset1);
13481373

1349-
ConstantRange CR2 = ConstantRange::makeExactICmpRegion(
1350-
IsAnd ? ICmpInst::getInverseCmpPredicate(Pred2) : Pred2, *C2);
1374+
ConstantRange CR2 =
1375+
matchedAnd2
1376+
? ConstantRange(*C2, *C2 - *Mask2)
1377+
: ConstantRange::makeExactICmpRegion(
1378+
IsAnd ? ICmpInst::getInverseCmpPredicate(Pred2) : Pred2, *C2);
13511379
if (Offset2)
13521380
CR2 = CR2.subtract(*Offset2);
13531381

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

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3494,10 +3494,8 @@ define i1 @and_icmp_eq_with_binary_range_operands(i8 range(i8 0, 2) %x, i8 range
34943494

34953495
define i1 @or_icmp_eq_and_pow2_1(i32 %x) {
34963496
; CHECK-LABEL: @or_icmp_eq_and_pow2_1(
3497-
; CHECK-NEXT: [[ICMP1:%.*]] = icmp eq i32 [[X:%.*]], 127
3498-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], -32
3499-
; CHECK-NEXT: [[ICMP2:%.*]] = icmp eq i32 [[AND]], 128
3500-
; CHECK-NEXT: [[TMP4:%.*]] = or i1 [[ICMP1]], [[ICMP2]]
3497+
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -127
3498+
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP1]], 33
35013499
; CHECK-NEXT: ret i1 [[TMP4]]
35023500
;
35033501
%icmp1 = icmp eq i32 %x, 127
@@ -3509,10 +3507,8 @@ define i1 @or_icmp_eq_and_pow2_1(i32 %x) {
35093507

35103508
define i1 @or_icmp_eq_and_pow2_2(i32 %x) {
35113509
; CHECK-LABEL: @or_icmp_eq_and_pow2_2(
3512-
; CHECK-NEXT: [[ICMP1:%.*]] = icmp eq i32 [[X:%.*]], 31
3513-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], -32
3514-
; CHECK-NEXT: [[ICMP2:%.*]] = icmp eq i32 [[AND]], 32
3515-
; CHECK-NEXT: [[TMP4:%.*]] = or i1 [[ICMP1]], [[ICMP2]]
3510+
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -31
3511+
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP1]], 33
35163512
; CHECK-NEXT: ret i1 [[TMP4]]
35173513
;
35183514
%icmp1 = icmp eq i32 %x, 31
@@ -3524,10 +3520,8 @@ define i1 @or_icmp_eq_and_pow2_2(i32 %x) {
35243520

35253521
define i1 @or_icmp_eq_and_pow2_3(i32 %x) {
35263522
; CHECK-LABEL: @or_icmp_eq_and_pow2_3(
3527-
; CHECK-NEXT: [[ICMP1:%.*]] = icmp eq i32 [[X:%.*]], 127
3528-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], -64
3529-
; CHECK-NEXT: [[ICMP2:%.*]] = icmp eq i32 [[AND]], 128
3530-
; CHECK-NEXT: [[TMP4:%.*]] = or i1 [[ICMP1]], [[ICMP2]]
3523+
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -127
3524+
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP1]], 65
35313525
; CHECK-NEXT: ret i1 [[TMP4]]
35323526
;
35333527
%icmp1 = icmp eq i32 %x, 127
@@ -3539,10 +3533,8 @@ define i1 @or_icmp_eq_and_pow2_3(i32 %x) {
35393533

35403534
define i1 @or_icmp_eq_and_pow2_commute(i32 %x) {
35413535
; CHECK-LABEL: @or_icmp_eq_and_pow2_commute(
3542-
; CHECK-NEXT: [[ICMP1:%.*]] = and i32 [[X:%.*]], -32
3543-
; CHECK-NEXT: [[AND:%.*]] = icmp eq i32 [[ICMP1]], 128
3544-
; CHECK-NEXT: [[ICMP2:%.*]] = icmp eq i32 [[X]], 127
3545-
; CHECK-NEXT: [[TMP4:%.*]] = or i1 [[AND]], [[ICMP2]]
3536+
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -127
3537+
; CHECK-NEXT: [[TMP4:%.*]] = icmp ult i32 [[TMP1]], 33
35463538
; CHECK-NEXT: ret i1 [[TMP4]]
35473539
;
35483540
%icmp1 = and i32 %x, -32

0 commit comments

Comments
 (0)