summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Gratton <angus@redyak.com.au>2025-05-02 15:39:35 +1000
committerDamien George <damien@micropython.org>2025-07-18 00:12:13 +1000
commite9845ab20ec798c1d5bf00bd3b64ff5d96d94500 (patch)
treea3cb1999eac4270ca29d1f8556be8491595e5b62
parent516aa02104c3344903bdda078b7c87f71f94938d (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.c4
-rw-r--r--py/runtime.c13
-rw-r--r--py/smallint.c5
-rw-r--r--py/smallint.h5
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);