summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Pigott <charlespigott@googlemail.com>2021-07-19 12:58:36 +0100
committerCharles Pigott <charlespigott@googlemail.com>2021-07-20 10:42:03 +0100
commite6e2a67aa10b39f322677bc144da230593de2d78 (patch)
tree54d1b994f48e36bc1d5efffabbe95e357fe23e6a
parent3d0d9edafd9199c0bd17e983e8f31e417b85d25d (diff)
downloadopenttd-e6e2a67aa10b39f322677bc144da230593de2d78.tar.xz
Codechange: Use GCC/clang builtins for overflow safety when supported
-rw-r--r--src/core/overflowsafe_type.hpp27
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 */