Index: llvm/trunk/include/llvm/ADT/APInt.h =================================================================== --- llvm/trunk/include/llvm/ADT/APInt.h +++ llvm/trunk/include/llvm/ADT/APInt.h @@ -1105,6 +1105,12 @@ APInt sshl_ov(const APInt &Amt, bool &Overflow) const; APInt ushl_ov(const APInt &Amt, bool &Overflow) const; + // Operations that saturate + APInt sadd_sat(const APInt &RHS) const; + APInt uadd_sat(const APInt &RHS) const; + APInt ssub_sat(const APInt &RHS) const; + APInt usub_sat(const APInt &RHS) const; + /// Array-indexing support. /// /// \returns the bit value at bitPosition Index: llvm/trunk/lib/Support/APInt.cpp =================================================================== --- llvm/trunk/lib/Support/APInt.cpp +++ llvm/trunk/lib/Support/APInt.cpp @@ -1947,7 +1947,43 @@ return *this << ShAmt; } +APInt APInt::sadd_sat(const APInt &RHS) const { + bool Overflow; + APInt Res = sadd_ov(RHS, Overflow); + if (!Overflow) + return Res; + return isNegative() ? APInt::getSignedMinValue(BitWidth) + : APInt::getSignedMaxValue(BitWidth); +} + +APInt APInt::uadd_sat(const APInt &RHS) const { + bool Overflow; + APInt Res = uadd_ov(RHS, Overflow); + if (!Overflow) + return Res; + + return APInt::getMaxValue(BitWidth); +} + +APInt APInt::ssub_sat(const APInt &RHS) const { + bool Overflow; + APInt Res = ssub_ov(RHS, Overflow); + if (!Overflow) + return Res; + + return isNegative() ? APInt::getSignedMinValue(BitWidth) + : APInt::getSignedMaxValue(BitWidth); +} + +APInt APInt::usub_sat(const APInt &RHS) const { + bool Overflow; + APInt Res = usub_ov(RHS, Overflow); + if (!Overflow) + return Res; + + return APInt(BitWidth, 0); +} void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { Index: llvm/trunk/unittests/ADT/APIntTest.cpp =================================================================== --- llvm/trunk/unittests/ADT/APIntTest.cpp +++ llvm/trunk/unittests/ADT/APIntTest.cpp @@ -1176,6 +1176,30 @@ EXPECT_EQ(APInt(32, uint64_t(-72LL)), APInt(32, "-20", 36)); } +TEST(APIntTest, SaturatingMath) { + APInt AP_10 = APInt(8, 10); + APInt AP_100 = APInt(8, 100); + APInt AP_200 = APInt(8, 200); + + EXPECT_EQ(APInt(8, 200), AP_100.uadd_sat(AP_100)); + EXPECT_EQ(APInt(8, 255), AP_100.uadd_sat(AP_200)); + EXPECT_EQ(APInt(8, 255), APInt(8, 255).uadd_sat(APInt(8, 255))); + + EXPECT_EQ(APInt(8, 110), AP_10.sadd_sat(AP_100)); + EXPECT_EQ(APInt(8, 127), AP_100.sadd_sat(AP_100)); + EXPECT_EQ(APInt(8, -128), (-AP_100).sadd_sat(-AP_100)); + EXPECT_EQ(APInt(8, -128), APInt(8, -128).sadd_sat(APInt(8, -128))); + + EXPECT_EQ(APInt(8, 90), AP_100.usub_sat(AP_10)); + EXPECT_EQ(APInt(8, 0), AP_100.usub_sat(AP_200)); + EXPECT_EQ(APInt(8, 0), APInt(8, 0).usub_sat(APInt(8, 255))); + + EXPECT_EQ(APInt(8, -90), AP_10.ssub_sat(AP_100)); + EXPECT_EQ(APInt(8, 127), AP_100.ssub_sat(-AP_100)); + EXPECT_EQ(APInt(8, -128), (-AP_100).ssub_sat(AP_100)); + EXPECT_EQ(APInt(8, -128), APInt(8, -128).ssub_sat(APInt(8, 127))); +} + TEST(APIntTest, FromArray) { EXPECT_EQ(APInt(32, uint64_t(1)), APInt(32, ArrayRef(1))); }