diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2703,9 +2703,17 @@ if (!OpTy->isIntOrIntVectorTy(1)) return nullptr; - // A boolean compared to true/false can be simplified in 14 out of the 20 - // (10 predicates * 2 constants) possible combinations. Cases not handled here - // require a 'not' of the LHS, so those must be transformed in InstCombine. + // A boolean compared to true/false can be reduced in 14 out of the 20 + // (10 predicates * 2 constants) possible combinations. The other + // 6 cases require a 'not' of the LHS. + + auto ExtractNotLHS = [](Value *V) -> Value * { + Value *X; + if (match(V, m_Not(m_Value(X)))) + return X; + return nullptr; + }; + if (match(RHS, m_Zero())) { switch (Pred) { case CmpInst::ICMP_NE: // X != 0 -> X @@ -2713,6 +2721,13 @@ case CmpInst::ICMP_SLT: // X X return LHS; + case CmpInst::ICMP_EQ: // not(X) == 0 -> X != 0 -> X + case CmpInst::ICMP_ULE: // not(X) <=u 0 -> X >u 0 -> X + case CmpInst::ICMP_SGE: // not(X) >=s 0 -> X X + if (Value *X = ExtractNotLHS(LHS)) + return X; + break; + case CmpInst::ICMP_ULT: // X false case CmpInst::ICMP_SGT: // X >s 0 -> false return getFalse(ITy); @@ -2730,6 +2745,13 @@ case CmpInst::ICMP_SLE: // X <=s -1 -> X return LHS; + case CmpInst::ICMP_NE: // not(X) != 1 -> X == 1 -> X + case CmpInst::ICMP_ULT: // not(X) <=u 1 -> X >=u 1 -> X + case CmpInst::ICMP_SGT: // not(X) >s 1 -> X <=s -1 -> X + if (Value *X = ExtractNotLHS(LHS)) + return X; + break; + case CmpInst::ICMP_UGT: // X >u 1 -> false case CmpInst::ICMP_SLT: // X false return getFalse(ITy); diff --git a/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll b/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll --- a/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll +++ b/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll @@ -2,7 +2,7 @@ ; RUN: opt < %s -instsimplify -S | FileCheck %s ; Test all integer predicates with bool types and true/false constants, -; with not on LHS (icmp pred (xor X, true), true|false). +; with not on LHS (icmp pred not(X), true|false). ; Use vectors to provide test coverage that is not duplicated in other folds. define <2 x i1> @eq_t_not(<2 x i1> %a) { @@ -17,26 +17,58 @@ define <2 x i1> @eq_f_not(<2 x i1> %a) { ; CHECK-LABEL: @eq_f_not( -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], -; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i1> [[NOT]], zeroinitializer -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] ; %not = xor <2 x i1> %a, %r = icmp eq <2 x i1> %not, ret <2 x i1> %r } +define <2 x i1> @eq_f_not_swap(<2 x i1> %a) { +; CHECK-LABEL: @eq_f_not_swap( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> , %a + %r = icmp eq <2 x i1> %not, + ret <2 x i1> %r +} + +define <2 x i1> @eq_f_not_undef(<2 x i1> %a) { +; CHECK-LABEL: @eq_f_not_undef( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> %a, + %r = icmp eq <2 x i1> %not, + ret <2 x i1> %r +} + define <2 x i1> @ne_t_not(<2 x i1> %a) { ; CHECK-LABEL: @ne_t_not( -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], -; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i1> [[NOT]], -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] ; %not = xor <2 x i1> %a, %r = icmp ne <2 x i1> %not, ret <2 x i1> %r } +define <2 x i1> @ne_t_not_swap(<2 x i1> %a) { +; CHECK-LABEL: @ne_t_not_swap( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> , %a + %r = icmp ne <2 x i1> %not, + ret <2 x i1> %r +} + +define <2 x i1> @ne_t_not_undef(<2 x i1> %a) { +; CHECK-LABEL: @ne_t_not_undef( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> %a, + %r = icmp ne <2 x i1> %not, + ret <2 x i1> %r +} + define <2 x i1> @ne_f_not(<2 x i1> %a) { ; CHECK-LABEL: @ne_f_not( ; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], @@ -68,15 +100,31 @@ define <2 x i1> @ult_t_not(<2 x i1> %a) { ; CHECK-LABEL: @ult_t_not( -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], -; CHECK-NEXT: [[R:%.*]] = icmp ult <2 x i1> [[NOT]], -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] ; %not = xor <2 x i1> %a, %r = icmp ult <2 x i1> %not, ret <2 x i1> %r } +define <2 x i1> @ult_t_not_swap(<2 x i1> %a) { +; CHECK-LABEL: @ult_t_not_swap( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> , %a + %r = icmp ult <2 x i1> %not, + ret <2 x i1> %r +} + +define <2 x i1> @ult_t_not_undef(<2 x i1> %a) { +; CHECK-LABEL: @ult_t_not_undef( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> %a, + %r = icmp ult <2 x i1> %not, + ret <2 x i1> %r +} + define <2 x i1> @ult_f_not(<2 x i1> %a) { ; CHECK-LABEL: @ult_f_not( ; CHECK-NEXT: ret <2 x i1> zeroinitializer @@ -88,15 +136,31 @@ define <2 x i1> @sgt_t_not(<2 x i1> %a) { ; CHECK-LABEL: @sgt_t_not( -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], -; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i1> [[NOT]], -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] ; %not = xor <2 x i1> %a, %r = icmp sgt <2 x i1> %not, ret <2 x i1> %r } +define <2 x i1> @sgt_t_not_swap(<2 x i1> %a) { +; CHECK-LABEL: @sgt_t_not_swap( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> , %a + %r = icmp sgt <2 x i1> %not, + ret <2 x i1> %r +} + +define <2 x i1> @sgt_t_not_undef(<2 x i1> %a) { +; CHECK-LABEL: @sgt_t_not_undef( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> %a, + %r = icmp sgt <2 x i1> %not, + ret <2 x i1> %r +} + define <2 x i1> @sgt_f_not(<2 x i1> %a) { ; CHECK-LABEL: @sgt_f_not( ; CHECK-NEXT: ret <2 x i1> zeroinitializer @@ -155,15 +219,31 @@ define <2 x i1> @ule_f_not(<2 x i1> %a) { ; CHECK-LABEL: @ule_f_not( -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], -; CHECK-NEXT: [[R:%.*]] = icmp ule <2 x i1> [[NOT]], zeroinitializer -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] ; %not = xor <2 x i1> %a, %r = icmp ule <2 x i1> %not, ret <2 x i1> %r } +define <2 x i1> @ule_f_not_swap(<2 x i1> %a) { +; CHECK-LABEL: @ule_f_not_swap( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> , %a + %r = icmp ule <2 x i1> %not, + ret <2 x i1> %r +} + +define <2 x i1> @ule_f_not_undef(<2 x i1> %a) { +; CHECK-LABEL: @ule_f_not_undef( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> %a, + %r = icmp ule <2 x i1> %not, + ret <2 x i1> %r +} + define <2 x i1> @sge_t_not(<2 x i1> %a) { ; CHECK-LABEL: @sge_t_not( ; CHECK-NEXT: ret <2 x i1> @@ -175,15 +255,31 @@ define <2 x i1> @sge_f_not(<2 x i1> %a) { ; CHECK-LABEL: @sge_f_not( -; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], -; CHECK-NEXT: [[R:%.*]] = icmp sge <2 x i1> [[NOT]], zeroinitializer -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] ; %not = xor <2 x i1> %a, %r = icmp sge <2 x i1> %not, ret <2 x i1> %r } +define <2 x i1> @sge_f_not_swap(<2 x i1> %a) { +; CHECK-LABEL: @sge_f_not_swap( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> , %a + %r = icmp sge <2 x i1> %not, + ret <2 x i1> %r +} + +define <2 x i1> @sge_f_not_undef(<2 x i1> %a) { +; CHECK-LABEL: @sge_f_not_undef( +; CHECK-NEXT: ret <2 x i1> [[A:%.*]] +; + %not = xor <2 x i1> %a, + %r = icmp sge <2 x i1> %not, + ret <2 x i1> %r +} + define <2 x i1> @sle_t_not(<2 x i1> %a) { ; CHECK-LABEL: @sle_t_not( ; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i1> [[A:%.*]],