diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4430,6 +4430,46 @@ return nullptr; } +static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q, + InstCombinerImpl &IC) { + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A; + + // Normalize or operand as operand 0. + CmpInst::Predicate Pred = I.getPredicate(); + if (match(Op1, m_c_Or(m_Specific(Op0), m_Value()))) { + std::swap(Op0, Op1); + Pred = ICmpInst::getSwappedPredicate(Pred); + } + + if (!match(Op0, m_c_Or(m_Specific(Op1), m_Value(A)))) + return nullptr; + + // icmp (X | Y) u<= X --> (X | Y) == X + if (Pred == ICmpInst::ICMP_ULE) + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, Op1); + + // icmp (X | Y) u> X --> (X | Y) != X + else if (Pred == ICmpInst::ICMP_UGT) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + + if (ICmpInst::isEquality(Pred) && Op0->hasOneUse()) { + auto IsFreelyInvertible = [](Value *V) { + return match(V, m_Not(m_Value())) || match(V, m_ImmConstant()); + }; + // icmp (X | Y) eq/ne Y --> (X & ~Y) eq/ne 0 if Y is freely invertible + if (IsFreelyInvertible(Op1)) + return new ICmpInst(Pred, + IC.Builder.CreateAnd(A, IC.Builder.CreateNot(Op1)), + Constant::getNullValue(Op1->getType())); + // icmp (X | Y) eq/ne Y --> (~X | Y) eq/ne -1 if X is freely invertible. + if (IsFreelyInvertible(A)) + return new ICmpInst(Pred, + IC.Builder.CreateOr(Op1, IC.Builder.CreateNot(A)), + Constant::getAllOnesValue(Op1->getType())); + } + return nullptr; +} + static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q, InstCombinerImpl &IC) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A; @@ -4752,6 +4792,8 @@ if (Instruction * R = foldICmpXorXX(I, Q, *this)) return R; + if (Instruction *R = foldICmpOrXX(I, Q, *this)) + return R; { // Try to remove shared multiplier from comparison: diff --git a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll --- a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll +++ b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll @@ -9,7 +9,7 @@ define i1 @or_ugt(i8 %x, i8 %y) { ; CHECK-LABEL: @or_ugt( ; CHECK-NEXT: [[XN1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[XN1]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[XN1]], [[X]] ; CHECK-NEXT: ret i1 [[R]] ; %xn1 = or i8 %x, %y @@ -20,7 +20,7 @@ define <2 x i1> @or_ule(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @or_ule( ; CHECK-NEXT: [[XN1:%.*]] = or <2 x i8> [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ule <2 x i8> [[XN1]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[XN1]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %xn1 = or <2 x i8> %x, %y @@ -82,9 +82,8 @@ define i1 @or_eq_notY_eq_0(i8 %x, i8 %y) { ; CHECK-LABEL: @or_eq_notY_eq_0( -; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i8 [[NY]], [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[OR]], [[NY]] +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %ny = xor i8 %y, -1 @@ -110,9 +109,8 @@ define i1 @or_ne_notY_eq_1s(i8 %x, i8 %y) { ; CHECK-LABEL: @or_ne_notY_eq_1s( -; CHECK-NEXT: [[NY:%.*]] = xor i8 [[Y:%.*]], -1 -; CHECK-NEXT: [[OR:%.*]] = or i8 [[NY]], [[X:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[OR]], [[X]] +; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[TMP1]], -1 ; CHECK-NEXT: ret i1 [[CMP]] ; %ny = xor i8 %y, -1 @@ -136,8 +134,8 @@ define <2 x i1> @or_ne_vecC(<2 x i8> %x) { ; CHECK-LABEL: @or_ne_vecC( -; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %or = or <2 x i8> %x, @@ -359,7 +357,7 @@ ; CHECK-LABEL: @or_simplify_ugt_fail( ; CHECK-NEXT: [[RHS:%.*]] = or i8 [[RHS_IN:%.*]], 1 ; CHECK-NEXT: [[LBO:%.*]] = or i8 [[RHS]], [[Y_IN:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[LBO]], [[RHS]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[LBO]], [[RHS]] ; CHECK-NEXT: ret i1 [[R]] ; %y = and i8 %y_in, -2 @@ -371,11 +369,7 @@ define i1 @pr64610(ptr %b) { ; CHECK-LABEL: @pr64610( -; CHECK-NEXT: [[V:%.*]] = load i1, ptr [[B:%.*]], align 2 -; CHECK-NEXT: [[S:%.*]] = select i1 [[V]], i32 74, i32 0 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[S]], 1 -; CHECK-NEXT: [[R:%.*]] = icmp ugt i32 [[OR]], [[S]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 true ; %v = load i1, ptr %b, align 2 %s = select i1 %v, i32 74, i32 0