Index: llvm/include/llvm/IR/ConstantRange.h =================================================================== --- llvm/include/llvm/IR/ConstantRange.h +++ llvm/include/llvm/IR/ConstantRange.h @@ -144,6 +144,15 @@ const ConstantRange &Other, unsigned NoWrapKind); + /// Produce the smallest range such that for all Y in Other and all X *not* + /// in the result, "X BinOp Y" wraps. This can be seen as the inverse of a + /// "guaranteed always wrap region". The AllowedNoWrapRegion can be used to + /// restrict the range of the LHS operand, as any value outside of it must + /// wrap regardless of the RHS value. + static ConstantRange makeAllowedNoWrapRegion(Instruction::BinaryOps BinOp, + const ConstantRange &Other, + unsigned NoWrapKind); + /// Produce the range that contains X if and only if "X BinOp Other" does /// not wrap. static ConstantRange makeExactNoWrapRegion(Instruction::BinaryOps BinOp, Index: llvm/lib/IR/ConstantRange.cpp =================================================================== --- llvm/lib/IR/ConstantRange.cpp +++ llvm/lib/IR/ConstantRange.cpp @@ -273,6 +273,65 @@ } } +ConstantRange +ConstantRange::makeAllowedNoWrapRegion(Instruction::BinaryOps BinOp, + const ConstantRange &Other, + unsigned NoWrapKind) { + using OBO = OverflowingBinaryOperator; + assert((NoWrapKind == OBO::NoSignedWrap || + NoWrapKind == OBO::NoUnsignedWrap) && + "NoWrapKind invalid!"); + + bool Unsigned = NoWrapKind == OBO::NoUnsignedWrap; + unsigned BitWidth = Other.getBitWidth(); + + switch (BinOp) { + default: + llvm_unreachable("Unsupported binary op"); + + case Instruction::Add: { + if (Unsigned) + return getNonEmpty(APInt::getNullValue(BitWidth), + -Other.getUnsignedMin()); + + APInt SignedMinVal = APInt::getSignedMinValue(BitWidth); + APInt SMin = Other.getSignedMin(), SMax = Other.getSignedMax(); + return getNonEmpty( + SMax.isNegative() ? SignedMinVal - SMax : SignedMinVal, + SMin.isStrictlyPositive() ? SignedMinVal - SMin : SignedMinVal); + } + + case Instruction::Sub: { + if (Unsigned) + return getNonEmpty(Other.getUnsignedMin(), APInt::getMinValue(BitWidth)); + + APInt SignedMinVal = APInt::getSignedMinValue(BitWidth); + APInt SMin = Other.getSignedMin(), SMax = Other.getSignedMax(); + return getNonEmpty( + SMin.isStrictlyPositive() ? SignedMinVal + SMin : SignedMinVal, + SMax.isNegative() ? SignedMinVal + SMax : SignedMinVal); + } + + case Instruction::Mul: { + if (Unsigned) + return makeExactMulNUWRegion(Other.getUnsignedMin()); + + ConstantRange NonNegCR = Other.intersectWith( + ConstantRange(APInt(BitWidth, 0), + APInt::getSignedMinValue(BitWidth))); + ConstantRange NegCR = Other.intersectWith( + ConstantRange(APInt::getSignedMinValue(BitWidth), + APInt::getNullValue(BitWidth))); + ConstantRange Result(BitWidth, /* full */ false); + if (!NonNegCR.isEmptySet()) + Result = makeExactMulNSWRegion(NonNegCR.Lower); + if (!NegCR.isEmptySet()) + Result = Result.unionWith(makeExactMulNSWRegion(NegCR.Upper - 1)); + return Result; + } + } +} + ConstantRange ConstantRange::makeExactNoWrapRegion(Instruction::BinaryOps BinOp, const APInt &Other, unsigned NoWrapKind) { Index: llvm/unittests/IR/ConstantRangeTest.cpp =================================================================== --- llvm/unittests/IR/ConstantRangeTest.cpp +++ llvm/unittests/IR/ConstantRangeTest.cpp @@ -1256,8 +1256,10 @@ if (CR2.isEmptySet()) return; - ConstantRange NoWrap = + ConstantRange GuaranteedNoWrap = ConstantRange::makeGuaranteedNoWrapRegion(BinOp, CR2, NoWrapKind); + ConstantRange AllowedNoWrap = + ConstantRange::makeAllowedNoWrapRegion(BinOp, CR2, NoWrapKind); ForeachNumInConstantRange(CR1, [&](const APInt &N1) { bool NoOverflow = true; bool Overflow = true; @@ -1267,11 +1269,12 @@ else Overflow = false; }); - EXPECT_EQ(NoOverflow, NoWrap.contains(N1)); + EXPECT_EQ(NoOverflow, GuaranteedNoWrap.contains(N1)); + EXPECT_EQ(Overflow, !AllowedNoWrap.contains(N1)); // The no-wrap range is exact for single-element ranges. if (CR2.isSingleElement()) { - EXPECT_EQ(Overflow, !NoWrap.contains(N1)); + EXPECT_EQ(GuaranteedNoWrap, AllowedNoWrap); } }); });