[llvm] r367470 - [Support] Added overflow checking add, sub and mul.
JF Bastien via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 31 12:40:07 PDT 2019
Author: jfb
Date: Wed Jul 31 12:40:07 2019
New Revision: 367470
URL: http://llvm.org/viewvc/llvm-project?rev=367470&view=rev
Log:
[Support] Added overflow checking add, sub and mul.
Added AddOverflow, SubOverflow and MulOverflow to compute truncated results and return a flag indicating whether overflow occured.
Differential Revision: https://reviews.llvm.org/D65494
Modified:
llvm/trunk/include/llvm/Support/MathExtras.h
llvm/trunk/unittests/Support/MathExtrasTest.cpp
Modified: llvm/trunk/include/llvm/Support/MathExtras.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MathExtras.h?rev=367470&r1=367469&r2=367470&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/MathExtras.h (original)
+++ llvm/trunk/include/llvm/Support/MathExtras.h Wed Jul 31 12:40:07 2019
@@ -853,6 +853,83 @@ SaturatingMultiplyAdd(T X, T Y, T A, boo
/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
extern const float huge_valf;
+
+
+/// Add two signed integers, computing the two's complement truncated result,
+/// returning true if overflow occured.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, T>::type
+AddOverflow(T X, T Y, T &Result) {
+ // Perform the unsigned addition.
+ using U = typename std::make_unsigned<T>::type;
+ const U UX = static_cast<U>(X);
+ const U UY = static_cast<U>(Y);
+ const U UResult = UX + UY;
+
+ // Convert to signed.
+ Result = static_cast<T>(UResult);
+
+ // Adding two positive numbers should result in a positive number.
+ if (X > 0 && Y > 0)
+ return Result <= 0;
+ // Adding two negatives should result in a negative number.
+ if (X < 0 && Y < 0)
+ return Result >= 0;
+ return false;
+}
+
+/// Subtract two signed integers, computing the two's complement truncated
+/// result, returning true if an overflow ocurred.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, T>::type
+SubOverflow(T X, T Y, T &Result) {
+ // Perform the unsigned addition.
+ using U = typename std::make_unsigned<T>::type;
+ const U UX = static_cast<U>(X);
+ const U UY = static_cast<U>(Y);
+ const U UResult = UX - UY;
+
+ // Convert to signed.
+ Result = static_cast<T>(UResult);
+
+ // Subtracting a positive number from a negative results in a negative number.
+ if (X <= 0 && Y > 0)
+ return Result >= 0;
+ // Subtracting a negative number from a positive results in a positive number.
+ if (X >= 0 && Y < 0)
+ return Result <= 0;
+ return false;
+}
+
+
+/// Multiply two signed integers, computing the two's complement truncated
+/// result, returning true if an overflow ocurred.
+template <typename T>
+typename std::enable_if<std::is_signed<T>::value, T>::type
+MulOverflow(T X, T Y, T &Result) {
+ // Perform the unsigned multiplication on absolute values.
+ using U = typename std::make_unsigned<T>::type;
+ const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
+ const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
+ const U UResult = UX * UY;
+
+ // Convert to signed.
+ const bool IsNegative = (X < 0) ^ (Y < 0);
+ Result = IsNegative ? (0 - UResult) : UResult;
+
+ // If any of the args was 0, result is 0 and no overflow occurs.
+ if (UX == 0 || UY == 0)
+ return false;
+
+ // UX and UY are in [1, 2^n], where n is the number of digits.
+ // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
+ // positive) divided by an argument compares to the other.
+ if (IsNegative)
+ return UX > (static_cast<U>(std::numeric_limits<T>::max()) + U(1)) / UY;
+ else
+ return UX > (static_cast<U>(std::numeric_limits<T>::max())) / UY;
+}
+
} // End llvm namespace
#endif
Modified: llvm/trunk/unittests/Support/MathExtrasTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/MathExtrasTest.cpp?rev=367470&r1=367469&r2=367470&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/MathExtrasTest.cpp (original)
+++ llvm/trunk/unittests/Support/MathExtrasTest.cpp Wed Jul 31 12:40:07 2019
@@ -468,4 +468,131 @@ TEST(MathExtras, IsShiftedInt) {
EXPECT_FALSE((isShiftedInt<6, 10>(int64_t(1) << 15)));
}
+template <typename T>
+class OverflowTest : public ::testing::Test { };
+
+using OverflowTestTypes = ::testing::Types<signed char, short, int, long,
+ long long>;
+
+TYPED_TEST_CASE(OverflowTest, OverflowTestTypes);
+
+TYPED_TEST(OverflowTest, AddNoOverflow) {
+ TypeParam Result;
+ EXPECT_FALSE(AddOverflow<TypeParam>(1, 2, Result));
+ EXPECT_EQ(Result, TypeParam(3));
+}
+
+TYPED_TEST(OverflowTest, AddOverflowToNegative) {
+ TypeParam Result;
+ auto MaxValue = std::numeric_limits<TypeParam>::max();
+ EXPECT_TRUE(AddOverflow<TypeParam>(MaxValue, MaxValue, Result));
+ EXPECT_EQ(Result, TypeParam(-2));
+}
+
+TYPED_TEST(OverflowTest, AddOverflowToMin) {
+ TypeParam Result;
+ auto MaxValue = std::numeric_limits<TypeParam>::max();
+ EXPECT_TRUE(AddOverflow<TypeParam>(MaxValue, TypeParam(1), Result));
+ EXPECT_EQ(Result, std::numeric_limits<TypeParam>::min());
+}
+
+TYPED_TEST(OverflowTest, AddOverflowToZero) {
+ TypeParam Result;
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_TRUE(AddOverflow<TypeParam>(MinValue, MinValue, Result));
+ EXPECT_EQ(Result, TypeParam(0));
+}
+
+TYPED_TEST(OverflowTest, AddOverflowToMax) {
+ TypeParam Result;
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_TRUE(AddOverflow<TypeParam>(MinValue, TypeParam(-1), Result));
+ EXPECT_EQ(Result, std::numeric_limits<TypeParam>::max());
+}
+
+TYPED_TEST(OverflowTest, SubNoOverflow) {
+ TypeParam Result;
+ EXPECT_FALSE(SubOverflow<TypeParam>(1, 2, Result));
+ EXPECT_EQ(Result, TypeParam(-1));
+}
+
+TYPED_TEST(OverflowTest, SubOverflowToMax) {
+ TypeParam Result;
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_TRUE(SubOverflow<TypeParam>(0, MinValue, Result));
+ EXPECT_EQ(Result, MinValue);
+}
+
+TYPED_TEST(OverflowTest, SubOverflowToMin) {
+ TypeParam Result;
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_TRUE(SubOverflow<TypeParam>(0, MinValue, Result));
+ EXPECT_EQ(Result, MinValue);
+}
+
+TYPED_TEST(OverflowTest, SubOverflowToNegative) {
+ TypeParam Result;
+ auto MaxValue = std::numeric_limits<TypeParam>::max();
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_TRUE(SubOverflow<TypeParam>(MaxValue, MinValue, Result));
+ EXPECT_EQ(Result, TypeParam(-1));
+}
+
+TYPED_TEST(OverflowTest, SubOverflowToPositive) {
+ TypeParam Result;
+ auto MaxValue = std::numeric_limits<TypeParam>::max();
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_TRUE(SubOverflow<TypeParam>(MinValue, MaxValue, Result));
+ EXPECT_EQ(Result, TypeParam(1));
+}
+
+TYPED_TEST(OverflowTest, MulNoOverflow) {
+ TypeParam Result;
+ EXPECT_FALSE(MulOverflow<TypeParam>(1, 2, Result));
+ EXPECT_EQ(Result, 2);
+ EXPECT_FALSE(MulOverflow<TypeParam>(-1, 3, Result));
+ EXPECT_EQ(Result, -3);
+ EXPECT_FALSE(MulOverflow<TypeParam>(4, -2, Result));
+ EXPECT_EQ(Result, -8);
+ EXPECT_FALSE(MulOverflow<TypeParam>(-6, -5, Result));
+ EXPECT_EQ(Result, 30);
+}
+
+TYPED_TEST(OverflowTest, MulNoOverflowToMax) {
+ TypeParam Result;
+ auto MaxValue = std::numeric_limits<TypeParam>::max();
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_FALSE(MulOverflow<TypeParam>(MinValue + 1, -1, Result));
+ EXPECT_EQ(Result, MaxValue);
+}
+
+TYPED_TEST(OverflowTest, MulOverflowToMin) {
+ TypeParam Result;
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ EXPECT_TRUE(MulOverflow<TypeParam>(MinValue, -1, Result));
+ EXPECT_EQ(Result, MinValue);
+}
+
+TYPED_TEST(OverflowTest, MulOverflowMax) {
+ TypeParam Result;
+ auto MinValue = std::numeric_limits<TypeParam>::min();
+ auto MaxValue = std::numeric_limits<TypeParam>::max();
+ EXPECT_TRUE(MulOverflow<TypeParam>(MinValue, MinValue, Result));
+ EXPECT_EQ(Result, 0);
+ EXPECT_TRUE(MulOverflow<TypeParam>(MaxValue, MaxValue, Result));
+ EXPECT_EQ(Result, 1);
+}
+
+TYPED_TEST(OverflowTest, MulResultZero) {
+ TypeParam Result;
+ EXPECT_FALSE(MulOverflow<TypeParam>(4, 0, Result));
+ EXPECT_EQ(Result, TypeParam(0));
+ EXPECT_FALSE(MulOverflow<TypeParam>(-5, 0, Result));
+ EXPECT_EQ(Result, TypeParam(0));
+ EXPECT_FALSE(MulOverflow<TypeParam>(0, 5, Result));
+ EXPECT_EQ(Result, TypeParam(0));
+ EXPECT_FALSE(MulOverflow<TypeParam>(0, -5, Result));
+ EXPECT_EQ(Result, TypeParam(0));
+}
+
} // namespace
More information about the llvm-commits
mailing list