diff options
| author | Jeff Epler <jepler@unpythonic.net> | 2025-10-11 19:12:55 -0500 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2025-10-23 15:12:28 +1100 |
| commit | 007f127a61ea058ca010b85883072bdefe0234c0 (patch) | |
| tree | f39d63b4cdc67ff1374b4e774511e9bb07718c58 /py | |
| parent | eac81de4e0a462dd8121f93b42271774ced3c85f (diff) | |
all: Simplify mp_int_t/mp_uint_t definition.
Assuming proper C99 language support, we can select "the int type as big as
a pointer" (most of the time) or "the 64-bit int type" (nanboxing with
REPR_D), and then define everything else automatically.
This simplifies port configuration files. And the types can still be
overridden if needed.
Signed-off-by: Jeff Epler <jepler@unpythonic.net>
Diffstat (limited to 'py')
| -rw-r--r-- | py/misc.h | 18 | ||||
| -rw-r--r-- | py/mpconfig.h | 103 | ||||
| -rw-r--r-- | py/mpprint.c | 4 | ||||
| -rw-r--r-- | py/runtime_utils.c | 4 |
4 files changed, 92 insertions, 37 deletions
@@ -456,15 +456,15 @@ static inline uint32_t mp_clz_mpi(mp_int_t x) { } return zeroes; #else - MP_STATIC_ASSERT(sizeof(mp_int_t) == sizeof(long long) - || sizeof(mp_int_t) == sizeof(long)); - - // ugly, but should compile to single intrinsic unless O0 is set - if (mp_check(sizeof(mp_int_t) == sizeof(long))) { - return mp_clzl((unsigned long)x); - } else { - return mp_clzll((unsigned long long)x); - } + #if MP_INT_MAX == INT_MAX + return mp_clz((unsigned)x); + #elif MP_INT_MAX == LONG_MAX + return mp_clzl((unsigned long)x); + #elif MP_INT_MAX == LLONG_MAX + return mp_clzll((unsigned long long)x); + #else + #error Unexpected MP_INT_MAX value + #endif #endif } diff --git a/py/mpconfig.h b/py/mpconfig.h index 6da872c56..6ad27c51f 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -26,6 +26,15 @@ #ifndef MICROPY_INCLUDED_PY_MPCONFIG_H #define MICROPY_INCLUDED_PY_MPCONFIG_H +#include <stdint.h> + +#if defined(__cplusplus) // Required on at least one compiler to get ULLONG_MAX +#include <climits> +#else +#include <limits.h> +#endif + + // Current version of MicroPython. This is used by sys.implementation.version // as well as a fallback to generate MICROPY_GIT_TAG if the git repo or tags // are unavailable. @@ -161,6 +170,78 @@ #define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D) #endif +// Definition of the `mp_int_t` and `mp_uint_t` types and associated macros. +// Normally, it suffices for the platform to do nothing: A type as wide +// as a pointer is chosen, unless nanboxing (REPR_D) is selected, in +// which case a 64-bit type is chosen to match the assumed size of +// double-precision floats. +// +// In the case of exceptions, the port, board, or variant must define +// MP_INT_TYPE as MP_INT_TYPE_OTHER and provide all the typedefs and +// defines. +#define MP_INT_TYPE_INTPTR (0) +#define MP_INT_TYPE_INT64 (1) +#define MP_INT_TYPE_OTHER (2) + +#if !defined(MP_INT_TYPE) +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +#define MP_INT_TYPE (MP_INT_TYPE_INT64) +#else +#define MP_INT_TYPE (MP_INT_TYPE_INTPTR) +#endif +#endif + +#if MP_INT_TYPE == MP_INT_TYPE_INTPTR +typedef intptr_t mp_int_t; +typedef uintptr_t mp_uint_t; +#define MP_INT_MAX INTPTR_MAX +#define MP_INT_MIN INTPTR_MIN +#define MP_UINT_MAX INTPTR_UMAX +#elif MP_INT_TYPE == MP_INT_TYPE_INT64 +typedef int64_t mp_int_t; +typedef uint64_t mp_uint_t; +#define MP_INT_MAX INT64_MAX +#define MP_INT_MIN INT64_MIN +#define MP_UINT_MAX INT64_UMAX +#endif + +// mp_printf format support for mp_int_t. In the unusual case that MP_INT_MAX doesn't +// match any of the standard C types (int/long/long long), provide all 3 +// macros. Otherwise, rely on these automatic definitions. +#if !defined(INT_FMT) +#if MP_INT_MAX == INT_MAX +#define INT_FMT "%d" +#define UINT_FMT "%u" +#define HEX_FMT "%x" +#elif MP_INT_MAX == LONG_MAX +#define INT_FMT "%ld" +#define UINT_FMT "%lu" +#define HEX_FMT "%lx" +#elif MP_INT_MAX == LLONG_MAX +#define INT_FMT "%lld" +#define UINT_FMT "%llu" +#define HEX_FMT "%llx" +#else +#error Unexpected MP_INT_MAX value +#endif +#endif + +// mp_printf format support for size_t. In the unusual case that SIZE_MAX doesn't +// match any of the standard C types (int/long/long long), provide a +// macro. Otherwise, rely on these automatic definitions. +#if !defined(SIZE_FMT) +#if SIZE_MAX == UINT_MAX +#define SIZE_FMT "%u" +#elif SIZE_MAX == ULONG_MAX +#define SIZE_FMT "%lu" +#elif SIZE_MAX == ULLONG_MAX +#define SIZE_FMT "%llu" +#else +#error Unexpected SIZE_MAX value +#endif +#endif + + /*****************************************************************************/ /* Memory allocation policy */ @@ -2237,28 +2318,6 @@ typedef time_t mp_timestamp_t; #define MP_SSIZE_MAX SSIZE_MAX #endif -// printf format spec to use for mp_int_t and friends -#ifndef INT_FMT -#if defined(__LP64__) -// Archs where mp_int_t == long, long != int -#define UINT_FMT "%lu" -#define INT_FMT "%ld" -#define HEX_FMT "%lx" -#define SIZE_FMT "%lu" -#elif defined(_WIN64) -#define UINT_FMT "%llu" -#define INT_FMT "%lld" -#define HEX_FMT "%llx" -#define SIZE_FMT "%llu" -#else -// Archs where mp_int_t == int -#define UINT_FMT "%u" -#define INT_FMT "%d" -#define HEX_FMT "%x" -#define SIZE_FMT "%u" -#endif -#endif // INT_FMT - // Modifier for function which doesn't return #ifndef MP_NORETURN #define MP_NORETURN __attribute__((noreturn)) diff --git a/py/mpprint.c b/py/mpprint.c index 89b3dbd76..fa37a4d07 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -482,7 +482,7 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } // parse long and long long specifiers (only where they make a difference) - #if defined(MICROPY_UNIX_COVERAGE) || (LONG_MAX > INT_MAX) + #if (MP_INT_MAX > INT_MAX && MP_INT_MAX == LONG_MAX) || defined(MICROPY_UNIX_COVERAGE) #define SUPPORT_L_FORMAT (1) #else #define SUPPORT_L_FORMAT (0) @@ -491,7 +491,7 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { bool long_arg = false; #endif - #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64) || defined(MICROPY_UNIX_COVERAGE) + #if (MP_INT_MAX > LONG_MAX) || defined(MICROPY_UNIX_COVERAGE) #define SUPPORT_LL_FORMAT (1) #else #define SUPPORT_LL_FORMAT (0) diff --git a/py/runtime_utils.c b/py/runtime_utils.c index 50526b210..3b0ae279a 100644 --- a/py/runtime_utils.c +++ b/py/runtime_utils.c @@ -77,10 +77,6 @@ bool mp_mul_ll_overflow(long long int x, long long int y, long long int *res) { return overflow; } -#define MP_UINT_MAX (~(mp_uint_t)0) -#define MP_INT_MAX ((mp_int_t)(MP_UINT_MAX >> 1)) -#define MP_INT_MIN (-MP_INT_MAX - 1) - bool mp_mul_mp_int_t_overflow(mp_int_t x, mp_int_t y, mp_int_t *res) { // Check for multiply overflow; see CERT INT32-C if (x > 0) { // x is positive |
