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 @@ -2832,6 +2832,54 @@ return nullptr; } +// Simplify (icmp (sub nuw/nsw C2, Y), C) to true/false. +static Value *simplifyICmpWithNoWrapSub(CmpInst::Predicate Pred, + BinaryOperator *Sub, Value *RHS, + const InstrInfoQuery &IIQ) { + const APInt *C, *C2; + + if (Sub->getOpcode() != Instruction::Sub) + return nullptr; + if (!match(RHS, m_APInt(C))) + return nullptr; + if (!match(Sub->getOperand(0), m_APInt(C2))) + return nullptr; + + bool isNSW = IIQ.hasNoSignedWrap(Sub); + bool isNUW = IIQ.hasNoUnsignedWrap(Sub); + + if (!(CmpInst::isUnsigned(Pred) && isNUW) && + !(CmpInst::isSigned(Pred) && isNSW)) + return nullptr; + + Type *ITy = GetCompareTy(RHS); // The return type. + + ConstantRange RHS_CR = ConstantRange::makeExactICmpRegion(Pred, *C); + + if (RHS_CR.isEmptySet()) + return ConstantInt::getFalse(ITy); + if (RHS_CR.isFullSet()) + return ConstantInt::getTrue(ITy); + + unsigned noWrapKind; + if (isNSW) + noWrapKind = OverflowingBinaryOperator::NoSignedWrap; + else + noWrapKind = OverflowingBinaryOperator::NoUnsignedWrap; + + ConstantRange LHS_CR = ConstantRange(*C2).subWithNoWrap( + ConstantRange::getFull(C2->getBitWidth()), noWrapKind); + + if (!LHS_CR.isFullSet()) { + if (RHS_CR.contains(LHS_CR)) + return ConstantInt::getTrue(ITy); + if (RHS_CR.inverse().contains(LHS_CR)) + return ConstantInt::getFalse(ITy); + } + + return nullptr; +} + static Value *simplifyICmpWithConstant(CmpInst::Predicate Pred, Value *LHS, Value *RHS, const InstrInfoQuery &IIQ) { Type *ITy = GetCompareTy(RHS); // The return type. @@ -3015,6 +3063,9 @@ return getTrue(ITy); } + if (Value *V = simplifyICmpWithNoWrapSub(Pred, LBO, RHS, Q.IIQ)) + return V; + return nullptr; } diff --git a/llvm/test/Transforms/InstSimplify/icmp.ll b/llvm/test/Transforms/InstSimplify/icmp.ll --- a/llvm/test/Transforms/InstSimplify/icmp.ll +++ b/llvm/test/Transforms/InstSimplify/icmp.ll @@ -211,3 +211,21 @@ %sub2 = sub i32 42, %p2 br label %loop } + +define i1 @test_negative_combined_sub_signed_overflow(i8 %x) { +; CHECK-LABEL: @test_negative_combined_sub_signed_overflow( +; CHECK-NEXT: ret i1 false +; + %y = sub nsw i8 127, %x + %z = icmp slt i8 %y, -1 + ret i1 %z +} + +define i1 @test_negative_combined_sub_unsigned_overflow(i64 %x) { +; CHECK-LABEL: @test_negative_combined_sub_unsigned_overflow( +; CHECK-NEXT: ret i1 true +; + %y = sub nuw i64 10, %x + %z = icmp ult i64 %y, 11 + ret i1 %z +}