Skip to content

Commit 3cf54c5

Browse files
committed
[InstCombine] Add transforms for (icmp upred (or X, Y), X)
We can simplify ule/ugt -> eq/ne and we can remove the `Or` in some cases of eq/ne. `icmp (X | Y) u<= X` --> `(X | Y) == X` - https://alive2.llvm.org/ce/z/qnbbPv `icmp (X | Y) u> X` --> `(X | Y) != X` - https://alive2.llvm.org/ce/z/fvLqg3 `icmp (X | Y) eq/ne X` - --> `(~X & Y) eq/ne 0` iff X is freely invertible - --> `(X & ~Y) eq/ne -1` iff Y is freely invertible - https://alive2.llvm.org/ce/z/cpPV_W Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D144610
1 parent bce55fb commit 3cf54c5

File tree

2 files changed

+48
-16
lines changed

2 files changed

+48
-16
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4430,6 +4430,42 @@ static Instruction *foldICmpXNegX(ICmpInst &I,
44304430
return nullptr;
44314431
}
44324432

4433+
static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q,
4434+
InstCombinerImpl &IC) {
4435+
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A;
4436+
4437+
// Normalize or operand as operand 0.
4438+
CmpInst::Predicate Pred = I.getPredicate();
4439+
if (match(Op1, m_c_Or(m_Specific(Op0), m_Value(A)))) {
4440+
std::swap(Op0, Op1);
4441+
Pred = ICmpInst::getSwappedPredicate(Pred);
4442+
} else if (!match(Op0, m_c_Or(m_Specific(Op1), m_Value(A)))) {
4443+
return nullptr;
4444+
}
4445+
4446+
// icmp (X | Y) u<= X --> (X | Y) == X
4447+
if (Pred == ICmpInst::ICMP_ULE)
4448+
return new ICmpInst(ICmpInst::ICMP_EQ, Op0, Op1);
4449+
4450+
// icmp (X | Y) u> X --> (X | Y) != X
4451+
if (Pred == ICmpInst::ICMP_UGT)
4452+
return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1);
4453+
4454+
if (ICmpInst::isEquality(Pred) && Op0->hasOneUse()) {
4455+
// icmp (X | Y) eq/ne Y --> (X & ~Y) eq/ne 0 if Y is freely invertible
4456+
if (IC.isFreeToInvert(Op1, Op1->hasOneUse()))
4457+
return new ICmpInst(Pred,
4458+
IC.Builder.CreateAnd(A, IC.Builder.CreateNot(Op1)),
4459+
Constant::getNullValue(Op1->getType()));
4460+
// icmp (X | Y) eq/ne Y --> (~X | Y) eq/ne -1 if X is freely invertible.
4461+
if (IC.isFreeToInvert(A, A->hasOneUse()))
4462+
return new ICmpInst(Pred,
4463+
IC.Builder.CreateOr(Op1, IC.Builder.CreateNot(A)),
4464+
Constant::getAllOnesValue(Op1->getType()));
4465+
}
4466+
return nullptr;
4467+
}
4468+
44334469
static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
44344470
InstCombinerImpl &IC) {
44354471
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A;
@@ -4752,6 +4788,8 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
47524788

47534789
if (Instruction * R = foldICmpXorXX(I, Q, *this))
47544790
return R;
4791+
if (Instruction *R = foldICmpOrXX(I, Q, *this))
4792+
return R;
47554793

47564794
{
47574795
// Try to remove shared multiplier from comparison:

llvm/test/Transforms/InstCombine/icmp-of-or-x.ll

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ declare void @use.i8(i8)
99
define i1 @or_ugt(i8 %x, i8 %y) {
1010
; CHECK-LABEL: @or_ugt(
1111
; CHECK-NEXT: [[XN1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
12-
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[XN1]], [[X]]
12+
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[XN1]], [[X]]
1313
; CHECK-NEXT: ret i1 [[R]]
1414
;
1515
%xn1 = or i8 %x, %y
@@ -20,7 +20,7 @@ define i1 @or_ugt(i8 %x, i8 %y) {
2020
define <2 x i1> @or_ule(<2 x i8> %x, <2 x i8> %y) {
2121
; CHECK-LABEL: @or_ule(
2222
; CHECK-NEXT: [[XN1:%.*]] = or <2 x i8> [[X:%.*]], [[Y:%.*]]
23-
; CHECK-NEXT: [[R:%.*]] = icmp ule <2 x i8> [[XN1]], [[X]]
23+
; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[XN1]], [[X]]
2424
; CHECK-NEXT: ret <2 x i1> [[R]]
2525
;
2626
%xn1 = or <2 x i8> %x, %y
@@ -82,9 +82,8 @@ define i1 @or_eq_noundef(i8 %x, i8 noundef %y) {
8282

8383
define i1 @or_eq_notY_eq_0(i8 %x, i8 %y) {
8484
; CHECK-LABEL: @or_eq_notY_eq_0(
85-
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1
86-
; CHECK-NEXT: [[OR:%.*]] = or i8 [[NY]], [[X:%.*]]
87-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], [[NY]]
85+
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], [[Y:%.*]]
86+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
8887
; CHECK-NEXT: ret i1 [[CMP]]
8988
;
9089
%ny = xor i8 %y, -1
@@ -110,9 +109,8 @@ define i1 @or_eq_notY_eq_0_fail_multiuse(i8 %x, i8 %y) {
110109

111110
define i1 @or_ne_notY_eq_1s(i8 %x, i8 %y) {
112111
; CHECK-LABEL: @or_ne_notY_eq_1s(
113-
; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1
114-
; CHECK-NEXT: [[OR:%.*]] = or i8 [[NY]], [[X:%.*]]
115-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[OR]], [[X]]
112+
; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
113+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[TMP1]], -1
116114
; CHECK-NEXT: ret i1 [[CMP]]
117115
;
118116
%ny = xor i8 %y, -1
@@ -136,8 +134,8 @@ define i1 @or_ne_notY_eq_1s_fail_bad_not(i8 %x, i8 %y) {
136134

137135
define <2 x i1> @or_ne_vecC(<2 x i8> %x) {
138136
; CHECK-LABEL: @or_ne_vecC(
139-
; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[X:%.*]], <i8 9, i8 42>
140-
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], <i8 9, i8 42>
137+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -10, i8 -43>
138+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer
141139
; CHECK-NEXT: ret <2 x i1> [[CMP]]
142140
;
143141
%or = or <2 x i8> %x, <i8 9, i8 42>
@@ -359,7 +357,7 @@ define i1 @or_simplify_ugt_fail(i8 %y_in, i8 %rhs_in) {
359357
; CHECK-LABEL: @or_simplify_ugt_fail(
360358
; CHECK-NEXT: [[RHS:%.*]] = or i8 [[RHS_IN:%.*]], 1
361359
; CHECK-NEXT: [[LBO:%.*]] = or i8 [[RHS]], [[Y_IN:%.*]]
362-
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[LBO]], [[RHS]]
360+
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[LBO]], [[RHS]]
363361
; CHECK-NEXT: ret i1 [[R]]
364362
;
365363
%y = and i8 %y_in, -2
@@ -371,11 +369,7 @@ define i1 @or_simplify_ugt_fail(i8 %y_in, i8 %rhs_in) {
371369

372370
define i1 @pr64610(ptr %b) {
373371
; CHECK-LABEL: @pr64610(
374-
; CHECK-NEXT: [[V:%.*]] = load i1, ptr [[B:%.*]], align 2
375-
; CHECK-NEXT: [[S:%.*]] = select i1 [[V]], i32 74, i32 0
376-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[S]], 1
377-
; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[OR]], [[S]]
378-
; CHECK-NEXT: ret i1 [[R]]
372+
; CHECK-NEXT: ret i1 true
379373
;
380374
%v = load i1, ptr %b, align 2
381375
%s = select i1 %v, i32 74, i32 0

0 commit comments

Comments
 (0)