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 @@ -4878,17 +4878,29 @@ // canoncalize: // (icmp eq/ne (and X, C), X) // -> (icmp eq/ne (and X, ~C), 0) - { + // (icmp eq/ne (or X, C), X) + // -> (icmp eq/ne (and X, C), C) + auto SimplifyBitwiseAndOrBitwiseOr = + [this, Pred](Value *BitwiseOp, Value *Operand) -> Instruction * { Constant *CMask; - A = nullptr; - if (match(Op0, m_OneUse(m_And(m_Specific(Op1), m_ImmConstant(CMask))))) - A = Op1; - else if (match(Op1, m_OneUse(m_And(m_Specific(Op0), m_ImmConstant(CMask))))) - A = Op0; - if (A) - return new ICmpInst(Pred, Builder.CreateAnd(A, Builder.CreateNot(CMask)), - Constant::getNullValue(A->getType())); - } + if (!BitwiseOp->hasOneUse()) + return nullptr; + + if (match(BitwiseOp, m_And(m_Specific(Operand), m_ImmConstant(CMask))) && + !CMask->containsUndefElement()) + return new ICmpInst(Pred, + Builder.CreateAnd(Operand, Builder.CreateNot(CMask)), + Constant::getNullValue(Operand->getType())); + if (match(BitwiseOp, m_Or(m_Specific(Operand), m_ImmConstant(CMask))) && + !CMask->containsUndefElement()) + return new ICmpInst(Pred, Builder.CreateAnd(Operand, CMask), CMask); + return nullptr; + }; + + if (Instruction *R = SimplifyBitwiseAndOrBitwiseOr(Op0, Op1)) + return R; + if (Instruction *R = SimplifyBitwiseAndOrBitwiseOr(Op1, Op0)) + return R; if (match(Op1, m_Xor(m_Value(A), m_Value(B))) && (A == Op0 || B == Op0)) { // A == (A^B) -> B == 0 diff --git a/llvm/test/Transforms/InstCombine/icmp-or-x-with-x.ll b/llvm/test/Transforms/InstCombine/icmp-or-x-with-x.ll --- a/llvm/test/Transforms/InstCombine/icmp-or-x-with-x.ll +++ b/llvm/test/Transforms/InstCombine/icmp-or-x-with-x.ll @@ -5,8 +5,8 @@ define i1 @fold_or_eq(i8 %x) { ; CHECK-LABEL: define i1 @fold_or_eq ; CHECK-SAME: (i8 [[X:%.*]]) { -; CHECK-NEXT: [[XO:%.*]] = or i8 [[X]], 123 -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XO]], [[X]] +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], 123 +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], 123 ; CHECK-NEXT: ret i1 [[R]] ; %xo = or i8 %x, 123 @@ -18,8 +18,8 @@ ; CHECK-LABEL: define <2 x i1> @fold_or_ne ; CHECK-SAME: (<2 x i8> [[XX:%.*]]) { ; CHECK-NEXT: [[X:%.*]] = mul <2 x i8> [[XX]], [[XX]] -; CHECK-NEXT: [[XO:%.*]] = or <2 x i8> [[X]], -; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[X]], [[XO]] +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %x = mul <2 x i8> %xx, %xx @@ -98,8 +98,8 @@ define <2 x i1> @fold_or_eq_with_poison(<2 x i8> %x) { ; CHECK-LABEL: define <2 x i1> @fold_or_eq_with_poison ; CHECK-SAME: (<2 x i8> [[X:%.*]]) { -; CHECK-NEXT: [[XO:%.*]] = or <2 x i8> [[X]], -; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[XO]], [[X]] +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %xo = or <2 x i8> %x,