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,31 @@ return nullptr; } +static std::optional +getKnownSign(Value *Op, Instruction *CxtI, const DataLayout &DL, + AssumptionCache *AC, const DominatorTree *DT, KnownBits &Known) { + Known = computeKnownBits(Op, DL, 0, AC, CxtI, DT); + if (Known.isNonNegative()) + return false; + if (Known.isNegative()) + return true; + + Value *X, *Y; + if (match(Op, m_NSWSub(m_Value(X), m_Value(Y)))) + return isImpliedByDomCondition(ICmpInst::ICMP_SLT, X, Y, CxtI, DL); + + return isImpliedByDomCondition( + 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; @@ -4463,6 +4488,35 @@ IC.Builder.CreateOr(Op1, IC.Builder.CreateNot(A)), Constant::getAllOnesValue(Op1->getType())); } + + 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 (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLE) + return IC.replaceInstUsesWith( + I, ConstantInt::get(I.getType(), Pred == ICmpInst::ICMP_SLE)); + else if (Pred == ICmpInst::ICMP_SGE) + return new ICmpInst(ICmpInst::ICMP_SLT, Op1, + Constant::getNullValue(Op0->getType())); + else + return new ICmpInst(ICmpInst::ICMP_SGE, Op1, + 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 (Pred == ICmpInst::ICMP_SGT) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + else if (Pred == ICmpInst::ICMP_SLE) + 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 @@ -33,7 +33,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> [[XN1]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %x = add <2 x i8> %xx, %z @@ -48,7 +48,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 @@ -180,8 +180,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 @@ -191,10 +190,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, @@ -233,8 +229,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 @@ -272,8 +267,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