core: Introduce mp_obj_new_long_ll.

Since #9531 a few ways remained to produce long ints that were
not reduced to small ints.

Explicitly introduce "mp_obj_new_long_from_ll" and make
the "new_int" functions always produce small ints when possible.

At sites where a long int is really intended (or will
eventually be reduced to a small int if the result fits),
the called function is changed to be the new _long_ function.

Signed-off-by: Jeff Epler <jepler@gmail.com>
This commit is contained in:
Jeff Epler 2025-07-28 21:04:37 -05:00
parent c68d8ac358
commit decc0c75a7
6 changed files with 52 additions and 26 deletions

View file

@ -527,9 +527,9 @@ static mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%f\n", mpz_as_float(&mpz)); mp_printf(&mp_plat_print, "%f\n", mpz_as_float(&mpz));
// convert a large integer value (stored in a mpz) to mp_uint_t and to ll; // convert a large integer value (stored in a mpz) to mp_uint_t and to ll;
mp_obj_t obj_bigint = mp_obj_new_int_from_uint((mp_uint_t)0xdeadbeef); mp_obj_t obj_bigint = mp_obj_new_int_from_ull((unsigned long long)0xdeadbeef);
mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint));
obj_bigint = mp_obj_new_int_from_ll(0xc0ffee777c0ffeell); obj_bigint = mp_obj_new_long_from_ll(0xc0ffee777c0ffeell);
long long value_ll = mp_obj_get_ll(obj_bigint); long long value_ll = mp_obj_get_ll(obj_bigint);
mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll);
@ -541,7 +541,7 @@ static mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll);
// convert a smaller integer value to mp_uint_t and to ll // convert a smaller integer value to mp_uint_t and to ll
obj_bigint = mp_obj_new_int_from_uint(0xc0ffee); obj_bigint = mp_obj_new_int_from_ull(0xc0ffeeull);
mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint));
value_ll = mp_obj_get_ll(obj_bigint); value_ll = mp_obj_get_ll(obj_bigint);
mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll);
@ -568,7 +568,7 @@ static mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(1))); mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(1)));
// mp_obj_int_get_uint_checked with non-negative big-int // mp_obj_int_get_uint_checked with non-negative big-int
mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(mp_obj_new_int_from_ll(2))); mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(mp_obj_new_long_from_ll(2)));
// mp_obj_int_get_uint_checked with negative small-int (should raise exception) // mp_obj_int_get_uint_checked with negative small-int (should raise exception)
nlr_buf_t nlr; nlr_buf_t nlr;
@ -581,7 +581,7 @@ static mp_obj_t extra_coverage(void) {
// mp_obj_int_get_uint_checked with negative big-int (should raise exception) // mp_obj_int_get_uint_checked with negative big-int (should raise exception)
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_obj_int_get_uint_checked(mp_obj_new_int_from_ll(-2)); mp_obj_int_get_uint_checked(mp_obj_new_long_from_ll(-2));
nlr_pop(); nlr_pop();
} else { } else {
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
@ -853,12 +853,12 @@ static mp_obj_t extra_coverage(void) {
mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_bool(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_bool(mp_const_none)); mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_bool(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_bool(mp_const_none));
// mp_obj_is_integer accepts ints and booleans // mp_obj_is_integer accepts ints and booleans
mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_integer(mp_obj_new_int_from_ll(1))); mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_integer(mp_obj_new_long_from_ll(1)));
mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_const_true), mp_obj_is_integer(mp_const_false)); mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_const_true), mp_obj_is_integer(mp_const_false));
mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_obj_new_str_from_cstr("1")), mp_obj_is_integer(mp_const_none)); mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_integer(mp_obj_new_str_from_cstr("1")), mp_obj_is_integer(mp_const_none));
// mp_obj_is_int accepts small int and object ints // mp_obj_is_int accepts small int and object ints
mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_int(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_int(mp_obj_new_int_from_ll(1))); mp_printf(&mp_plat_print, "%d %d\n", mp_obj_is_int(MP_OBJ_NEW_SMALL_INT(1)), mp_obj_is_int(mp_obj_new_long_from_ll(1)));
} }
// Legacy stackctrl.h API, this has been replaced by cstack.h // Legacy stackctrl.h API, this has been replaced by cstack.h

