James Almer: > From: Justine Tunney <jtun...@gmail.com> > > Header contents taken from > https://github.com/jart/jtckdint/commit/62df1fc0966926299253b7af46c777723e345545 > > Signed-off-by: James Almer <jamr...@gmail.com> > --- > compat/stdckdint/stdckdint.h | 663 +++++++++++++++++++++++++++++++++++ > tests/ref/fate/source | 1 + > 2 files changed, 664 insertions(+) > create mode 100644 compat/stdckdint/stdckdint.h > > diff --git a/compat/stdckdint/stdckdint.h b/compat/stdckdint/stdckdint.h > new file mode 100644 > index 0000000000..2d36e8ad89 > --- /dev/null > +++ b/compat/stdckdint/stdckdint.h > @@ -0,0 +1,663 @@ > +/* > + * Copyright 2023 Justine Alexandra Roberts Tunney > + * > + * Permission to use, copy, modify, and/or distribute this software for > + * any purpose with or without fee is hereby granted, provided that the > + * above copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL > + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED > + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE > + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL > + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR > + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER > + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR > + * PERFORMANCE OF THIS SOFTWARE. > + */ > + > +/** > + * @fileoverview C23 Checked Arithmetic > + * > + * This header defines three type generic functions: > + * > + * - `bool ckd_add(res, a, b)` > + * - `bool ckd_sub(res, a, b)` > + * - `bool ckd_mul(res, a, b)` > + * > + * Which allow integer arithmetic errors to be detected. There are many > + * kinds of integer errors, e.g. overflow, truncation, etc. These funcs > + * catch them all. Here's an example of how it works: > + * > + * uint32_t c; > + * int32_t a = 0x7fffffff; > + * int32_t b = 2; > + * assert(!ckd_add(&c, a, b)); > + * assert(c == 0x80000001u); > + * > + * Experienced C / C++ users should find this example counter-intuitive > + * because the expression `0x7fffffff + 2` not only overflows it's also > + * undefined behavior. However here we see it's specified, and does not > + * result in an error. That's because C23 checked arithmetic is not the > + * arithmetic you're used to. The new standard changes the mathematics. > + * > + * C23 checked arithmetic is defined as performing the arithmetic using > + * infinite precision and then checking if the resulting value will fit > + * in the output type. Our example above did not result in an error due > + * to `0x80000001` being a legal value for `uint32_t`. > + * > + * This implementation will use the GNU compiler builtins, when they're > + * available, only if you don't use build flags like `-std=c11` because > + * they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI. > + * Instead, you'll get a pretty good pure C11 and C++11 implementation.
Doesn't this imply that we will no longer get the compiler builtins? That is very bad. > + * > + * @see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf > + * @version 0.1 (2023-07-22) > + */ > + > +#ifndef JTCKDINT_H_ > +#define JTCKDINT_H_ > + > +#ifdef __has_include > +#define __ckd_has_include(x) __has_include(x) > +#else > +#define __ckd_has_include(x) 0 > +#endif > + > +#if __ckd_has_include(<stdckdint.h>) > +#include <stdckdint.h> > +#else > + > +#define __STDC_VERSION_STDCKDINT_H__ 202311L > + > +#if ((defined(__llvm__) || \ > + (defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 406)) && \ > + !defined(__STRICT_ANSI__)) > +#define __ckd_have_int128 > +#define __ckd_intmax __int128 > +#elif ((defined(__cplusplus) && __cplusplus >= 201103L) || \ > + (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)) > +#define __ckd_intmax long long > +#else > +#define __ckd_intmax long > +#endif > + > +typedef signed __ckd_intmax __ckd_intmax_t; > +typedef unsigned __ckd_intmax __ckd_uintmax_t; > + > +#ifdef __has_builtin > +#define __ckd_has_builtin(x) __has_builtin(x) > +#else > +#define __ckd_has_builtin(x) 0 > +#endif > + > +#if (!defined(__STRICT_ANSI__) && \ > + ((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \ > + (__ckd_has_builtin(__builtin_add_overflow) && \ > + __ckd_has_builtin(__builtin_sub_overflow) && \ > + __ckd_has_builtin(__builtin_mul_overflow)))) > +#define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res)) > +#define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res)) > +#define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res)) > + > +#elif (defined(__cplusplus) && \ > + (__cplusplus >= 201103L || \ > + (defined(_MSC_VER) && __cplusplus >= 199711L && \ > + __ckd_has_include(<type_traits>) && \ > + __ckd_has_include(<limits>)))) > +#include <type_traits> > +#include <limits> > + > +template <typename __T, typename __U, typename __V> > +inline bool ckd_add(__T *__res, __U __a, __V __b) { > + static_assert(std::is_integral<__T>::value && > + std::is_integral<__U>::value && > + std::is_integral<__V>::value, > + "non-integral types not allowed"); > + static_assert(!std::is_same<__T, bool>::value && > + !std::is_same<__U, bool>::value && > + !std::is_same<__V, bool>::value, > + "checked booleans not supported"); > + static_assert(!std::is_same<__T, char>::value && > + !std::is_same<__U, char>::value && > + !std::is_same<__V, char>::value, > + "unqualified char type is ambiguous"); > + __ckd_uintmax_t __x = __a; > + __ckd_uintmax_t __y = __b; > + __ckd_uintmax_t __z = __x + __y; > + *__res = __z; > + if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) { > + if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) { > + return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z); > + } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { > + return (__z != static_cast<__T>(__z) || > + ((std::is_signed<__U>::value || > + std::is_signed<__V>::value) && > + static_cast<__ckd_intmax_t>(__z) < 0)); > + } > + } > + bool __truncated = false; > + if (sizeof(__T) < sizeof(__ckd_intmax_t)) { > + __truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z)); > + } > + switch (std::is_signed<__T>::value << 2 | // > + std::is_signed<__U>::value << 1 | // > + std::is_signed<__V>::value) { > + case 0: // u = u + u > + return __truncated | (__z < __x); > + case 1: // u = u + s > + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); > + return __truncated | > + (static_cast<__ckd_intmax_t>((__z ^ __x) & > + (__z ^ __y)) < 0); > + case 2: // u = s + u > + __x ^= std::numeric_limits<__ckd_intmax_t>::min(); > + return __truncated | > + (static_cast<__ckd_intmax_t>((__z ^ __x) & > + (__z ^ __y)) < 0); > + case 3: // u = s + s > + return __truncated | > + (static_cast<__ckd_intmax_t>(((__z | __x) & __y) | > + ((__z & __x) & ~__y)) < 0); > + case 4: // s = u + u > + return __truncated | (__z < __x) | (static_cast<__ckd_intmax_t>(__z) < > 0); > + case 5: // s = u + s > + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); > + return __truncated | (__x + __y < __y); > + case 6: // s = s + u > + __x ^= std::numeric_limits<__ckd_intmax_t>::min(); > + return __truncated | (__x + __y < __x); > + case 7: // s = s + s > + return __truncated | > + (static_cast<__ckd_intmax_t>((__z ^ __x) & > + (__z ^ __y)) < 0); > + default: > + for (;;) (void)0; > + } > +} > + > +template <typename __T, typename __U, typename __V> > +inline bool ckd_sub(__T *__res, __U __a, __V __b) { > + static_assert(std::is_integral<__T>::value && > + std::is_integral<__U>::value && > + std::is_integral<__V>::value, > + "non-integral types not allowed"); > + static_assert(!std::is_same<__T, bool>::value && > + !std::is_same<__U, bool>::value && > + !std::is_same<__V, bool>::value, > + "checked booleans not supported"); > + static_assert(!std::is_same<__T, char>::value && > + !std::is_same<__U, char>::value && > + !std::is_same<__V, char>::value, > + "unqualified char type is ambiguous"); > + __ckd_uintmax_t __x = __a; > + __ckd_uintmax_t __y = __b; > + __ckd_uintmax_t __z = __x - __y; > + *__res = __z; > + if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) { > + if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) { > + return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z); > + } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { > + return (__z != static_cast<__T>(__z) || > + ((std::is_signed<__U>::value || > + std::is_signed<__V>::value) && > + static_cast<__ckd_intmax_t>(__z) < 0)); > + } > + } > + bool __truncated = false; > + if (sizeof(__T) < sizeof(__ckd_intmax_t)) { > + __truncated = __z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z)); > + } > + switch (std::is_signed<__T>::value << 2 | // > + std::is_signed<__U>::value << 1 | // > + std::is_signed<__V>::value) { > + case 0: // u = u - u > + return __truncated | (__x < __y); > + case 1: // u = u - s > + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); > + return __truncated | > + (static_cast<__ckd_intmax_t>((__x ^ __y) & > + (__z ^ __x)) < 0); > + case 2: // u = s - u > + return __truncated | (__y > __x) | (static_cast<__ckd_intmax_t>(__x) < > 0); > + case 3: // u = s - s > + return __truncated | > + (static_cast<__ckd_intmax_t>(((__z & __x) & __y) | > + ((__z | __x) & ~__y)) < 0); > + case 4: // s = u - u > + return __truncated | > + ((__x < __y) ^ (static_cast<__ckd_intmax_t>(__z) < 0)); > + case 5: // s = u - s > + __y ^= std::numeric_limits<__ckd_intmax_t>::min(); > + return __truncated | (__x >= __y); > + case 6: // s = s - u > + __x ^= std::numeric_limits<__ckd_intmax_t>::min(); > + return __truncated | (__x < __y); > + case 7: // s = s - s > + return __truncated | > + (static_cast<__ckd_intmax_t>((__x ^ __y) & > + (__z ^ __x)) < 0); > + default: > + for (;;) (void)0; > + } > +} > + > +template <typename __T, typename __U, typename __V> > +inline bool ckd_mul(__T *__res, __U __a, __V __b) { > + static_assert(std::is_integral<__T>::value && > + std::is_integral<__U>::value && > + std::is_integral<__V>::value, > + "non-integral types not allowed"); > + static_assert(!std::is_same<__T, bool>::value && > + !std::is_same<__U, bool>::value && > + !std::is_same<__V, bool>::value, > + "checked booleans not supported"); > + static_assert(!std::is_same<__T, char>::value && > + !std::is_same<__U, char>::value && > + !std::is_same<__V, char>::value, > + "unqualified char type is ambiguous"); > + __ckd_uintmax_t __x = __a; > + __ckd_uintmax_t __y = __b; > + if ((sizeof(__U) * 8 - std::is_signed<__U>::value) + > + (sizeof(__V) * 8 - std::is_signed<__V>::value) <= > + (sizeof(__T) * 8 - std::is_signed<__T>::value)) { > + if (sizeof(__ckd_uintmax_t) > sizeof(__T) || std::is_signed<__T>::value) > { > + __ckd_intmax_t __z = __x * __y; > + return __z != (*__res = __z); > + } else if (!std::is_same<__T, __ckd_uintmax_t>::value) { > + __ckd_uintmax_t __z = __x * __y; > + *__res = __z; > + return (__z != static_cast<__T>(__z) || > + ((std::is_signed<__U>::value || > + std::is_signed<__V>::value) && > + static_cast<__ckd_intmax_t>(__z) < 0)); > + } > + } > + switch (std::is_signed<__T>::value << 2 | // > + std::is_signed<__U>::value << 1 | // > + std::is_signed<__V>::value) { > + case 0: { // u = u * u > + __ckd_uintmax_t __z = __x * __y; > + int __o = __x && __z / __x != __y; > + *__res = __z; > + return __o | (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res)); > + } > + case 1: { // u = u * s > + __ckd_uintmax_t __z = __x * __y; > + int __o = __x && __z / __x != __y; > + *__res = __z; > + return (__o | ((static_cast<__ckd_intmax_t>(__y) < 0) & !!__x) | > + (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res))); > + } > + case 2: { // u = s * u > + __ckd_uintmax_t __z = __x * __y; > + int __o = __x && __z / __x != __y; > + *__res = __z; > + return (__o | ((static_cast<__ckd_intmax_t>(__x) < 0) & !!__y) | > + (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res))); > + } > + case 3: { // u = s * s > + int __o = false; > + if (static_cast<__ckd_intmax_t>(__x & __y) < 0) { > + __x = -__x; > + __y = -__y; > + } else if (static_cast<__ckd_intmax_t>(__x ^ __y) < 0) { > + __o = __x && __y; > + } > + __ckd_uintmax_t __z = __x * __y; > + __o |= __x && __z / __x != __y; > + *__res = __z; > + return __o | (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res)); > + } > + case 4: { // s = u * u > + __ckd_uintmax_t __z = __x * __y; > + int __o = __x && __z / __x != __y; > + *__res = __z; > + return (__o | (static_cast<__ckd_intmax_t>(__z) < 0) | > + (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res))); > + } > + case 5: { // s = u * s > + __ckd_uintmax_t __t = -__y; > + __t = static_cast<__ckd_intmax_t>(__t) < 0 ? __y : __t; > + __ckd_uintmax_t __p = __t * __x; > + int __o = __t && __p / __t != __x; > + int __n = static_cast<__ckd_intmax_t>(__y) < 0; > + __ckd_uintmax_t __z = __n ? -__p : __p; > + *__res = __z; > + __ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max(); > + return (__o | (__p > __m + __n) | > + (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res))); > + } > + case 6: { // s = s * u > + __ckd_uintmax_t __t = -__x; > + __t = static_cast<__ckd_intmax_t>(__t) < 0 ? __x : __t; > + __ckd_uintmax_t __p = __t * __y; > + int __o = __t && __p / __t != __y; > + int __n = static_cast<__ckd_intmax_t>(__x) < 0; > + __ckd_uintmax_t __z = __n ? -__p : __p; > + *__res = __z; > + __ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max(); > + return (__o | (__p > __m + __n) | > + (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res))); > + } > + case 7: { // s = s * s > + __ckd_uintmax_t __z = __x * __y; > + *__res = __z; > + return ((((static_cast<__ckd_intmax_t>(__y) < 0) && > + (static_cast<__ckd_intmax_t>(__x) == > + std::numeric_limits<__ckd_intmax_t>::min())) || > + (__y && ((static_cast<__ckd_intmax_t>(__z) / > + static_cast<__ckd_intmax_t>(__y)) != > + static_cast<__ckd_intmax_t>(__x)))) | > + (sizeof(__T) < sizeof(__z) && > + __z != static_cast<__ckd_uintmax_t>(*__res))); > + } > + default: > + for (;;) (void)0; > + } > +} > + > +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L > + > +#define ckd_add(res, a, b) __ckd_expr(add, (res), (a), (b)) > +#define ckd_sub(res, a, b) __ckd_expr(sub, (res), (a), (b)) > +#define ckd_mul(res, a, b) __ckd_expr(mul, (res), (a), (b)) > + > +#if defined(__GNUC__) || defined(__llvm__) > +#define __ckd_inline \ > + extern __inline __attribute__((__gnu_inline__, \ > + __always_inline__, \ > + __artificial__)) > +#else > +#define __ckd_inline static inline > +#endif > + > +#ifdef __ckd_have_int128 > +#define __ckd_generic_int128(x, y) , signed __int128: x, unsigned __int128: y > +#else > +#define __ckd_generic_int128(x, y) > +#endif > + > +#define __ckd_sign(T) \ > + ((T)1 << (sizeof(T) * 8 - 1)) > + > +#define __ckd_is_signed(x) \ > + _Generic(x, \ > + signed char: 1, \ > + unsigned char: 0, \ > + signed short: 1, \ > + unsigned short: 0, \ > + signed int: 1, \ > + unsigned int: 0, \ > + signed long: 1, \ > + unsigned long: 0, \ > + signed long long: 1, \ > + unsigned long long: 0 \ > + __ckd_generic_int128(1, 0)) > + > +#define __ckd_expr(op, res, a, b) \ > + (_Generic(*res, \ > + signed char: __ckd_##op##_schar, \ > + unsigned char: __ckd_##op##_uchar, \ > + signed short: __ckd_##op##_sshort, \ > + unsigned short: __ckd_##op##_ushort, \ > + signed int: __ckd_##op##_sint, \ > + unsigned int: __ckd_##op##_uint, \ > + signed long: __ckd_##op##_slong, \ > + unsigned long: __ckd_##op##_ulong, \ > + signed long long: __ckd_##op##_slonger, \ > + unsigned long long: __ckd_##op##_ulonger \ > + __ckd_generic_int128( \ > + __ckd_##op##_sint128, \ > + __ckd_##op##_uint128))( \ > + res, a, b, \ > + __ckd_is_signed(a), \ > + __ckd_is_signed(b))) > + > +#define __ckd_declare_add(S, T) \ > + __ckd_inline char S(void *__res, \ > + __ckd_uintmax_t __x, \ > + __ckd_uintmax_t __y, \ > + char __a_signed, \ > + char __b_signed) { \ > + __ckd_uintmax_t __z = __x + __y; \ > + *(T *)__res = __z; \ > + char __truncated = 0; \ > + if (sizeof(T) < sizeof(__ckd_intmax_t)) { \ > + __truncated = __z != (__ckd_uintmax_t)(T)__z; \ > + } \ > + switch (__ckd_is_signed((T)0) << 2 | \ > + __a_signed << 1 | __b_signed) { \ > + case 0: /* u = u + u */ \ > + return __truncated | (__z < __x); \ > + case 1: /* u = u + s */ \ > + __y ^= __ckd_sign(__ckd_uintmax_t); \ > + return __truncated | \ > + ((__ckd_intmax_t)((__z ^ __x) & \ > + (__z ^ __y)) < 0); \ > + case 2: /* u = s + u */ \ > + __x ^= __ckd_sign(__ckd_uintmax_t); \ > + return __truncated | \ > + ((__ckd_intmax_t)((__z ^ __x) & \ > + (__z ^ __y)) < 0); \ > + case 3: /* u = s + s */ \ > + return __truncated | \ > + ((__ckd_intmax_t)(((__z | __x) & __y) | \ > + ((__z & __x) & ~__y)) < 0); \ > + case 4: /* s = u + u */ \ > + return __truncated | (__z < __x) | ((__ckd_intmax_t)__z < 0); \ > + case 5: /* s = u + s */ \ > + __y ^= __ckd_sign(__ckd_uintmax_t); \ > + return __truncated | (__x + __y < __y); \ > + case 6: /* s = s + u */ \ > + __x ^= __ckd_sign(__ckd_uintmax_t); \ > + return __truncated | (__x + __y < __x); \ > + case 7: /* s = s + s */ \ > + return __truncated | \ > + ((__ckd_intmax_t)((__z ^ __x) & \ > + (__z ^ __y)) < 0); \ > + default: \ > + for (;;) (void)0; \ > + } \ > + } > + > +__ckd_declare_add(__ckd_add_schar, signed char) > +__ckd_declare_add(__ckd_add_uchar, unsigned char) > +__ckd_declare_add(__ckd_add_sshort, signed short) > +__ckd_declare_add(__ckd_add_ushort, unsigned short) > +__ckd_declare_add(__ckd_add_sint, signed int) > +__ckd_declare_add(__ckd_add_uint, unsigned int) > +__ckd_declare_add(__ckd_add_slong, signed long) > +__ckd_declare_add(__ckd_add_ulong, unsigned long) > +__ckd_declare_add(__ckd_add_slonger, signed long long) > +__ckd_declare_add(__ckd_add_ulonger, unsigned long long) > +#ifdef __ckd_have_int128 > +__ckd_declare_add(__ckd_add_sint128, signed __int128) > +__ckd_declare_add(__ckd_add_uint128, unsigned __int128) > +#endif > + > +#define __ckd_declare_sub(S, T) \ > + __ckd_inline char S(void *__res, \ > + __ckd_uintmax_t __x, \ > + __ckd_uintmax_t __y, \ > + char __a_signed, \ > + char __b_signed) { \ > + __ckd_uintmax_t __z = __x - __y; \ > + *(T *)__res = __z; \ > + char __truncated = 0; \ > + if (sizeof(T) < sizeof(__ckd_intmax_t)) { \ > + __truncated = __z != (__ckd_uintmax_t)(T)__z; \ > + } \ > + switch (__ckd_is_signed((T)0) << 2 | \ > + __a_signed << 1 | __b_signed) { \ > + case 0: /* u = u - u */ \ > + return __truncated | (__x < __y); \ > + case 1: /* u = u - s */ \ > + __y ^= __ckd_sign(__ckd_uintmax_t); \ > + return __truncated | \ > + ((__ckd_intmax_t)((__x ^ __y) & \ > + (__z ^ __x)) < 0); \ > + case 2: /* u = s - u */ \ > + return __truncated | (__y > __x) | ((__ckd_intmax_t)__x < 0); \ > + case 3: /* u = s - s */ \ > + return __truncated | \ > + ((__ckd_intmax_t)(((__z & __x) & __y) | \ > + ((__z | __x) & ~__y)) < 0); \ > + case 4: /* s = u - u */ \ > + return __truncated | ((__x < __y) ^ ((__ckd_intmax_t)__z < 0)); \ > + case 5: /* s = u - s */ \ > + __y ^= __ckd_sign(__ckd_uintmax_t); \ > + return __truncated | (__x >= __y); \ > + case 6: /* s = s - u */ \ > + __x ^= __ckd_sign(__ckd_uintmax_t); \ > + return __truncated | (__x < __y); \ > + case 7: /* s = s - s */ \ > + return __truncated | \ > + ((__ckd_intmax_t)((__x ^ __y) & \ > + (__z ^ __x)) < 0); \ > + default: \ > + for (;;) (void)0; \ > + } \ > + } > + > +__ckd_declare_sub(__ckd_sub_schar, signed char) > +__ckd_declare_sub(__ckd_sub_uchar, unsigned char) > +__ckd_declare_sub(__ckd_sub_sshort, signed short) > +__ckd_declare_sub(__ckd_sub_ushort, unsigned short) > +__ckd_declare_sub(__ckd_sub_sint, signed int) > +__ckd_declare_sub(__ckd_sub_uint, unsigned int) > +__ckd_declare_sub(__ckd_sub_slong, signed long) > +__ckd_declare_sub(__ckd_sub_ulong, unsigned long) > +__ckd_declare_sub(__ckd_sub_slonger, signed long long) > +__ckd_declare_sub(__ckd_sub_ulonger, unsigned long long) > +#ifdef __ckd_have_int128 > +__ckd_declare_sub(__ckd_sub_sint128, signed __int128) > +__ckd_declare_sub(__ckd_sub_uint128, unsigned __int128) > +#endif > + > +#define __ckd_declare_mul(S, T) \ > + __ckd_inline char S(void *__res, \ > + __ckd_uintmax_t __x, \ > + __ckd_uintmax_t __y, \ > + char __a_signed, \ > + char __b_signed) { \ > + switch (__ckd_is_signed((T)0) << 2 | \ > + __a_signed << 1 | __b_signed) { \ > + case 0: { /* u = u * u */ \ > + __ckd_uintmax_t __z = __x * __y; \ > + int __o = __x && __z / __x != __y; \ > + *(T *)__res = __z; \ > + return __o | (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res); \ > + } \ > + case 1: { /* u = u * s */ \ > + __ckd_uintmax_t __z = __x * __y; \ > + int __o = __x && __z / __x != __y; \ > + *(T *)__res = __z; \ > + return (__o | (((__ckd_intmax_t)__y < 0) & !!__x) | \ > + (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res)); \ > + } \ > + case 2: { /* u = s * u */ \ > + __ckd_uintmax_t __z = __x * __y; \ > + int __o = __x && __z / __x != __y; \ > + *(T *)__res = __z; \ > + return (__o | (((__ckd_intmax_t)__x < 0) & !!__y) | \ > + (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res)); \ > + } \ > + case 3: { /* u = s * s */ \ > + int __o = 0; \ > + if ((__ckd_intmax_t)(__x & __y) < 0) { \ > + __x = -__x; \ > + __y = -__y; \ > + } else if ((__ckd_intmax_t)(__x ^ __y) < 0) { \ > + __o = __x && __y; \ > + } \ > + __ckd_uintmax_t __z = __x * __y; \ > + __o |= __x && __z / __x != __y; \ > + *(T *)__res = __z; \ > + return __o | (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res); \ > + } \ > + case 4: { /* s = u * u */ \ > + __ckd_uintmax_t __z = __x * __y; \ > + int __o = __x && __z / __x != __y; \ > + *(T *)__res = __z; \ > + return (__o | ((__ckd_intmax_t)(__z) < 0) | \ > + (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res)); \ > + } \ > + case 5: { /* s = u * s */ \ > + __ckd_uintmax_t __t = -__y; \ > + __t = (__ckd_intmax_t)(__t) < 0 ? __y : __t; \ > + __ckd_uintmax_t __p = __t * __x; \ > + int __o = __t && __p / __t != __x; \ > + int __n = (__ckd_intmax_t)__y < 0; \ > + __ckd_uintmax_t __z = __n ? -__p : __p; \ > + *(T *)__res = __z; \ > + __ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \ > + return (__o | (__p > __m + __n) | \ > + (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res)); \ > + } \ > + case 6: { /* s = s * u */ \ > + __ckd_uintmax_t __t = -__x; \ > + __t = (__ckd_intmax_t)(__t) < 0 ? __x : __t; \ > + __ckd_uintmax_t __p = __t * __y; \ > + int __o = __t && __p / __t != __y; \ > + int __n = (__ckd_intmax_t)__x < 0; \ > + __ckd_uintmax_t __z = __n ? -__p : __p; \ > + *(T *)__res = __z; \ > + __ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \ > + return (__o | (__p > __m + __n) | \ > + (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res)); \ > + } \ > + case 7: { /* s = s * s */ \ > + __ckd_uintmax_t __z = __x * __y; \ > + *(T *)__res = __z; \ > + return (((((__ckd_intmax_t)__y < 0) && \ > + (__x == __ckd_sign(__ckd_uintmax_t))) || \ > + (__y && (((__ckd_intmax_t)__z / \ > + (__ckd_intmax_t)__y) != \ > + (__ckd_intmax_t)__x))) | \ > + (sizeof(T) < sizeof(__z) && \ > + __z != (__ckd_uintmax_t)*(T *)__res)); \ > + } \ > + default: \ > + for (;;) (void)0; \ > + } \ > + } > + > +__ckd_declare_mul(__ckd_mul_schar, signed char) > +__ckd_declare_mul(__ckd_mul_uchar, unsigned char) > +__ckd_declare_mul(__ckd_mul_sshort, signed short) > +__ckd_declare_mul(__ckd_mul_ushort, unsigned short) > +__ckd_declare_mul(__ckd_mul_sint, signed int) > +__ckd_declare_mul(__ckd_mul_uint, unsigned int) > +__ckd_declare_mul(__ckd_mul_slong, signed long) > +__ckd_declare_mul(__ckd_mul_ulong, unsigned long) > +__ckd_declare_mul(__ckd_mul_slonger, signed long long) > +__ckd_declare_mul(__ckd_mul_ulonger, unsigned long long) > +#ifdef __ckd_have_int128 > +__ckd_declare_mul(__ckd_mul_sint128, signed __int128) > +__ckd_declare_mul(__ckd_mul_uint128, unsigned __int128) > +#endif > + > +#else > +#pragma message "checked integer arithmetic unsupported in this environment" > + > +#define ckd_add(res, x, y) (*(res) = (x) + (y), 0) > +#define ckd_sub(res, x, y) (*(res) = (x) - (y), 0) > +#define ckd_mul(res, x, y) (*(res) = (x) * (y), 0) > + > +#endif /* GNU */ > +#endif /* stdckdint.h */ > +#endif /* JTCKDINT_H_ */ > diff --git a/tests/ref/fate/source b/tests/ref/fate/source > index 78d3a2e0fa..ab6182bf4c 100644 > --- a/tests/ref/fate/source > +++ b/tests/ref/fate/source > @@ -25,6 +25,7 @@ compat/djgpp/math.h > compat/float/float.h > compat/float/limits.h > compat/stdbit/stdbit.h > +compat/stdckdint/stdckdint.h > libavcodec/bitstream_template.h > tools/decode_simple.h > Use of av_clip() where av_clip_uintp2() could be used: _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".