diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -739,6 +739,38 @@ return Builder.CreateICmp(NewPred, Input, RangeEnd); } +// (or (icmp eq X, 0), (icmp eq X, Pow2OrZero)) +// -> (icmp eq (and X, Pow2OrZero), X) +// (and (icmp ne X, 0), (icmp ne X, Pow2OrZero)) +// -> (icmp ne (and X, Pow2OrZero), X) +static Value * +foldAndOrOfICmpsWithPow2AndWithZero(InstCombiner::BuilderTy &Builder, + ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, + const SimplifyQuery &Q) { + CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ; + // Make sure we have right compares for out op. + if (LHS->getPredicate() != Pred || RHS->getPredicate() != Pred) + return nullptr; + + // Make it so we can match LHS against the (icmp eq/ne X, 0) just for + // simplicity. + if (match(RHS->getOperand(1), m_Zero())) + std::swap(LHS, RHS); + + Value *Pow2, *Op; + // Match the desired pattern: + // LHS: (icmp eq/ne X, 0) + // RHS: (icmp eq/ne X, Pow2OrZero) + if (!match(LHS, m_ICmp(Pred, m_Value(Op), m_Zero())) || + !match(RHS, m_c_ICmp(Pred, m_Specific(Op), m_Value(Pow2))) || + !isKnownToBeAPowerOfTwo(Pow2, Q.DL, /*OrZero*/ true, /*Depth*/ 0, Q.AC, + Q.CxtI, Q.DT)) + return nullptr; + + Value *And = Builder.CreateAnd(Op, Pow2); + return Builder.CreateICmp(Pred, And, Op); +} + // Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2) // Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2) Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS, @@ -3048,6 +3080,11 @@ if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, &I, IsAnd, IsLogical)) return V; + if (!IsLogical) + if (Value *V = + foldAndOrOfICmpsWithPow2AndWithZero(Builder, LHS, RHS, IsAnd, Q)) + return V; + ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0); Value *LHS1 = LHS->getOperand(1), *RHS1 = RHS->getOperand(1); diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll --- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll +++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll @@ -3051,9 +3051,8 @@ ; CHECK-LABEL: @icmp_eq_or_z_or_pow2orz( ; CHECK-NEXT: [[NY:%.*]] = sub i8 0, [[Y:%.*]] ; CHECK-NEXT: [[POW2ORZ:%.*]] = and i8 [[NY]], [[Y]] -; CHECK-NEXT: [[C0:%.*]] = icmp eq i8 [[X:%.*]], 0 -; CHECK-NEXT: [[CP2:%.*]] = icmp eq i8 [[POW2ORZ]], [[X]] -; CHECK-NEXT: [[R:%.*]] = or i1 [[C0]], [[CP2]] +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[POW2ORZ]], [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], [[X]] ; CHECK-NEXT: ret i1 [[R]] ; %ny = sub i8 0, %y @@ -3089,9 +3088,8 @@ ; CHECK-LABEL: @icmp_ne_and_z_and_pow2orz( ; CHECK-NEXT: [[NY:%.*]] = sub <2 x i8> zeroinitializer, [[Y:%.*]] ; CHECK-NEXT: [[POW2ORZ:%.*]] = and <2 x i8> [[NY]], [[Y]] -; CHECK-NEXT: [[C0:%.*]] = icmp ne <2 x i8> [[X:%.*]], zeroinitializer -; CHECK-NEXT: [[CP2:%.*]] = icmp ne <2 x i8> [[POW2ORZ]], [[X]] -; CHECK-NEXT: [[R:%.*]] = and <2 x i1> [[C0]], [[CP2]] +; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[POW2ORZ]], [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[TMP1]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %ny = sub <2 x i8> zeroinitializer, %y