Skip to content

Commit a5424ec

Browse files
committed
[InstCombine] Add combines for (icmp eq/ne (and X, P2), (and X, -P2))
`(icmp eq/ne (and X, P2), (and X, -P2))` -> `(icmp ult/uge X, P2 * 2)` If `P2` is constant, we can perform this fold profitably even if the `and` ops are multi-use. NB: This came up in some of the diffs resulting from llvm#94648 Proofs: https://alive2.llvm.org/ce/z/mfd3G9
1 parent 8f1c940 commit a5424ec

File tree

2 files changed

+27
-8
lines changed

2 files changed

+27
-8
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5548,8 +5548,8 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
55485548
}
55495549

55505550
// (X&Z) == (Y&Z) -> (X^Y) & Z == 0
5551-
if (match(Op0, m_OneUse(m_And(m_Value(A), m_Value(B)))) &&
5552-
match(Op1, m_OneUse(m_And(m_Value(C), m_Value(D))))) {
5551+
if (match(Op0, m_And(m_Value(A), m_Value(B))) &&
5552+
match(Op1, m_And(m_Value(C), m_Value(D)))) {
55535553
Value *X = nullptr, *Y = nullptr, *Z = nullptr;
55545554

55555555
if (A == C) {
@@ -5570,10 +5570,29 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
55705570
Z = B;
55715571
}
55725572

5573-
if (X) { // Build (X^Y) & Z
5574-
Op1 = Builder.CreateXor(X, Y);
5575-
Op1 = Builder.CreateAnd(Op1, Z);
5576-
return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
5573+
if (X) {
5574+
// (X&P2) == (X&-P2)
5575+
// -> X u< P2*2
5576+
// (X&P2) != (X&-P2)
5577+
// -> X u>= P2*2
5578+
// iff P2 is not INT_MIN
5579+
const APInt *CP2;
5580+
ICmpInst::Predicate P2Pred =
5581+
Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
5582+
if (match(X, m_APInt(CP2)) && match(Y, m_SpecificInt(-*CP2)) &&
5583+
(CP2->isPowerOf2() || CP2->isNegatedPowerOf2()) &&
5584+
!CP2->isMinSignedValue()) {
5585+
APInt CMask = CP2->isPowerOf2() ? *CP2 : -*CP2;
5586+
return new ICmpInst(P2Pred, Z,
5587+
ConstantInt::get(Z->getType(), CMask + CMask));
5588+
}
5589+
5590+
if (Op0->hasOneUse() && Op1->hasOneUse()) {
5591+
// Build (X^Y) & Z
5592+
Op1 = Builder.CreateXor(X, Y);
5593+
Op1 = Builder.CreateAnd(Op1, Z);
5594+
return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
5595+
}
55775596
}
55785597
}
55795598

llvm/test/Transforms/InstCombine/and-compare.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ define i1 @test_ne_cp2(i8 %x, i8 %yy) {
8383
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
8484
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
8585
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
86-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_NEG_Y]], [[AND_X_Y]]
86+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[X]], 31
8787
; CHECK-NEXT: ret i1 [[R]]
8888
;
8989
%and_x_neg_y = and i8 %x, -16
@@ -100,7 +100,7 @@ define i1 @test_ne_cp2_2(i8 %x, i8 %yy) {
100100
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 4
101101
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
102102
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
103-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND_X_Y]], [[AND_X_NEG_Y]]
103+
; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[X]], 8
104104
; CHECK-NEXT: ret i1 [[R]]
105105
;
106106
%and_x_neg_y = and i8 %x, -4

0 commit comments

Comments
 (0)