From e6e2a67aa10b39f322677bc144da230593de2d78 Mon Sep 17 00:00:00 2001 From: Charles Pigott Date: Mon, 19 Jul 2021 12:58:36 +0100 Subject: Codechange: Use GCC/clang builtins for overflow safety when supported --- src/core/overflowsafe_type.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/core/overflowsafe_type.hpp b/src/core/overflowsafe_type.hpp index 00d0dfca1..3f2948551 100644 --- a/src/core/overflowsafe_type.hpp +++ b/src/core/overflowsafe_type.hpp @@ -12,6 +12,12 @@ #include "math_func.hpp" +#ifdef __has_builtin +# if __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_sub_overflow) && __has_builtin(__builtin_mul_overflow) +# define HAS_OVERFLOW_BUILTINS +# endif +#endif + /** * Overflow safe template for integers, i.e. integers that will never overflow * you multiply the maximum value with 2, or add 2, or subtract something from @@ -43,6 +49,11 @@ public: */ inline OverflowSafeInt& operator += (const OverflowSafeInt& other) { +#ifdef HAS_OVERFLOW_BUILTINS + if (unlikely(__builtin_add_overflow(this->m_value, other.m_value, &this->m_value))) { + this->m_value = (other.m_value < 0) ? T_MIN : T_MAX; + } +#else if (this->m_value > 0 && other.m_value > 0 && (T_MAX - other.m_value) < this->m_value) { this->m_value = T_MAX; } else if (this->m_value < 0 && other.m_value < 0 && (this->m_value == T_MIN || other.m_value == T_MIN || ((T_MAX + this->m_value) + other.m_value < (T_MIN + T_MAX)))) { @@ -50,6 +61,7 @@ public: } else { this->m_value += other.m_value; } +#endif return *this; } @@ -60,6 +72,11 @@ public: */ inline OverflowSafeInt& operator -= (const OverflowSafeInt& other) { +#ifdef HAS_OVERFLOW_BUILTINS + if (unlikely(__builtin_sub_overflow(this->m_value, other.m_value, &this->m_value))) { + this->m_value = (other.m_value < 0) ? T_MAX : T_MIN; + } +#else if (this->m_value > 0 && other.m_value < 0 && (T_MAX + other.m_value) < this->m_value) { this->m_value = T_MAX; } else if (this->m_value < 0 && other.m_value > 0 && (T_MAX + this->m_value) < (T_MIN + T_MAX) + other.m_value) { @@ -67,6 +84,7 @@ public: } else { this->m_value -= other.m_value; } +#endif return *this; } @@ -91,6 +109,12 @@ public: */ inline OverflowSafeInt& operator *= (const int factor) { +#ifdef HAS_OVERFLOW_BUILTINS + bool is_result_positive = (this->m_value < 0) == (factor < 0); // -ve * -ve == +ve + if (unlikely(__builtin_mul_overflow(this->m_value, factor, &this->m_value))) { + this->m_value = is_result_positive ? T_MAX : T_MIN; + } +#else if (factor == -1) { this->m_value = (this->m_value == T_MIN) ? T_MAX : -this->m_value; } else if (factor > 0 && this->m_value > 0 && (T_MAX / factor) < this->m_value) { @@ -104,6 +128,7 @@ public: } else { this->m_value *= factor; } +#endif return *this; } @@ -176,4 +201,6 @@ template inline OverflowSafeInt OverflowSafeInt64; typedef OverflowSafeInt OverflowSafeInt32; +#undef HAS_OVERFLOW_BUILTINS + #endif /* OVERFLOWSAFE_TYPE_HPP */ -- cgit v1.2.3-54-g00ecf