diff --git a/meson.build b/meson.build index 117ec90b27b..c7925760679 100644 --- a/meson.build +++ b/meson.build @@ -1019,6 +1019,13 @@ foreach b : ['bswap32', 'bswap64', 'clz', 'clzll', 'ctz', 'expect', 'ffs', endif endforeach +# Check for GCC overflow intrinsics +foreach b : ['add_overflow', 'add_overflow_p', 'sub_overflow_p'] + if cc.has_function('__builtin_' + b) + pre_args += '-DHAVE___BUILTIN_@0@'.format(b.to_upper()) + endif +endforeach + # check for GCC __attribute__ _attributes = [ 'const', 'flatten', 'malloc', 'pure', 'unused', 'warn_unused_result', diff --git a/src/util/meson.build b/src/util/meson.build index 6990bf419d0..73c3a05dda3 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -165,6 +165,7 @@ files_mesa_util = files( 'u_cpu_detect.h', 'u_printf.c', 'u_printf.h', + 'u_overflow.h', 'u_tristate.h', 'u_worklist.c', 'u_worklist.h', diff --git a/src/util/u_overflow.h b/src/util/u_overflow.h new file mode 100644 index 00000000000..fb3f3f42552 --- /dev/null +++ b/src/util/u_overflow.h @@ -0,0 +1,82 @@ +/* + * Copyright © 2025 Advanced Micro Devices, Inc. + * SPDX-License-Identifier: MIT + */ +#include "util/macros.h" + +#ifndef U_OVERFLOW_H +#define U_OVERFLOW_H + +#ifdef HAVE___BUILTIN_ADD_OVERFLOW +#define util_add_overflow(ty, a, b, c) __builtin_add_overflow(a, b, c) +#else +#define DEFINE_U_ADD_OVERFLOW_UINT(ty) \ + static inline bool \ + util_add_overflow_##ty(ty a, ty b, ty * res) { \ + *res = a + b; \ + return *res < a; \ + } +#define DEFINE_U_ADD_OVERFLOW_SINT(ty) \ + static inline bool \ + util_add_overflow_##ty(ty a, ty b, ty * res) { \ + if ((b > 0 && a > u_intN_max(sizeof(a) * 8) - b) || \ + (b < 0 && a < u_intN_min(sizeof(a) * 8) - b)) \ + return true; \ + *res = a + b; \ + return false; \ + } + +DEFINE_U_ADD_OVERFLOW_UINT(size_t) +DEFINE_U_ADD_OVERFLOW_UINT(uint64_t) +DEFINE_U_ADD_OVERFLOW_SINT(int64_t) + +#define util_add_overflow(ty, a, b, c) util_add_overflow_##ty(a, b, c) +#endif /* HAVE___BUILTIN_ADD_OVERFLOW */ + +#ifdef HAVE___BUILTIN_ADD_OVERFLOW_P +#define util_add_check_overflow(ty, a, b) __builtin_add_overflow_p(a, b, (ty)0) +#else +#define DEFINE_U_ADD_CHECK_OVERFLOW_UINT(ty) \ + static inline bool \ + util_add_check_overflow_##ty(ty a, ty b) { \ + ty c = a + b; \ + return c < a; \ + } +#define DEFINE_U_ADD_CHECK_OVERFLOW_SINT(ty) \ + static inline bool \ + util_add_check_overflow_##ty(ty a, ty b) { \ + return (b > 0 && a > u_intN_max(sizeof(a) * 8) - b) || \ + (b < 0 && a < u_intN_min(sizeof(a) * 8) - b); \ + } +DEFINE_U_ADD_CHECK_OVERFLOW_UINT(uint8_t) +DEFINE_U_ADD_CHECK_OVERFLOW_UINT(uint16_t) +DEFINE_U_ADD_CHECK_OVERFLOW_UINT(uint32_t) +DEFINE_U_ADD_CHECK_OVERFLOW_UINT(uint64_t) + +DEFINE_U_ADD_CHECK_OVERFLOW_SINT(int8_t) +DEFINE_U_ADD_CHECK_OVERFLOW_SINT(int16_t) +DEFINE_U_ADD_CHECK_OVERFLOW_SINT(int32_t) +DEFINE_U_ADD_CHECK_OVERFLOW_SINT(int64_t) + +#define util_add_check_overflow(ty, a, b) util_add_check_overflow_##ty(a, b) +#endif /* HAVE___BUILTIN_ADD_OVERFLOW_P */ + +#ifdef HAVE___BUILTIN_SUB_OVERFLOW_P +#define util_sub_check_overflow(ty, a, b) __builtin_sub_overflow_p(a, b, (ty)0) +#else +#define DEFINE_U_SUB_CHECK_OVERFLOW_SINT(ty) \ + static inline bool \ + util_sub_check_overflow_##ty(ty a, ty b) { \ + return (b < 0 && a > u_intN_max(sizeof(a) * 8) + b) || \ + (b > 0 && a < u_intN_min(sizeof(a) * 8) + b); \ + } + +DEFINE_U_SUB_CHECK_OVERFLOW_SINT(int8_t) +DEFINE_U_SUB_CHECK_OVERFLOW_SINT(int16_t) +DEFINE_U_SUB_CHECK_OVERFLOW_SINT(int32_t) +DEFINE_U_SUB_CHECK_OVERFLOW_SINT(int64_t) + +#define util_sub_check_overflow(ty, a, b) util_sub_check_overflow_##ty(a, b) +#endif /* HAVE___BUILTIN_SUB_OVERFLOW_P */ + +#endif