/// 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;
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();
});
}
+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