Skip to content

Commit 970c0d6

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. If `P2` is not constant, then we only perform the fold if the `and` ops are multi-use. This, however, saves an instruction compared to the `xor` + `and` variant. NB: This came up in some of the diffs resulting from #94648 Proofs: https://alive2.llvm.org/ce/z/mfd3G9
1 parent d8d186e commit 970c0d6

File tree

2 files changed

+38
-16
lines changed

2 files changed

+38
-16
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 32 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,36 @@ 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+
// nsw neg precludes INT_MIN
5592+
if (match(X, m_NSWNeg(m_Specific(Y))))
5593+
std::swap(X, Y);
5594+
if (match(Y, m_NSWNeg(m_Specific(X))) &&
5595+
isKnownToBeAPowerOfTwo(X, /*OrZero=*/false, 0, &I))
5596+
return new ICmpInst(P2Pred, Z, Builder.CreateAdd(X, X));
5597+
5598+
// Build (X^Y) & Z
5599+
Op1 = Builder.CreateXor(X, Y);
5600+
Op1 = Builder.CreateAnd(Op1, Z);
5601+
return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
5602+
}
55775603
}
55785604
}
55795605

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,8 @@ define <2 x i1> @test3vec(<2 x i64> %A) {
7979

8080
define i1 @test_eq_p2(i8 %x, i8 %yy) {
8181
; CHECK-LABEL: @test_eq_p2(
82-
; CHECK-NEXT: [[Y:%.*]] = shl nuw nsw i8 1, [[YY:%.*]]
83-
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i8 [[Y]], -1
84-
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[Y]], [[TMP1]]
85-
; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[TMP2]], [[X:%.*]]
82+
; CHECK-NEXT: [[TMP1:%.*]] = shl i8 2, [[YY:%.*]]
83+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[TMP1]], [[X:%.*]]
8684
; CHECK-NEXT: ret i1 [[R]]
8785
;
8886
%y = shl nsw i8 1, %yy
@@ -96,10 +94,8 @@ define i1 @test_eq_p2(i8 %x, i8 %yy) {
9694

9795
define i1 @test_eq_p2_2(i8 %x, i8 %yy) {
9896
; CHECK-LABEL: @test_eq_p2_2(
99-
; CHECK-NEXT: [[Y:%.*]] = shl nuw nsw i8 1, [[YY:%.*]]
100-
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i8 [[Y]], -1
101-
; CHECK-NEXT: [[TMP2:%.*]] = xor i8 [[Y]], [[TMP1]]
102-
; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[TMP2]], [[X:%.*]]
97+
; CHECK-NEXT: [[TMP1:%.*]] = shl i8 2, [[YY:%.*]]
98+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[TMP1]], [[X:%.*]]
10399
; CHECK-NEXT: ret i1 [[R]]
104100
;
105101
%y = shl nsw i8 1, %yy
@@ -171,7 +167,7 @@ define i1 @test_ne_cp2(i8 %x, i8 %yy) {
171167
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
172168
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
173169
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
174-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_NEG_Y]], [[AND_X_Y]]
170+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[X]], 31
175171
; CHECK-NEXT: ret i1 [[R]]
176172
;
177173
%and_x_neg_y = and i8 %x, -16
@@ -188,7 +184,7 @@ define i1 @test_ne_cp2_2(i8 %x, i8 %yy) {
188184
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 4
189185
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
190186
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
191-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_Y]], [[AND_X_NEG_Y]]
187+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[X]], 7
192188
; CHECK-NEXT: ret i1 [[R]]
193189
;
194190
%and_x_neg_y = and i8 %x, -4

0 commit comments

Comments
 (0)