From e9845ab20ec798c1d5bf00bd3b64ff5d96d94500 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Fri, 2 May 2025 15:39:35 +1000 Subject: [PATCH] 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 Signed-off-by: Angus Gratton --- py/parsenum.c | 4 ++-- py/runtime.c | 13 +++++++------ py/smallint.c | 5 ++++- py/smallint.h | 5 ++++- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/py/parsenum.c b/py/parsenum.c index 7e6695fbfc..31b332c180 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 90587a010a..0ab0626ef9 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 aa542ca7bf..a494093d61 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 584e0018d1..e50f98651e 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);