py: Add MP_BINARY_OP_DIVMOD to simplify and consolidate divmod builtin.
This commit is contained in:
parent
6f49520042
commit
c5029bcbf3
2
py/bc0.h
2
py/bc0.h
@ -117,6 +117,6 @@
|
||||
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
|
||||
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
|
||||
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(6)
|
||||
#define MP_BC_BINARY_OP_MULTI (0xd6) // + op(35)
|
||||
#define MP_BC_BINARY_OP_MULTI (0xd6) // + op(36)
|
||||
|
||||
#endif // __MICROPY_INCLUDED_PY_BC0_H__
|
||||
|
@ -230,44 +230,7 @@ STATIC mp_obj_t mp_builtin_dir(mp_uint_t n_args, const mp_obj_t *args) {
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir);
|
||||
|
||||
STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
|
||||
// TODO handle big int
|
||||
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
|
||||
mp_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
|
||||
mp_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
|
||||
if (i2 == 0) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
zero_division_error:
|
||||
#endif
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
|
||||
}
|
||||
mp_obj_t args[2];
|
||||
args[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(i1, i2));
|
||||
args[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(i1, i2));
|
||||
return mp_obj_new_tuple(2, args);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
} else if (MP_OBJ_IS_TYPE(o1_in, &mp_type_float) || MP_OBJ_IS_TYPE(o2_in, &mp_type_float)) {
|
||||
mp_float_t f1 = mp_obj_get_float(o1_in);
|
||||
mp_float_t f2 = mp_obj_get_float(o2_in);
|
||||
if (f2 == 0.0) {
|
||||
goto zero_division_error;
|
||||
}
|
||||
mp_obj_float_divmod(&f1, &f2);
|
||||
mp_obj_t tuple[2] = {
|
||||
mp_obj_new_float(f1),
|
||||
mp_obj_new_float(f2),
|
||||
};
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
#endif
|
||||
} else {
|
||||
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
|
||||
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
|
||||
"unsupported operand type(s) for divmod()"));
|
||||
} else {
|
||||
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
|
||||
"unsupported operand type(s) for divmod(): '%s' and '%s'",
|
||||
mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
|
||||
}
|
||||
}
|
||||
return mp_binary_op(MP_BINARY_OP_DIVMOD, o1_in, o2_in);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj, mp_builtin_divmod);
|
||||
|
||||
|
1
py/obj.h
1
py/obj.h
@ -575,7 +575,6 @@ typedef struct _mp_obj_float_t {
|
||||
} mp_obj_float_t;
|
||||
mp_float_t mp_obj_float_get(mp_obj_t self_in);
|
||||
mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
|
||||
void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y);
|
||||
|
||||
// complex
|
||||
void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);
|
||||
|
@ -126,6 +126,41 @@ mp_float_t mp_obj_float_get(mp_obj_t self_in) {
|
||||
return self->value;
|
||||
}
|
||||
|
||||
STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
|
||||
// logic here follows that of CPython
|
||||
// https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
|
||||
// x == (x//y)*y + (x%y)
|
||||
// divmod(x, y) == (x//y, x%y)
|
||||
mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y);
|
||||
mp_float_t div = (*x - mod) / *y;
|
||||
|
||||
// Python specs require that mod has same sign as second operand
|
||||
if (mod == 0.0) {
|
||||
mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y);
|
||||
} else {
|
||||
if ((mod < 0.0) != (*y < 0.0)) {
|
||||
mod += *y;
|
||||
div -= 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
mp_float_t floordiv;
|
||||
if (div == 0.0) {
|
||||
// if division is zero, take the correct sign of zero
|
||||
floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y);
|
||||
} else {
|
||||
// Python specs require that x == (x//y)*y + (x%y)
|
||||
floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
|
||||
if (div - floordiv > 0.5) {
|
||||
floordiv += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// return results
|
||||
*x = floordiv;
|
||||
*y = mod;
|
||||
}
|
||||
|
||||
mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_in) {
|
||||
mp_float_t rhs_val = mp_obj_get_float(rhs_in); // can be any type, this function will convert to float (if possible)
|
||||
switch (op) {
|
||||
@ -170,6 +205,17 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i
|
||||
break;
|
||||
case MP_BINARY_OP_POWER:
|
||||
case MP_BINARY_OP_INPLACE_POWER: lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); break;
|
||||
case MP_BINARY_OP_DIVMOD: {
|
||||
if (rhs_val == 0) {
|
||||
goto zero_division_error;
|
||||
}
|
||||
mp_obj_float_divmod(&lhs_val, &rhs_val);
|
||||
mp_obj_t tuple[2] = {
|
||||
mp_obj_new_float(lhs_val),
|
||||
mp_obj_new_float(rhs_val),
|
||||
};
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
}
|
||||
case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val);
|
||||
case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val);
|
||||
case MP_BINARY_OP_EQUAL: return MP_BOOL(lhs_val == rhs_val);
|
||||
@ -182,39 +228,4 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i
|
||||
return mp_obj_new_float(lhs_val);
|
||||
}
|
||||
|
||||
void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
|
||||
// logic here follows that of CPython
|
||||
// https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
|
||||
// x == (x//y)*y + (x%y)
|
||||
// divmod(x, y) == (x//y, x%y)
|
||||
mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y);
|
||||
mp_float_t div = (*x - mod) / *y;
|
||||
|
||||
// Python specs require that mod has same sign as second operand
|
||||
if (mod == 0.0) {
|
||||
mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y);
|
||||
} else {
|
||||
if ((mod < 0.0) != (*y < 0.0)) {
|
||||
mod += *y;
|
||||
div -= 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
mp_float_t floordiv;
|
||||
if (div == 0.0) {
|
||||
// if division is zero, take the correct sign of zero
|
||||
floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y);
|
||||
} else {
|
||||
// Python specs require that x == (x//y)*y + (x%y)
|
||||
floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
|
||||
if (div - floordiv > 0.5) {
|
||||
floordiv += 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
// return results
|
||||
*x = floordiv;
|
||||
*y = mod;
|
||||
}
|
||||
|
||||
#endif // MICROPY_PY_BUILTINS_FLOAT
|
||||
|
@ -400,6 +400,7 @@ const qstr mp_binary_op_method_name[] = {
|
||||
/*
|
||||
MP_BINARY_OP_MODULO,
|
||||
MP_BINARY_OP_POWER,
|
||||
MP_BINARY_OP_DIVMOD,
|
||||
MP_BINARY_OP_INPLACE_OR,
|
||||
MP_BINARY_OP_INPLACE_XOR,
|
||||
MP_BINARY_OP_INPLACE_AND,
|
||||
|
11
py/runtime.c
11
py/runtime.c
@ -441,6 +441,17 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||
lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs));
|
||||
goto generic_binary_op;
|
||||
|
||||
case MP_BINARY_OP_DIVMOD: {
|
||||
if (rhs_val == 0) {
|
||||
goto zero_division;
|
||||
}
|
||||
// to reduce stack usage we don't pass a temp array of the 2 items
|
||||
mp_obj_tuple_t *tuple = mp_obj_new_tuple(2, NULL);
|
||||
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(lhs_val, rhs_val));
|
||||
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(lhs_val, rhs_val));
|
||||
return tuple;
|
||||
}
|
||||
|
||||
case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break;
|
||||
case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break;
|
||||
case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break;
|
||||
|
@ -74,29 +74,30 @@ typedef enum {
|
||||
|
||||
MP_BINARY_OP_MODULO,
|
||||
MP_BINARY_OP_POWER,
|
||||
MP_BINARY_OP_DIVMOD, // not emitted by the compiler but supported by the runtime
|
||||
MP_BINARY_OP_INPLACE_OR,
|
||||
MP_BINARY_OP_INPLACE_XOR,
|
||||
MP_BINARY_OP_INPLACE_AND,
|
||||
|
||||
MP_BINARY_OP_INPLACE_AND,
|
||||
MP_BINARY_OP_INPLACE_LSHIFT,
|
||||
MP_BINARY_OP_INPLACE_RSHIFT,
|
||||
MP_BINARY_OP_INPLACE_ADD,
|
||||
MP_BINARY_OP_INPLACE_SUBTRACT,
|
||||
MP_BINARY_OP_INPLACE_MULTIPLY,
|
||||
|
||||
MP_BINARY_OP_INPLACE_MULTIPLY,
|
||||
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
|
||||
MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
|
||||
MP_BINARY_OP_INPLACE_MODULO,
|
||||
MP_BINARY_OP_INPLACE_POWER,
|
||||
|
||||
// these should return a bool
|
||||
MP_BINARY_OP_LESS,
|
||||
|
||||
MP_BINARY_OP_MORE,
|
||||
MP_BINARY_OP_EQUAL,
|
||||
MP_BINARY_OP_LESS_EQUAL,
|
||||
MP_BINARY_OP_MORE_EQUAL,
|
||||
MP_BINARY_OP_NOT_EQUAL,
|
||||
|
||||
MP_BINARY_OP_NOT_EQUAL,
|
||||
MP_BINARY_OP_IN,
|
||||
MP_BINARY_OP_IS,
|
||||
MP_BINARY_OP_EXCEPTION_MATCH,
|
||||
|
2
py/vm.c
2
py/vm.c
@ -1199,7 +1199,7 @@ yield:
|
||||
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 6) {
|
||||
SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));
|
||||
DISPATCH();
|
||||
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 35) {
|
||||
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) {
|
||||
mp_obj_t rhs = POP();
|
||||
mp_obj_t lhs = TOP();
|
||||
SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));
|
||||
|
@ -112,7 +112,7 @@ static void* entry_table[256] = {
|
||||
[MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI,
|
||||
[MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI,
|
||||
[MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + 5] = &&entry_MP_BC_UNARY_OP_MULTI,
|
||||
[MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 34] = &&entry_MP_BC_BINARY_OP_MULTI,
|
||||
[MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 35] = &&entry_MP_BC_BINARY_OP_MULTI,
|
||||
};
|
||||
|
||||
#if __clang__
|
||||
|
@ -93,21 +93,21 @@ arg names:
|
||||
69 LOAD_DEREF 14
|
||||
71 DUP_TOP
|
||||
72 ROT_THREE
|
||||
73 BINARY_OP 26 __eq__
|
||||
73 BINARY_OP 27 __eq__
|
||||
74 JUMP_IF_FALSE_OR_POP 82
|
||||
77 LOAD_FAST 1
|
||||
78 BINARY_OP 26 __eq__
|
||||
78 BINARY_OP 27 __eq__
|
||||
79 JUMP 84
|
||||
82 ROT_TWO
|
||||
83 POP_TOP
|
||||
84 STORE_FAST 10
|
||||
85 LOAD_FAST 0
|
||||
86 LOAD_DEREF 14
|
||||
88 BINARY_OP 26 __eq__
|
||||
88 BINARY_OP 27 __eq__
|
||||
89 JUMP_IF_FALSE_OR_POP 96
|
||||
92 LOAD_DEREF 14
|
||||
94 LOAD_FAST 1
|
||||
95 BINARY_OP 26 __eq__
|
||||
95 BINARY_OP 27 __eq__
|
||||
96 UNARY_OP 0
|
||||
97 NOT
|
||||
98 STORE_FAST 10
|
||||
|
Loading…
x
Reference in New Issue
Block a user