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 @@ -4102,6 +4102,14 @@ ICmpInst::ICMP_SLT, Op, Constant::getNullValue(Op->getType()), CxtI, DL); } +static std::optional getKnownSign(Value *Op, Instruction *CxtI, + const DataLayout &DL, + AssumptionCache *AC, + const DominatorTree *DT) { + KnownBits Known; + return getKnownSign(Op, CxtI, DL, AC, DT, Known); +} + static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q, InstCombinerImpl &IC) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A; @@ -4131,6 +4139,43 @@ /*Depth*/ 0)) return new ICmpInst(Pred, IC.Builder.CreateAnd(X, A), A); + if (ICmpInst::isEquality(Pred) || ICmpInst::getSignedPredicate(Pred) != Pred) + return nullptr; + + auto KnownSign = getKnownSign(A, &I, Q.DL, Q.AC, Q.DT); + if (KnownSign != std::nullopt) { + // icmp (X | MinInt) s> X --> false + // icmp (X | MinInt) s<= X --> true + // icmp (X | MinInt) s>= X --> X s< 0 + // icmp (X | MinInt) s< X --> X s>= 0 + if (*KnownSign /* true is Signed. */ && + IC.isKnownToBeAPowerOfTwo(A, /*OrZero*/ true, 0, &I)) { + if (Op0IsOr && (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE)) + return IC.replaceInstUsesWith( + I, ConstantInt::get(I.getType(), Pred == ICmpInst::ICMP_SLE)); + else if (!Op0IsOr && + (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SGE)) + return IC.replaceInstUsesWith( + I, ConstantInt::get(I.getType(), Pred == ICmpInst::ICMP_SGE)); + else if (Op0IsOr ? Pred == ICmpInst::ICMP_SGE + : Pred == ICmpInst::ICMP_SLE) + return new ICmpInst(ICmpInst::ICMP_SLT, X, + Constant::getNullValue(Op0->getType())); + else + return new ICmpInst(ICmpInst::ICMP_SGE, X, + Constant::getNullValue(Op0->getType())); + } + // icmp (X | Pos_Y) s> X --> (X | Pos_Y) != X + // icmp (X | Pos_Y) s<= X --> (X | Pos_Y) == X + else if (!*KnownSign) { + if (Op0IsOr ? Pred == ICmpInst::ICMP_SGT : Pred == ICmpInst::ICMP_SLT) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + else if (Op0IsOr ? Pred == ICmpInst::ICMP_SLE + : Pred == ICmpInst::ICMP_SGE) + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, Op1); + } + } + return nullptr; } 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 @@ -32,7 +32,7 @@ ; CHECK-NEXT: [[X:%.*]] = add <2 x i8> [[XX:%.*]], [[Z:%.*]] ; CHECK-NEXT: [[Y:%.*]] = and <2 x i8> [[YY:%.*]], ; CHECK-NEXT: [[XN1:%.*]] = or <2 x i8> [[X]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = icmp slt <2 x i8> [[X]], [[XN1]] +; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[X]], [[XN1]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %x = add <2 x i8> %xx, %z @@ -47,7 +47,7 @@ ; CHECK-NEXT: [[NS:%.*]] = icmp sgt i8 [[Y:%.*]], -1 ; CHECK-NEXT: call void @llvm.assume(i1 [[NS]]) ; CHECK-NEXT: [[XN1:%.*]] = or i8 [[X:%.*]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = icmp sle i8 [[XN1]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XN1]], [[X]] ; CHECK-NEXT: ret i1 [[R]] ; %ns = icmp sge i8 %y, 0 @@ -116,8 +116,7 @@ define i1 @or_slt_intmin(i8 %x) { ; CHECK-LABEL: @or_slt_intmin( -; CHECK-NEXT: [[XN1:%.*]] = or i8 [[X:%.*]], -128 -; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XN1]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[X:%.*]], -1 ; CHECK-NEXT: ret i1 [[R]] ; %xn1 = or i8 %x, 128 @@ -127,10 +126,7 @@ define <2 x i1> @or_slt_intmin_2(<2 x i8> %xx, <2 x i8> %z) { ; CHECK-LABEL: @or_slt_intmin_2( -; CHECK-NEXT: [[X:%.*]] = add <2 x i8> [[XX:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[XN1:%.*]] = or <2 x i8> [[X]], -; CHECK-NEXT: [[R:%.*]] = icmp slt <2 x i8> [[X]], [[XN1]] -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> zeroinitializer ; %x = add <2 x i8> %xx, %z %xn1 = or <2 x i8> %x, @@ -169,8 +165,7 @@ define i1 @or_sge_intmin(i8 %x) { ; CHECK-LABEL: @or_sge_intmin( -; CHECK-NEXT: [[XN1:%.*]] = or i8 [[X:%.*]], -128 -; CHECK-NEXT: [[R:%.*]] = icmp sge i8 [[XN1]], [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[X:%.*]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %xn1 = or i8 %x, 128 @@ -208,8 +203,7 @@ define <2 x i1> @or_sgt_intmin_2(<2 x i8> %xx, <2 x i8> %z) { ; CHECK-LABEL: @or_sgt_intmin_2( ; CHECK-NEXT: [[X:%.*]] = add <2 x i8> [[XX:%.*]], [[Z:%.*]] -; CHECK-NEXT: [[XN1:%.*]] = or <2 x i8> [[X]], -; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[X]], [[XN1]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[X]], ; CHECK-NEXT: ret <2 x i1> [[R]] ; %x = add <2 x i8> %xx, %z