diff options
| -rw-r--r-- | llvm/include/llvm/IR/ConstantRange.h | 12 | ||||
| -rw-r--r-- | llvm/lib/IR/ConstantRange.cpp | 36 | ||||
| -rw-r--r-- | llvm/unittests/IR/ConstantRangeTest.cpp | 94 | 
3 files changed, 142 insertions, 0 deletions
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index 6dbe4053994..f006a9321fc 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -377,6 +377,18 @@ public:    /// arithmetic right shift of a value in this range and a value in \p Other.    ConstantRange ashr(const ConstantRange &Other) const; +  /// Perform an unsigned saturating addition of two constant ranges. +  ConstantRange uadd_sat(const ConstantRange &Other) const; + +  /// Perform a signed saturating addition of two constant ranges. +  ConstantRange sadd_sat(const ConstantRange &Other) const; + +  /// Perform an unsigned saturating subtraction of two constant ranges. +  ConstantRange usub_sat(const ConstantRange &Other) const; + +  /// Perform a signed saturating subtraction of two constant ranges. +  ConstantRange ssub_sat(const ConstantRange &Other) const; +    /// Return a new range that is the logical not of the current set.    ConstantRange inverse() const; diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 7bd14e62dc1..b2bdd0abd9c 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -1099,6 +1099,42 @@ ConstantRange::ashr(const ConstantRange &Other) const {    return getNonEmpty(std::move(min), std::move(max));  } +ConstantRange ConstantRange::uadd_sat(const ConstantRange &Other) const { +  if (isEmptySet() || Other.isEmptySet()) +    return getEmpty(); + +  APInt NewL = getUnsignedMin().uadd_sat(Other.getUnsignedMin()); +  APInt NewU = getUnsignedMax().uadd_sat(Other.getUnsignedMax()) + 1; +  return getNonEmpty(std::move(NewL), std::move(NewU)); +} + +ConstantRange ConstantRange::sadd_sat(const ConstantRange &Other) const { +  if (isEmptySet() || Other.isEmptySet()) +    return getEmpty(); + +  APInt NewL = getSignedMin().sadd_sat(Other.getSignedMin()); +  APInt NewU = getSignedMax().sadd_sat(Other.getSignedMax()) + 1; +  return getNonEmpty(std::move(NewL), std::move(NewU)); +} + +ConstantRange ConstantRange::usub_sat(const ConstantRange &Other) const { +  if (isEmptySet() || Other.isEmptySet()) +    return getEmpty(); + +  APInt NewL = getUnsignedMin().usub_sat(Other.getUnsignedMax()); +  APInt NewU = getUnsignedMax().usub_sat(Other.getUnsignedMin()) + 1; +  return getNonEmpty(std::move(NewL), std::move(NewU)); +} + +ConstantRange ConstantRange::ssub_sat(const ConstantRange &Other) const { +  if (isEmptySet() || Other.isEmptySet()) +    return getEmpty(); + +  APInt NewL = getSignedMin().ssub_sat(Other.getSignedMax()); +  APInt NewU = getSignedMax().ssub_sat(Other.getSignedMin()) + 1; +  return getNonEmpty(std::move(NewL), std::move(NewU)); +} +  ConstantRange ConstantRange::inverse() const {    if (isFullSet())      return getEmpty(); diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index 060d69126e2..3306fe3ea69 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -1647,4 +1647,98 @@ TEST_F(ConstantRangeTest, Negative) {    });  } +template<typename Fn1, typename Fn2> +static void TestUnsignedBinOpExhaustive(Fn1 RangeFn, Fn2 IntFn) { +  unsigned Bits = 4; +  EnumerateTwoConstantRanges(Bits, [&](const ConstantRange &CR1, +                                       const ConstantRange &CR2) { +    ConstantRange CR = RangeFn(CR1, CR2); +    if (CR1.isEmptySet() || CR2.isEmptySet()) { +      EXPECT_TRUE(CR.isEmptySet()); +      return; +    } + +    APInt Min = APInt::getMaxValue(Bits); +    APInt Max = APInt::getMinValue(Bits); +    ForeachNumInConstantRange(CR1, [&](const APInt &N1) { +      ForeachNumInConstantRange(CR2, [&](const APInt &N2) { +        APInt N = IntFn(N1, N2); +        if (N.ult(Min)) +          Min = N; +        if (N.ugt(Max)) +          Max = N; +      }); +    }); + +    EXPECT_EQ(ConstantRange::getNonEmpty(Min, Max + 1), CR); +  }); +} + +template<typename Fn1, typename Fn2> +static void TestSignedBinOpExhaustive(Fn1 RangeFn, Fn2 IntFn) { +  unsigned Bits = 4; +  EnumerateTwoConstantRanges(Bits, [&](const ConstantRange &CR1, +                                       const ConstantRange &CR2) { +    ConstantRange CR = RangeFn(CR1, CR2); +    if (CR1.isEmptySet() || CR2.isEmptySet()) { +      EXPECT_TRUE(CR.isEmptySet()); +      return; +    } + +    APInt Min = APInt::getSignedMaxValue(Bits); +    APInt Max = APInt::getSignedMinValue(Bits); +    ForeachNumInConstantRange(CR1, [&](const APInt &N1) { +      ForeachNumInConstantRange(CR2, [&](const APInt &N2) { +        APInt N = IntFn(N1, N2); +        if (N.slt(Min)) +          Min = N; +        if (N.sgt(Max)) +          Max = N; +      }); +    }); + +    EXPECT_EQ(ConstantRange::getNonEmpty(Min, Max + 1), CR); +  }); +} + +TEST_F(ConstantRangeTest, UAddSat) { +  TestUnsignedBinOpExhaustive( +      [](const ConstantRange &CR1, const ConstantRange &CR2) { +        return CR1.uadd_sat(CR2); +      }, +      [](const APInt &N1, const APInt &N2) { +        return N1.uadd_sat(N2); +      }); +} + +TEST_F(ConstantRangeTest, USubSat) { +  TestUnsignedBinOpExhaustive( +      [](const ConstantRange &CR1, const ConstantRange &CR2) { +        return CR1.usub_sat(CR2); +      }, +      [](const APInt &N1, const APInt &N2) { +        return N1.usub_sat(N2); +      }); +} + +TEST_F(ConstantRangeTest, SAddSat) { +  TestSignedBinOpExhaustive( +      [](const ConstantRange &CR1, const ConstantRange &CR2) { +        return CR1.sadd_sat(CR2); +      }, +      [](const APInt &N1, const APInt &N2) { +        return N1.sadd_sat(N2); +      }); +} + +TEST_F(ConstantRangeTest, SSubSat) { +  TestSignedBinOpExhaustive( +      [](const ConstantRange &CR1, const ConstantRange &CR2) { +        return CR1.ssub_sat(CR2); +      }, +      [](const APInt &N1, const APInt &N2) { +        return N1.ssub_sat(N2); +      }); +} +  }  // anonymous namespace  | 

