Index: include/llvm/Support/MathExtras.h =================================================================== --- include/llvm/Support/MathExtras.h +++ include/llvm/Support/MathExtras.h @@ -839,6 +839,18 @@ return SaturatingAdd(A, Product, &Overflowed); } +/// Add two integers \p LHS and \p RHS, write into \p Res if non-null and the +/// operation does not oveflow. +/// Does not guarantee saturating arithmetic. +/// \return Whether the result overflows. +bool checkedAdd(int64_t LHS, int64_t RHS, int64_t *Res=nullptr); + +/// Multiply two integers \p LHS and \p RHS, write into \p Res if non-null and +/// the operation does not oveflow. +/// Does not guarantee saturating arithmetic. +/// \return Whether the result overflows. +bool checkedMul(int64_t LHS, int64_t RHS, int64_t *Res=nullptr); + /// Use this rather than HUGE_VALF; the latter causes warnings on MSVC. extern const float huge_valf; } // End llvm namespace Index: lib/Support/MathExtras.cpp =================================================================== --- lib/Support/MathExtras.cpp +++ lib/Support/MathExtras.cpp @@ -18,9 +18,39 @@ #else #include #endif +#include +#include namespace llvm { +static bool checkedOp( + int64_t LHS, + int64_t RHS, + std::function Op, + int64_t *Res = nullptr) { + llvm::APInt ALHS(/*BitSize=*/64, LHS, /*Signed=*/true); + llvm::APInt ARHS(/*BitSize=*/64, RHS, /*Signed=*/true); + bool Overflow; + llvm::APInt Out = Op(&ALHS, ARHS, Overflow); + if (!Overflow && Res) + *Res = Out.getSExtValue(); + return Overflow; +} + +bool checkedAdd( + int64_t LHS, + int64_t RHS, + int64_t *Res) { + return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov, Res); +} + +bool checkedMul( + int64_t LHS, + int64_t RHS, + int64_t *Res) { + return checkedOp(LHS, RHS, &llvm::APInt::smul_ov, Res); +} + #if defined(_MSC_VER) // Visual Studio defines the HUGE_VAL class of macros using purposeful // constant arithmetic overflow, which it then warns on when encountered. Index: unittests/Support/MathExtrasTest.cpp =================================================================== --- unittests/Support/MathExtrasTest.cpp +++ unittests/Support/MathExtrasTest.cpp @@ -469,4 +469,27 @@ EXPECT_FALSE((isShiftedInt<6, 10>(int64_t(1) << 15))); } +TEST(MathExtras, CheckedAdd) { + const int64_t Max = std::numeric_limits::max(); + const int64_t Min = std::numeric_limits::min(); + EXPECT_EQ(checkedAdd(Max, Max), true); + EXPECT_EQ(checkedAdd(Min, -1), true); + EXPECT_EQ(checkedAdd(Max, 1), true); + int64_t Out; + EXPECT_EQ(checkedAdd(10, 1, &Out), false); + EXPECT_EQ(Out, 11); + +} + +TEST(MathExtras, CheckedMul) { + const int64_t Max = std::numeric_limits::max(); + const int64_t Min = std::numeric_limits::min(); + EXPECT_EQ(checkedMul(Max, 2), true); + EXPECT_EQ(checkedMul(Max, Max), true); + EXPECT_EQ(checkedMul(Min, 2), true); + int64_t Out; + EXPECT_EQ(checkedMul(10, 2, &Out), false); + EXPECT_EQ(Out, 20); +} + } // namespace