Skip to content

Commit 77f75b4

Browse files
committed
[InstCombine] Extend (icmp eq/ne (and Z, X), (and Z, Y)) folds
Two ways to relaxed: 1) Only require one of the `and` ops to be single-use if both `X` and `Y` are constant. 2) Special case, if `X ^ Y` is a negative power of 2, then `Z ^ NegP2 ==/!= 0` will fold to `Z u</u>= -NegP2` which creates no additional instructions so fold irrelivant of use counts. Closes #94867
1 parent 4ac158e commit 77f75b4

File tree

2 files changed

+29
-15
lines changed

2 files changed

+29
-15
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

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

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

55565556
if (A == C) {
@@ -5571,10 +5571,26 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
55715571
Z = B;
55725572
}
55735573

5574-
if (X) { // Build (X^Y) & Z
5575-
Op1 = Builder.CreateXor(X, Y);
5576-
Op1 = Builder.CreateAnd(Op1, Z);
5577-
return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
5574+
if (X) {
5575+
// If X^Y is a negative power of two, then `icmp eq/ne (Z & NegP2), 0`
5576+
// will fold to `icmp ult/uge Z, -NegP2` incurringb no additional
5577+
// instructions.
5578+
const APInt *C0, *C1;
5579+
bool XorIsNegP2 = match(X, m_APInt(C0)) && match(Y, m_APInt(C1)) &&
5580+
(*C0 ^ *C1).isNegatedPowerOf2();
5581+
5582+
// If either Op0/Op1 are both one use or X^Y will constant fold and one of
5583+
// Op0/Op1 are one use, proceed. In those cases we are instruction neutral
5584+
// but `icmp eq/ne A, 0` is easier to analyze than `icmp eq/ne A, B`.
5585+
int UseCnt =
5586+
int(Op0->hasOneUse()) + int(Op1->hasOneUse()) +
5587+
(int(match(X, m_ImmConstant()) && match(Y, m_ImmConstant())));
5588+
if (XorIsNegP2 || UseCnt >= 2) {
5589+
// Build (X^Y) & Z
5590+
Op1 = Builder.CreateXor(X, Y);
5591+
Op1 = Builder.CreateAnd(Op1, Z);
5592+
return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
5593+
}
55785594
}
55795595
}
55805596

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

Lines changed: 7 additions & 9 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
@@ -117,7 +117,7 @@ define i1 @test_ne_cp2_other_okay_all_ones(i8 %x, i8 %yy) {
117117
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
118118
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
119119
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
120-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_NEG_Y]], [[AND_X_Y]]
120+
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0
121121
; CHECK-NEXT: ret i1 [[R]]
122122
;
123123
%and_x_neg_y = and i8 %x, -17
@@ -147,10 +147,9 @@ define i1 @test_ne_cp2_other_fail2(i8 %x, i8 %yy) {
147147

148148
define i1 @test_ne_cp2_other_okay(i8 %x, i8 %yy) {
149149
; CHECK-LABEL: @test_ne_cp2_other_okay(
150-
; CHECK-NEXT: [[AND_X_NEG_Y:%.*]] = and i8 [[X:%.*]], -17
151-
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
150+
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X:%.*]], 16
152151
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
153-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_NEG_Y]], [[AND_X_Y]]
152+
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0
154153
; CHECK-NEXT: ret i1 [[R]]
155154
;
156155
%and_x_neg_y = and i8 %x, -17
@@ -162,10 +161,9 @@ define i1 @test_ne_cp2_other_okay(i8 %x, i8 %yy) {
162161

163162
define i1 @test_ne_cp2_other_okay2(i8 %x, i8 %yy) {
164163
; CHECK-LABEL: @test_ne_cp2_other_okay2(
165-
; CHECK-NEXT: [[AND_X_NEG_Y:%.*]] = and i8 [[X:%.*]], -17
166-
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
164+
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X:%.*]], 16
167165
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
168-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_Y]], [[AND_X_NEG_Y]]
166+
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0
169167
; CHECK-NEXT: ret i1 [[R]]
170168
;
171169
%and_x_neg_y = and i8 %x, -17

0 commit comments

Comments
 (0)