diff options
-rw-r--r-- | llvm/include/llvm/IR/ConstantRange.h | 8 | ||||
-rw-r--r-- | llvm/lib/IR/ConstantRange.cpp | 30 | ||||
-rw-r--r-- | llvm/unittests/IR/ConstantRangeTest.cpp | 28 |
3 files changed, 66 insertions, 0 deletions
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index c057ce8bf7b..ec73b514ba7 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -351,6 +351,14 @@ public: ConstantRange sub(const ConstantRange &Other) const; /// Return a new range representing the possible values resulting + /// from an subtraction with wrap type \p NoWrapKind of a value in this + /// range and a value in \p Other. + /// If the result range is disjoint, the preferred range is determined by the + /// \p PreferredRangeType. + ConstantRange subWithNoWrap(const ConstantRange &Other, unsigned NoWrapKind, + PreferredRangeType RangeType = Smallest) const; + + /// Return a new range representing the possible values resulting /// from a multiplication of a value in this range and a value in \p Other, /// treating both this and \p Other as unsigned ranges. ConstantRange multiply(const ConstantRange &Other) const; diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index cc1d86ba1b1..4914c50c203 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -898,6 +898,36 @@ ConstantRange::sub(const ConstantRange &Other) const { return X; } +ConstantRange ConstantRange::subWithNoWrap(const ConstantRange &Other, + unsigned NoWrapKind, + PreferredRangeType RangeType) const { + // Calculate the range for "X - Y" which is guaranteed not to wrap(overflow). + // (X is from this, and Y is from Other) + if (isEmptySet() || Other.isEmptySet()) + return getEmpty(); + if (isFullSet() && Other.isFullSet()) + return getFull(); + + using OBO = OverflowingBinaryOperator; + ConstantRange Result = sub(Other); + + // If an overflow happens for every value pair in these two constant ranges, + // we must return Empty set. In signed case, we get that for free, because we + // get lucky that intersection of add() with ssub_sat() results in an + // empty set. But for unsigned we must perform the overflow check manually. + + if (NoWrapKind & OBO::NoSignedWrap) + Result = Result.intersectWith(ssub_sat(Other), RangeType); + + if (NoWrapKind & OBO::NoUnsignedWrap) { + if (getUnsignedMax().ult(Other.getUnsignedMin())) + return getEmpty(); // Always overflows. + Result = Result.intersectWith(usub_sat(Other), RangeType); + } + + return Result; +} + ConstantRange ConstantRange::multiply(const ConstantRange &Other) const { // TODO: If either operand is a single element and the multiply is known to diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index eb79711250c..4bc620f3ce8 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -934,6 +934,34 @@ TEST_F(ConstantRangeTest, Sub) { ConstantRange(APInt(16, 0x6))); } +TEST_F(ConstantRangeTest, SubWithNoWrap) { + typedef OverflowingBinaryOperator OBO; + TestAddWithNoSignedWrapExhaustive( + [](const ConstantRange &CR1, const ConstantRange &CR2) { + return CR1.subWithNoWrap(CR2, OBO::NoSignedWrap); + }, + [](bool &IsOverflow, const APInt &N1, const APInt &N2) { + return N1.ssub_ov(N2, IsOverflow); + }); + TestAddWithNoUnsignedWrapExhaustive( + [](const ConstantRange &CR1, const ConstantRange &CR2) { + return CR1.subWithNoWrap(CR2, OBO::NoUnsignedWrap); + }, + [](bool &IsOverflow, const APInt &N1, const APInt &N2) { + return N1.usub_ov(N2, IsOverflow); + }); + TestAddWithNoSignedUnsignedWrapExhaustive( + [](const ConstantRange &CR1, const ConstantRange &CR2) { + return CR1.subWithNoWrap(CR2, OBO::NoUnsignedWrap | OBO::NoSignedWrap); + }, + [](bool &IsOverflow, const APInt &N1, const APInt &N2) { + return N1.ssub_ov(N2, IsOverflow); + }, + [](bool &IsOverflow, const APInt &N1, const APInt &N2) { + return N1.usub_ov(N2, IsOverflow); + }); +} + TEST_F(ConstantRangeTest, Multiply) { EXPECT_EQ(Full.multiply(Full), Full); EXPECT_EQ(Full.multiply(Empty), Empty); |