View file

@ -994,8 +994,9 @@ mp_obj_t mp_obj_new_cell(mp_obj_t obj);
mp_obj_t mp_obj_new_int(mp_int_t value); mp_obj_t mp_obj_new_int(mp_int_t value);
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value);
mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base); mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base);
mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ll(long long val); // returns a small int if value fits
mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // returns a small int if value fits
mp_obj_t mp_obj_new_long_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception)
mp_obj_t mp_obj_new_str(const char *data, size_t len); // will check utf-8 (raises UnicodeError) mp_obj_t mp_obj_new_str(const char *data, size_t len); // will check utf-8 (raises UnicodeError)
mp_obj_t mp_obj_new_str_from_cstr(const char *str); // // accepts null-terminated string, will check utf-8 (raises UnicodeError) mp_obj_t mp_obj_new_str_from_cstr(const char *str); // // accepts null-terminated string, will check utf-8 (raises UnicodeError)
mp_obj_t mp_obj_new_str_via_qstr(const char *data, size_t len); // input data must be valid utf-8 mp_obj_t mp_obj_new_str_via_qstr(const char *data, size_t len); // input data must be valid utf-8

View file

@ -326,7 +326,13 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i
// This is called only with strings whose value doesn't fit in SMALL_INT // This is called only with strings whose value doesn't fit in SMALL_INT
mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) {
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("long int not supported in this build")); mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow"));
return mp_const_none;
}
// This is called when an integer larger than a SMALL_INT is needed (although val might still fit in a SMALL_INT)
mp_obj_t mp_obj_new_long_from_ll(long long val) {
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow"));
return mp_const_none; return mp_const_none;
} }

View file

