diff options
author | Angus Gratton <angus@redyak.com.au> | 2025-05-02 15:39:35 +1000 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2025-07-18 00:12:13 +1000 |
commit | e9845ab20ec798c1d5bf00bd3b64ff5d96d94500 (patch) | |
tree | a3cb1999eac4270ca29d1f8556be8491595e5b62 | |
parent | 516aa02104c3344903bdda078b7c87f71f94938d (diff) |
py/smallint: Update mp_small_int_mul_overflow() to perform the multiply.
Makes it compatible with the __builtin_mul_overflow() syntax, used in
follow-up commit.
Includes optimisation in runtime.c to minimise the code size impact from
additional param.
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Angus Gratton <angus@redyak.com.au>
-rw-r--r-- | py/parsenum.c | 4 | ||||
-rw-r--r-- | py/runtime.c | 13 | ||||
-rw-r--r-- | py/smallint.c | 5 | ||||
-rw-r--r-- | py/smallint.h | 5 |
4 files changed, 17 insertions, 10 deletions
diff --git a/py/parsenum.c b/py/parsenum.c index 7e6695fbf..31b332c18 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -99,10 +99,10 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m } // add next digi and check for overflow - if (mp_small_int_mul_overflow(int_val, base)) { + if (mp_small_int_mul_overflow(int_val, base, &int_val)) { goto overflow; } - int_val = int_val * base + dig; + int_val += dig; if (!MP_SMALL_INT_FITS(int_val)) { goto overflow; } diff --git a/py/runtime.c b/py/runtime.c index 90587a010..0ab0626ef 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -505,13 +505,14 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs } #endif - if (mp_small_int_mul_overflow(lhs_val, rhs_val)) { + mp_int_t int_res; + if (mp_small_int_mul_overflow(lhs_val, rhs_val, &int_res)) { // use higher precision lhs = mp_obj_new_int_from_ll(lhs_val); goto generic_binary_op; } else { // use standard precision - return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); + return MP_OBJ_NEW_SMALL_INT(int_res); } } case MP_BINARY_OP_FLOOR_DIVIDE: @@ -552,19 +553,19 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs mp_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { - if (mp_small_int_mul_overflow(ans, lhs_val)) { + if (mp_small_int_mul_overflow(ans, lhs_val, &ans)) { goto power_overflow; } - ans *= lhs_val; } if (rhs_val == 1) { break; } rhs_val /= 2; - if (mp_small_int_mul_overflow(lhs_val, lhs_val)) { + mp_int_t int_res; + if (mp_small_int_mul_overflow(lhs_val, lhs_val, &int_res)) { goto power_overflow; } - lhs_val *= lhs_val; + lhs_val = int_res; } lhs_val = ans; } diff --git a/py/smallint.c b/py/smallint.c index aa542ca7b..a494093d6 100644 --- a/py/smallint.c +++ b/py/smallint.c @@ -26,7 +26,7 @@ #include "py/smallint.h" -bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) { +bool mp_small_int_mul_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 if (y > 0) { // x and y are positive @@ -49,6 +49,9 @@ bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) { } } // End if x and y are nonpositive } // End if x is nonpositive + + // Result doesn't overflow + *res = x * y; return false; } diff --git a/py/smallint.h b/py/smallint.h index 584e0018d..e50f98651 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -68,7 +68,10 @@ // The number of bits in a MP_SMALL_INT including the sign bit. #define MP_SMALL_INT_BITS (MP_IMAX_BITS(MP_SMALL_INT_MAX) + 1) -bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y); +// Multiply two small ints. +// If returns false, the correct result is stored in 'res' +// If returns true, the multiplication would have overflowed. 'res' is unchanged. +bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y, mp_int_t *res); mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor); mp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom); |