summaryrefslogtreecommitdiff
path: root/py/misc.h
diff options
context:
space:
mode:
Diffstat (limited to 'py/misc.h')
-rw-r--r--py/misc.h105
1 files changed, 98 insertions, 7 deletions
diff --git a/py/misc.h b/py/misc.h
index 5d0893bbd..e03448583 100644
--- a/py/misc.h
+++ b/py/misc.h
@@ -33,10 +33,15 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
+#include <limits.h>
typedef unsigned char byte;
typedef unsigned int uint;
+#ifndef __has_builtin
+#define __has_builtin(x) (0)
+#endif
+
/** generic ops *************************************************/
#ifndef MIN
@@ -374,26 +379,23 @@ static inline bool mp_check(bool value) {
static inline uint32_t mp_popcount(uint32_t x) {
return __popcnt(x);
}
-#else
+#else // _MSC_VER
#define mp_clz(x) __builtin_clz(x)
#define mp_clzl(x) __builtin_clzl(x)
#define mp_clzll(x) __builtin_clzll(x)
#define mp_ctz(x) __builtin_ctz(x)
#define mp_check(x) (x)
-#if defined __has_builtin
#if __has_builtin(__builtin_popcount)
#define mp_popcount(x) __builtin_popcount(x)
-#endif
-#endif
-#if !defined(mp_popcount)
+#else
static inline uint32_t mp_popcount(uint32_t x) {
x = x - ((x >> 1) & 0x55555555);
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
x = (x + (x >> 4)) & 0x0F0F0F0F;
return (x * 0x01010101) >> 24;
}
-#endif
-#endif
+#endif // __has_builtin(__builtin_popcount)
+#endif // _MSC_VER
#define MP_FIT_UNSIGNED(bits, value) (((value) & (~0U << (bits))) == 0)
#define MP_FIT_SIGNED(bits, value) \
@@ -426,4 +428,93 @@ static inline uint32_t mp_clz_mpi(mp_int_t x) {
#endif
}
+// Overflow-checked operations for long long
+
+// Integer overflow builtins were added to GCC 5, but __has_builtin only in GCC 10
+//
+// Note that the builtins has a defined result when overflow occurs, whereas the custom
+// functions below don't update the result if an overflow would occur (to avoid UB).
+#define MP_GCC_HAS_BUILTIN_OVERFLOW (__GNUC__ >= 5)
+
+#if __has_builtin(__builtin_umulll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW
+#define mp_mul_ull_overflow __builtin_umulll_overflow
+#else
+inline static bool mp_mul_ull_overflow(unsigned long long int x, unsigned long long int y, unsigned long long int *res) {
+ if (y > 0 && x > (ULLONG_MAX / y)) {
+ return true; // overflow
+ }
+ *res = x * y;
+ return false;
+}
+#endif
+
+#if __has_builtin(__builtin_smulll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW
+#define mp_mul_ll_overflow __builtin_smulll_overflow
+#else
+inline static bool mp_mul_ll_overflow(long long int x, long long int y, long long int *res) {
+ bool overflow;
+
+ // Check for multiply overflow; see CERT INT32-C
+ if (x > 0) { // x is positive
+ if (y > 0) { // x and y are positive
+ overflow = (x > (LLONG_MAX / y));
+ } else { // x positive, y nonpositive
+ overflow = (y < (LLONG_MIN / x));
+ } // x positive, y nonpositive
+ } else { // x is nonpositive
+ if (y > 0) { // x is nonpositive, y is positive
+ overflow = (x < (LLONG_MIN / y));
+ } else { // x and y are nonpositive
+ overflow = (x != 0 && y < (LLONG_MAX / x));
+ } // End if x and y are nonpositive
+ } // End if x is nonpositive
+
+ if (!overflow) {
+ *res = x * y;
+ }
+
+ return overflow;
+}
+#endif
+
+#if __has_builtin(__builtin_saddll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW
+#define mp_add_ll_overflow __builtin_saddll_overflow
+#else
+inline static bool mp_add_ll_overflow(long long int lhs, long long int rhs, long long int *res) {
+ bool overflow;
+
+ if (rhs > 0) {
+ overflow = (lhs > LLONG_MAX - rhs);
+ } else {
+ overflow = (lhs < LLONG_MIN - rhs);
+ }
+
+ if (!overflow) {
+ *res = lhs + rhs;
+ }
+
+ return overflow;
+}
+#endif
+
+#if __has_builtin(__builtin_ssubll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW
+#define mp_sub_ll_overflow __builtin_ssubll_overflow
+#else
+inline static bool mp_sub_ll_overflow(long long int lhs, long long int rhs, long long int *res) {
+ bool overflow;
+
+ if (rhs > 0) {
+ overflow = (lhs < LLONG_MIN + rhs);
+ } else {
+ overflow = (lhs > LLONG_MAX + rhs);
+ }
+
+ if (!overflow) {
+ *res = lhs - rhs;
+ }
+
+ return overflow;
+}
+#endif
+
#endif // MICROPY_INCLUDED_PY_MISC_H