summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/ConstantRange.h8
-rw-r--r--llvm/lib/IR/ConstantRange.cpp30
-rw-r--r--llvm/unittests/IR/ConstantRangeTest.cpp28
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);
OpenPOWER on IntegriCloud