@ -298,14 +298,18 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
return mp_obj_new_int_from_ll(value); return mp_obj_new_int_from_ll(value);
} }
mp_obj_t mp_obj_new_long_from_ll(long long val) {
mp_obj_int_t *o = mp_obj_malloc(mp_obj_int_t, &mp_type_int);
o->val = val;
return MP_OBJ_FROM_PTR(o);
}
mp_obj_t mp_obj_new_int_from_ll(long long val) { mp_obj_t mp_obj_new_int_from_ll(long long val) {
if ((long long)(mp_int_t)val == val && MP_SMALL_INT_FITS(val)) { if ((long long)(mp_int_t)val == val && MP_SMALL_INT_FITS(val)) {
return MP_OBJ_NEW_SMALL_INT(val); return MP_OBJ_NEW_SMALL_INT(val);
} }
mp_obj_int_t *o = mp_obj_malloc(mp_obj_int_t, &mp_type_int); return mp_obj_new_long_from_ll(val);
o->val = val;
return MP_OBJ_FROM_PTR(o);
} }
mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {

View file

@ -382,23 +382,38 @@ mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) {
} }
#endif #endif
// This routine *always* returns an mpz integer. Call it only if the value is *known*
// to exceed the small integer range, because integers that fit are required to always
// be returned as small integers.
static mp_obj_t mp_obj_new_mpz_from_ll(long long val, bool is_signed) {
mp_obj_int_t *o = mp_obj_int_new_mpz();
mpz_set_from_ll(&o->mpz, val, is_signed);
return MP_OBJ_FROM_PTR(o);
}
mp_obj_t mp_obj_new_long_from_ll(long long val) {
return mp_obj_new_mpz_from_ll(val, true);
}
mp_obj_t mp_obj_new_int(mp_int_t value) { mp_obj_t mp_obj_new_int(mp_int_t value) {
if (MP_SMALL_INT_FITS(value)) { if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value); return MP_OBJ_NEW_SMALL_INT(value);
} }
return mp_obj_new_int_from_ll(value); return mp_obj_new_mpz_from_ll(value, true);
} }
mp_obj_t mp_obj_new_int_from_ll(long long val) { mp_obj_t mp_obj_new_int_from_ll(long long val) {
mp_obj_int_t *o = mp_obj_int_new_mpz(); if (val == (mp_int_t)val && MP_SMALL_INT_FITS((mp_int_t)val)) {
mpz_set_from_ll(&o->mpz, val, true); return MP_OBJ_NEW_SMALL_INT(val);
return MP_OBJ_FROM_PTR(o); }
return mp_obj_new_mpz_from_ll(val, true);
} }
mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {
mp_obj_int_t *o = mp_obj_int_new_mpz(); if ((val & ~(unsigned long long)MP_SMALL_INT_POSITIVE_MASK) == 0) {
mpz_set_from_ll(&o->mpz, val, false); return mp_obj_new_int(val);
return MP_OBJ_FROM_PTR(o); }
return mp_obj_new_mpz_from_ll(val, false);
} }
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
@ -407,7 +422,7 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) { if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) {
return MP_OBJ_NEW_SMALL_INT(value); return MP_OBJ_NEW_SMALL_INT(value);
} }
return mp_obj_new_int_from_ull(value); return mp_obj_new_mpz_from_ll(value, false);
} }
mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) {

View file

@ -456,7 +456,7 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs
|| lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val > (MP_SMALL_INT_MAX >> rhs_val)
|| lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) { || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) {
// left-shift will overflow, so use higher precision integer // left-shift will overflow, so use higher precision integer
lhs = mp_obj_new_int_from_ll(lhs_val); lhs = mp_obj_new_long_from_ll(lhs_val);
goto generic_binary_op; goto generic_binary_op;
} else { } else {
// use standard precision // use standard precision
@ -498,7 +498,7 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs
long long res = (long long)lhs_val * (long long)rhs_val; long long res = (long long)lhs_val * (long long)rhs_val;
if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) { if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) {
// result overflowed SMALL_INT, so return higher precision integer // result overflowed SMALL_INT, so return higher precision integer
return mp_obj_new_int_from_ll(res); return mp_obj_new_long_from_ll(res);
} else { } else {
// use standard precision // use standard precision
lhs_val = (mp_int_t)res; lhs_val = (mp_int_t)res;
@ -508,7 +508,7 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs
mp_int_t int_res; mp_int_t int_res;
if (mp_small_int_mul_overflow(lhs_val, rhs_val, &int_res)) { if (mp_small_int_mul_overflow(lhs_val, rhs_val, &int_res)) {
// use higher precision // use higher precision
lhs = mp_obj_new_int_from_ll(lhs_val); lhs = mp_obj_new_long_from_ll(lhs_val);
goto generic_binary_op; goto generic_binary_op;
} else { } else {
// use standard precision // use standard precision
@ -573,7 +573,7 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs
power_overflow: power_overflow:
// use higher precision // use higher precision
lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs)); lhs = mp_obj_new_long_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs));
goto generic_binary_op; goto generic_binary_op;
case MP_BINARY_OP_DIVMOD: { case MP_BINARY_OP_DIVMOD: {
@ -603,7 +603,7 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs
if (MP_SMALL_INT_FITS(lhs_val)) { if (MP_SMALL_INT_FITS(lhs_val)) {
return MP_OBJ_NEW_SMALL_INT(lhs_val); return MP_OBJ_NEW_SMALL_INT(lhs_val);
} else { } else {
return mp_obj_new_int_from_ll(lhs_val); return mp_obj_new_long_from_ll(lhs_val);
} }
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
} else if (mp_obj_is_float(rhs)) { } else if (mp_obj_is_float(rhs)) {