diff options
author | Charles Pigott <charlespigott@googlemail.com> | 2021-07-19 12:58:36 +0100 |
---|---|---|
committer | Charles Pigott <charlespigott@googlemail.com> | 2021-07-20 10:42:03 +0100 |
commit | e6e2a67aa10b39f322677bc144da230593de2d78 (patch) | |
tree | 54d1b994f48e36bc1d5efffabbe95e357fe23e6a /src | |
parent | 3d0d9edafd9199c0bd17e983e8f31e417b85d25d (diff) | |
download | openttd-e6e2a67aa10b39f322677bc144da230593de2d78.tar.xz |
Codechange: Use GCC/clang builtins for overflow safety when supported
Diffstat (limited to 'src')
-rw-r--r-- | src/core/overflowsafe_type.hpp | 27 |
1 files changed, 27 insertions, 0 deletions
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 <class T, int64 T_MAX, int64 T_MIN> inline OverflowSafeInt<T, T_MAX, T_ typedef OverflowSafeInt<int64, INT64_MAX, INT64_MIN> OverflowSafeInt64; typedef OverflowSafeInt<int32, INT32_MAX, INT32_MIN> OverflowSafeInt32; +#undef HAS_OVERFLOW_BUILTINS + #endif /* OVERFLOWSAFE_TYPE_HPP */ |