From 9aa2a527b532e31c77592cede3b38c018c83ac64 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 1 Feb 2014 23:04:09 +0000 Subject: [PATCH] py: Tidy up BINARY_OPs; negation done by special NOT bytecode. IS_NOT and NOT_IN are now compiled to IS + NOT and IN + NOT, with a new special NOT bytecode. --- py/bc0.h | 5 +++-- py/compile.c | 42 ++++++++++++++---------------------------- py/emitbc.c | 23 +++++++++++++++++++++-- py/emitcpy.c | 24 ++++++++++++------------ py/emitnative.c | 2 +- py/obj.c | 4 ++-- py/objdict.c | 7 +++---- py/objfloat.c | 8 ++++---- py/objint_longlong.c | 12 ++++++------ py/objlist.c | 32 ++++++++++++++++---------------- py/objset.c | 17 ++++++++--------- py/objstr.c | 5 ++--- py/objtype.c | 21 ++++++++++----------- py/runtime.c | 34 +++++++++++++++------------------- py/runtime0.h | 27 ++++++++++++++------------- py/showbc.c | 8 +++++--- py/vm.c | 8 ++++++++ 17 files changed, 144 insertions(+), 135 deletions(-) diff --git a/py/bc0.h b/py/bc0.h index 37c0bf7bb5..2c8c47bd2e 100644 --- a/py/bc0.h +++ b/py/bc0.h @@ -63,8 +63,9 @@ #define MP_BC_POP_EXCEPT (0x55) #define MP_BC_UNWIND_JUMP (0x56) // rel byte code offset, 16-bit signed, in excess; then a byte -#define MP_BC_UNARY_OP (0x60) // byte -#define MP_BC_BINARY_OP (0x61) // byte +#define MP_BC_NOT (0x60) +#define MP_BC_UNARY_OP (0x61) // byte +#define MP_BC_BINARY_OP (0x62) // byte #define MP_BC_BUILD_TUPLE (0x70) // uint #define MP_BC_BUILD_LIST (0x71) // uint diff --git a/py/compile.c b/py/compile.c index 5a2ef0b5c4..47741b8da8 100644 --- a/py/compile.c +++ b/py/compile.c @@ -1466,9 +1466,9 @@ void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t pn_var, compile_node(comp, pn_var); compile_node(comp, pn_end); if (MP_PARSE_NODE_LEAF_ARG(pn_step) >= 0) { - EMIT_ARG(binary_op, RT_COMPARE_OP_LESS); + EMIT_ARG(binary_op, RT_BINARY_OP_LESS); } else { - EMIT_ARG(binary_op, RT_COMPARE_OP_MORE); + EMIT_ARG(binary_op, RT_BINARY_OP_MORE); } EMIT_ARG(pop_jump_if_true, top_label); @@ -1605,7 +1605,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, } EMIT(dup_top); compile_node(comp, pns_exception_expr); - EMIT_ARG(binary_op, RT_COMPARE_OP_EXCEPTION_MATCH); + EMIT_ARG(binary_op, RT_BINARY_OP_EXCEPTION_MATCH); EMIT_ARG(pop_jump_if_false, end_finally_label); } @@ -1912,21 +1912,7 @@ void compile_and_test(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_not_test_2(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pns->nodes[0]); -#if MICROPY_EMIT_CPYTHON EMIT_ARG(unary_op, RT_UNARY_OP_NOT); -#else - // eliminate use of NOT byte code - int l_load_false = comp_next_label(comp); - int l_done = comp_next_label(comp); - int stack_size = EMIT(get_stack_size); - EMIT_ARG(pop_jump_if_true, l_load_false); - EMIT_ARG(load_const_tok, MP_TOKEN_KW_TRUE); - EMIT_ARG(jump, l_done); - EMIT_ARG(label_assign, l_load_false); - EMIT_ARG(load_const_tok, MP_TOKEN_KW_FALSE); - EMIT_ARG(label_assign, l_done); - EMIT_ARG(set_stack_size, stack_size); // force stack size since it counts 1 pop and 2 pushes statically, but really it's 1 pop and 1 push dynamically -#endif } void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -1947,26 +1933,26 @@ void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { if (MP_PARSE_NODE_IS_TOKEN(pns->nodes[i])) { rt_binary_op_t op; switch (MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])) { - case MP_TOKEN_OP_LESS: op = RT_COMPARE_OP_LESS; break; - case MP_TOKEN_OP_MORE: op = RT_COMPARE_OP_MORE; break; - case MP_TOKEN_OP_DBL_EQUAL: op = RT_COMPARE_OP_EQUAL; break; - case MP_TOKEN_OP_LESS_EQUAL: op = RT_COMPARE_OP_LESS_EQUAL; break; - case MP_TOKEN_OP_MORE_EQUAL: op = RT_COMPARE_OP_MORE_EQUAL; break; - case MP_TOKEN_OP_NOT_EQUAL: op = RT_COMPARE_OP_NOT_EQUAL; break; - case MP_TOKEN_KW_IN: op = RT_COMPARE_OP_IN; break; - default: assert(0); op = RT_COMPARE_OP_LESS; // shouldn't happen + case MP_TOKEN_OP_LESS: op = RT_BINARY_OP_LESS; break; + case MP_TOKEN_OP_MORE: op = RT_BINARY_OP_MORE; break; + case MP_TOKEN_OP_DBL_EQUAL: op = RT_BINARY_OP_EQUAL; break; + case MP_TOKEN_OP_LESS_EQUAL: op = RT_BINARY_OP_LESS_EQUAL; break; + case MP_TOKEN_OP_MORE_EQUAL: op = RT_BINARY_OP_MORE_EQUAL; break; + case MP_TOKEN_OP_NOT_EQUAL: op = RT_BINARY_OP_NOT_EQUAL; break; + case MP_TOKEN_KW_IN: op = RT_BINARY_OP_IN; break; + default: assert(0); op = RT_BINARY_OP_LESS; // shouldn't happen } EMIT_ARG(binary_op, op); } else if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[i])) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[i]; int kind = MP_PARSE_NODE_STRUCT_KIND(pns2); if (kind == PN_comp_op_not_in) { - EMIT_ARG(binary_op, RT_COMPARE_OP_NOT_IN); + EMIT_ARG(binary_op, RT_BINARY_OP_NOT_IN); } else if (kind == PN_comp_op_is) { if (MP_PARSE_NODE_IS_NULL(pns2->nodes[0])) { - EMIT_ARG(binary_op, RT_COMPARE_OP_IS); + EMIT_ARG(binary_op, RT_BINARY_OP_IS); } else { - EMIT_ARG(binary_op, RT_COMPARE_OP_IS_NOT); + EMIT_ARG(binary_op, RT_BINARY_OP_IS_NOT); } } else { // shouldn't happen diff --git a/py/emitbc.c b/py/emitbc.c index a76e593363..e22a8b47ae 100644 --- a/py/emitbc.c +++ b/py/emitbc.c @@ -600,13 +600,32 @@ static void emit_bc_pop_except(emit_t *emit) { } static void emit_bc_unary_op(emit_t *emit, rt_unary_op_t op) { - emit_pre(emit, 0); - emit_write_byte_code_byte_byte(emit, MP_BC_UNARY_OP, op); + if (op == RT_UNARY_OP_NOT) { + emit_pre(emit, 0); + emit_write_byte_code_byte_byte(emit, MP_BC_UNARY_OP, RT_UNARY_OP_BOOL); + emit_pre(emit, 0); + emit_write_byte_code_byte(emit, MP_BC_NOT); + } else { + emit_pre(emit, 0); + emit_write_byte_code_byte_byte(emit, MP_BC_UNARY_OP, op); + } } static void emit_bc_binary_op(emit_t *emit, rt_binary_op_t op) { + bool invert = false; + if (op == RT_BINARY_OP_NOT_IN) { + invert = true; + op = RT_BINARY_OP_IN; + } else if (op == RT_BINARY_OP_IS_NOT) { + invert = true; + op = RT_BINARY_OP_IS; + } emit_pre(emit, -1); emit_write_byte_code_byte_byte(emit, MP_BC_BINARY_OP, op); + if (invert) { + emit_pre(emit, 0); + emit_write_byte_code_byte(emit, MP_BC_NOT); + } } static void emit_bc_build_tuple(emit_t *emit, int n_args) { diff --git a/py/emitcpy.c b/py/emitcpy.c index 1e507a5819..bf8abd1c93 100644 --- a/py/emitcpy.c +++ b/py/emitcpy.c @@ -545,10 +545,10 @@ static void emit_cpy_unary_op(emit_t *emit, rt_unary_op_t op) { emit_pre(emit, 0, 1); if (emit->pass == PASS_3) { switch (op) { - case RT_UNARY_OP_NOT: printf("UNARY_NOT\n"); break; case RT_UNARY_OP_POSITIVE: printf("UNARY_POSITIVE\n"); break; case RT_UNARY_OP_NEGATIVE: printf("UNARY_NEGATIVE\n"); break; case RT_UNARY_OP_INVERT: printf("UNARY_INVERT\n"); break; + case RT_UNARY_OP_NOT: printf("UNARY_NOT\n"); break; default: assert(0); } } @@ -589,17 +589,17 @@ static void emit_cpy_binary_op(emit_t *emit, rt_binary_op_t op) { case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: printf("INPLACE_TRUE_DIVIDE\n"); break; case RT_BINARY_OP_INPLACE_MODULO: printf("INPLACE_MODULO\n"); break; case RT_BINARY_OP_INPLACE_POWER: printf("INPLACE_POWER\n"); break; - case RT_COMPARE_OP_LESS: printf("COMPARE_OP <\n"); break; - case RT_COMPARE_OP_MORE: printf("COMPARE_OP >\n"); break; - case RT_COMPARE_OP_EQUAL: printf("COMPARE_OP ==\n"); break; - case RT_COMPARE_OP_LESS_EQUAL: printf("COMPARE_OP <=\n"); break; - case RT_COMPARE_OP_MORE_EQUAL: printf("COMPARE_OP >=\n"); break; - case RT_COMPARE_OP_NOT_EQUAL: printf("COMPARE_OP !=\n"); break; - case RT_COMPARE_OP_IN: printf("COMPARE_OP in\n"); break; - case RT_COMPARE_OP_NOT_IN: printf("COMPARE_OP not in\n"); break; - case RT_COMPARE_OP_IS: printf("COMPARE_OP is\n"); break; - case RT_COMPARE_OP_IS_NOT: printf("COMPARE_OP is not\n"); break; - case RT_COMPARE_OP_EXCEPTION_MATCH: printf("COMPARE_OP exception match\n"); break; + case RT_BINARY_OP_LESS: printf("COMPARE_OP <\n"); break; + case RT_BINARY_OP_MORE: printf("COMPARE_OP >\n"); break; + case RT_BINARY_OP_EQUAL: printf("COMPARE_OP ==\n"); break; + case RT_BINARY_OP_LESS_EQUAL: printf("COMPARE_OP <=\n"); break; + case RT_BINARY_OP_MORE_EQUAL: printf("COMPARE_OP >=\n"); break; + case RT_BINARY_OP_NOT_EQUAL: printf("COMPARE_OP !=\n"); break; + case RT_BINARY_OP_IN: printf("COMPARE_OP in\n"); break; + case RT_BINARY_OP_IS: printf("COMPARE_OP is\n"); break; + case RT_BINARY_OP_EXCEPTION_MATCH: printf("COMPARE_OP exception match\n"); break; + case RT_BINARY_OP_NOT_IN: printf("COMPARE_OP not in\n"); break; + case RT_BINARY_OP_IS_NOT: printf("COMPARE_OP is not\n"); break; default: assert(0); } } diff --git a/py/emitnative.c b/py/emitnative.c index 9e8ae1a99b..8968db4be6 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -1017,7 +1017,7 @@ static void emit_native_binary_op(emit_t *emit, rt_binary_op_t op) { asm_thumb_add_reg_reg_reg(emit->as, REG_ARG_2, REG_ARG_2, REG_ARG_3); #endif emit_post_push_reg(emit, VTYPE_INT, REG_ARG_2); - } else if (op == RT_COMPARE_OP_LESS) { + } else if (op == RT_BINARY_OP_LESS) { #if N_X64 asm_x64_xor_r64_to_r64(emit->as, REG_RET, REG_RET); asm_x64_cmp_r64_with_r64(emit->as, REG_ARG_3, REG_ARG_2); diff --git a/py/obj.c b/py/obj.c index 33d64c894f..e21596fdf5 100644 --- a/py/obj.c +++ b/py/obj.c @@ -116,7 +116,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { // If o2 is long int, dispatch to its virtual methods mp_obj_base_t *o = o2; if (o->type->binary_op != NULL) { - mp_obj_t r = o->type->binary_op(RT_COMPARE_OP_EQUAL, o2, o1); + mp_obj_t r = o->type->binary_op(RT_BINARY_OP_EQUAL, o2, o1); return r == mp_const_true ? true : false; } } @@ -127,7 +127,7 @@ bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) { } else { mp_obj_base_t *o = o1; if (o->type->binary_op != NULL) { - mp_obj_t r = o->type->binary_op(RT_COMPARE_OP_EQUAL, o1, o2); + mp_obj_t r = o->type->binary_op(RT_BINARY_OP_EQUAL, o1, o2); if (r != MP_OBJ_NULL) { return r == mp_const_true ? true : false; } diff --git a/py/objdict.c b/py/objdict.c index 934eb50650..bb851d1024 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -65,11 +65,10 @@ static mp_obj_t dict_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { return elem->value; } } - case RT_COMPARE_OP_IN: - case RT_COMPARE_OP_NOT_IN: + case RT_BINARY_OP_IN: { mp_map_elem_t *elem = mp_map_lookup(&o->map, rhs_in, MP_MAP_LOOKUP); - return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (elem == NULL)); + return MP_BOOL(elem != NULL); } default: // op not supported @@ -380,7 +379,7 @@ static mp_obj_t dict_view_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { /* only supported for the 'keys' kind until sets and dicts are refactored */ mp_obj_dict_view_t *o = lhs_in; if (o->kind != MP_DICT_VIEW_KEYS) return NULL; - if (op != RT_COMPARE_OP_IN && op != RT_COMPARE_OP_NOT_IN) return NULL; + if (op != RT_BINARY_OP_IN) return NULL; return dict_binary_op(op, o->dict, rhs_in); } diff --git a/py/objfloat.c b/py/objfloat.c index 9caeaf7686..ed6260681c 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -101,10 +101,10 @@ mp_obj_t mp_obj_float_binary_op(int op, mp_float_t lhs_val, mp_obj_t rhs_in) { case RT_BINARY_OP_TRUE_DIVIDE: case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: lhs_val /= rhs_val; break; - case RT_COMPARE_OP_LESS: return MP_BOOL(lhs_val < rhs_val); - case RT_COMPARE_OP_MORE: return MP_BOOL(lhs_val > rhs_val); - case RT_COMPARE_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); - case RT_COMPARE_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); + case RT_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); + case RT_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); + case RT_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); + case RT_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); return NULL; // op not supported } diff --git a/py/objint_longlong.c b/py/objint_longlong.c index a59bcf061e..83db6033f4 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -103,17 +103,17 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { case RT_BINARY_OP_INPLACE_RSHIFT: lhs->val >>= (int)rhs_val; return lhs; - case RT_COMPARE_OP_LESS: + case RT_BINARY_OP_LESS: return MP_BOOL(lhs->val < rhs_val); - case RT_COMPARE_OP_MORE: + case RT_BINARY_OP_MORE: return MP_BOOL(lhs->val > rhs_val); - case RT_COMPARE_OP_LESS_EQUAL: + case RT_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs->val <= rhs_val); - case RT_COMPARE_OP_MORE_EQUAL: + case RT_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs->val >= rhs_val); - case RT_COMPARE_OP_EQUAL: + case RT_BINARY_OP_EQUAL: return MP_BOOL(lhs->val == rhs_val); - case RT_COMPARE_OP_NOT_EQUAL: + case RT_BINARY_OP_NOT_EQUAL: return MP_BOOL(lhs->val != rhs_val); default: diff --git a/py/objlist.c b/py/objlist.c index 81040e3b8e..b28ca81279 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -67,7 +67,7 @@ static mp_obj_t list_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp return NULL; } -// Don't pass RT_COMPARE_OP_NOT_EQUAL here +// Don't pass RT_BINARY_OP_NOT_EQUAL here static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) { assert(MP_OBJ_IS_TYPE(self_in, &list_type)); if (!MP_OBJ_IS_TYPE(another_in, &list_type)) { @@ -75,19 +75,19 @@ static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) { } mp_obj_list_t *self = self_in; mp_obj_list_t *another = another_in; - if (op == RT_COMPARE_OP_EQUAL && self->len != another->len) { + if (op == RT_BINARY_OP_EQUAL && self->len != another->len) { return false; } // Let's deal only with > & >= - if (op == RT_COMPARE_OP_LESS || op == RT_COMPARE_OP_LESS_EQUAL) { + if (op == RT_BINARY_OP_LESS || op == RT_BINARY_OP_LESS_EQUAL) { mp_obj_t t = self; self = another; another = t; - if (op == RT_COMPARE_OP_LESS) { - op = RT_COMPARE_OP_MORE; + if (op == RT_BINARY_OP_LESS) { + op = RT_BINARY_OP_MORE; } else { - op = RT_COMPARE_OP_MORE_EQUAL; + op = RT_BINARY_OP_MORE_EQUAL; } } @@ -96,7 +96,7 @@ static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) { bool rel_status; for (int i = 0; i < len; i++) { eq_status = mp_obj_equal(self->items[i], another->items[i]); - if (op == RT_COMPARE_OP_EQUAL && !eq_status) { + if (op == RT_BINARY_OP_EQUAL && !eq_status) { return false; } rel_status = (rt_binary_op(op, self->items[i], another->items[i]) == mp_const_true); @@ -113,7 +113,7 @@ static bool list_cmp_helper(int op, mp_obj_t self_in, mp_obj_t another_in) { // ... then longer list length wins (we deal only with >) return false; } - } else if (op == RT_COMPARE_OP_MORE) { + } else if (op == RT_BINARY_OP_MORE) { // Otherwise, if we have strict relation, equality means failure return false; } @@ -169,14 +169,14 @@ static mp_obj_t list_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); return s; } - case RT_COMPARE_OP_EQUAL: - case RT_COMPARE_OP_LESS: - case RT_COMPARE_OP_LESS_EQUAL: - case RT_COMPARE_OP_MORE: - case RT_COMPARE_OP_MORE_EQUAL: + case RT_BINARY_OP_EQUAL: + case RT_BINARY_OP_LESS: + case RT_BINARY_OP_LESS_EQUAL: + case RT_BINARY_OP_MORE: + case RT_BINARY_OP_MORE_EQUAL: return MP_BOOL(list_cmp_helper(op, lhs, rhs)); - case RT_COMPARE_OP_NOT_EQUAL: - return MP_BOOL(!list_cmp_helper(RT_COMPARE_OP_EQUAL, lhs, rhs)); + case RT_BINARY_OP_NOT_EQUAL: + return MP_BOOL(!list_cmp_helper(RT_BINARY_OP_EQUAL, lhs, rhs)); default: // op not supported @@ -237,7 +237,7 @@ static mp_obj_t list_pop(uint n_args, const mp_obj_t *args) { // TODO make this conform to CPython's definition of sort static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, bool reversed) { - int op = reversed ? RT_COMPARE_OP_MORE : RT_COMPARE_OP_LESS; + int op = reversed ? RT_BINARY_OP_MORE : RT_BINARY_OP_LESS; while (head < tail) { mp_obj_t *h = head - 1; mp_obj_t *t = tail; diff --git a/py/objset.c b/py/objset.c index cf4545c257..05079cf55b 100644 --- a/py/objset.c +++ b/py/objset.c @@ -396,24 +396,23 @@ static mp_obj_t set_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { return set_intersect(lhs, rhs); case RT_BINARY_OP_INPLACE_SUBTRACT: return set_diff(2, args); - case RT_COMPARE_OP_LESS: + case RT_BINARY_OP_LESS: return set_issubset_proper(lhs, rhs); - case RT_COMPARE_OP_MORE: + case RT_BINARY_OP_MORE: return set_issuperset_proper(lhs, rhs); - case RT_COMPARE_OP_EQUAL: + case RT_BINARY_OP_EQUAL: return set_equal(lhs, rhs); - case RT_COMPARE_OP_LESS_EQUAL: + case RT_BINARY_OP_LESS_EQUAL: return set_issubset(lhs, rhs); - case RT_COMPARE_OP_MORE_EQUAL: + case RT_BINARY_OP_MORE_EQUAL: return set_issuperset(lhs, rhs); - case RT_COMPARE_OP_NOT_EQUAL: + case RT_BINARY_OP_NOT_EQUAL: return MP_BOOL(set_equal(lhs, rhs) == mp_const_false); - case RT_COMPARE_OP_IN: - case RT_COMPARE_OP_NOT_IN: + case RT_BINARY_OP_IN: { mp_obj_set_t *o = lhs; mp_obj_t elem = mp_set_lookup(&o->set, rhs, MP_MAP_LOOKUP); - return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (elem == NULL)); + return MP_BOOL(elem != NULL); } default: // op not supported diff --git a/py/objstr.c b/py/objstr.c index fa658ac4d7..3f6aa483e2 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -168,12 +168,11 @@ mp_obj_t str_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } break; - case RT_COMPARE_OP_IN: - case RT_COMPARE_OP_NOT_IN: + case RT_BINARY_OP_IN: /* NOTE `a in b` is `b.__contains__(a)` */ if (MP_OBJ_IS_STR(rhs_in)) { GET_STR_DATA_LEN(rhs_in, rhs_data, rhs_len); - return MP_BOOL((op == RT_COMPARE_OP_IN) ^ (find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len) == NULL)); + return MP_BOOL(find_subbytes(lhs_data, lhs_len, rhs_data, rhs_len) != NULL); } break; diff --git a/py/objtype.c b/py/objtype.c index 45992b23a3..6016325344 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -117,6 +117,7 @@ static mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const m } static const qstr unary_op_method_name[] = { + [RT_UNARY_OP_NOT] = MP_QSTR_, // don't need to implement this [RT_UNARY_OP_BOOL] = MP_QSTR___bool__, [RT_UNARY_OP_LEN] = MP_QSTR___len__, //[RT_UNARY_OP_POSITIVE, @@ -168,18 +169,16 @@ static const qstr binary_op_method_name[] = { RT_BINARY_OP_INPLACE_TRUE_DIVIDE, RT_BINARY_OP_INPLACE_MODULO, RT_BINARY_OP_INPLACE_POWER, - RT_COMPARE_OP_LESS, - RT_COMPARE_OP_MORE, - RT_COMPARE_OP_EQUAL, - RT_COMPARE_OP_LESS_EQUAL, - RT_COMPARE_OP_MORE_EQUAL, - RT_COMPARE_OP_NOT_EQUAL, - RT_COMPARE_OP_IN, - RT_COMPARE_OP_NOT_IN, - RT_COMPARE_OP_IS, - RT_COMPARE_OP_IS_NOT, + RT_BINARY_OP_LESS, + RT_BINARY_OP_MORE, + RT_BINARY_OP_EQUAL, + RT_BINARY_OP_LESS_EQUAL, + RT_BINARY_OP_MORE_EQUAL, + RT_BINARY_OP_NOT_EQUAL, + RT_BINARY_OP_IN, + RT_BINARY_OP_IS, */ - [RT_COMPARE_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size + [RT_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size }; static mp_obj_t class_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) { diff --git a/py/runtime.c b/py/runtime.c index 77e596c5d0..d22fba8f00 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -478,6 +478,7 @@ void rt_store_global(qstr qstr, mp_obj_t obj) { mp_obj_t rt_unary_op(int op, mp_obj_t arg) { DEBUG_OP_printf("unary %d %p\n", op, arg); + if (MP_OBJ_IS_SMALL_INT(arg)) { mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg); switch (op) { @@ -516,28 +517,23 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { // then fail // note that list does not implement + or +=, so that inplace_concat is reached first for += - // deal with is, is not - if (op == RT_COMPARE_OP_IS) { + // deal with is + if (op == RT_BINARY_OP_IS) { // TODO: may need to handle strings specially, CPython appears to // assume all strings are interned (so "is" == "==" for strings) return MP_BOOL(lhs == rhs); } - if (op == RT_COMPARE_OP_IS_NOT) { - // TODO: may need to handle strings specially, CPython appears to - // assume all strings are interned (so "is" == "==" for strings) - return MP_BOOL(lhs != rhs); - } // deal with == and != for all types - if (op == RT_COMPARE_OP_EQUAL || op == RT_COMPARE_OP_NOT_EQUAL) { + if (op == RT_BINARY_OP_EQUAL || op == RT_BINARY_OP_NOT_EQUAL) { if (mp_obj_equal(lhs, rhs)) { - if (op == RT_COMPARE_OP_EQUAL) { + if (op == RT_BINARY_OP_EQUAL) { return mp_const_true; } else { return mp_const_false; } } else { - if (op == RT_COMPARE_OP_EQUAL) { + if (op == RT_BINARY_OP_EQUAL) { return mp_const_false; } else { return mp_const_true; @@ -546,7 +542,7 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } // deal with exception_match for all types - if (op == RT_COMPARE_OP_EXCEPTION_MATCH) { + if (op == RT_BINARY_OP_EXCEPTION_MATCH) { // TODO properly! at the moment it just compares the exception identifier for equality if (MP_OBJ_IS_TYPE(lhs, &exception_type) && MP_OBJ_IS_TYPE(rhs, &exception_type)) { if (mp_obj_exception_get_type(lhs) == mp_obj_exception_get_type(rhs)) { @@ -604,10 +600,10 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { lhs_val = ans; break; } - case RT_COMPARE_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break; - case RT_COMPARE_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break; - case RT_COMPARE_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break; - case RT_COMPARE_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); break; + case RT_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break; + case RT_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break; + case RT_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break; + case RT_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); break; default: assert(0); } @@ -625,12 +621,12 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { } } - /* deal with `in` and `not in` + /* deal with `in` * * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch * needs to go below */ - if (op == RT_COMPARE_OP_IN || op == RT_COMPARE_OP_NOT_IN) { + if (op == RT_BINARY_OP_IN) { mp_obj_type_t *type = mp_obj_get_type(rhs); if (type->binary_op != NULL) { mp_obj_t res = type->binary_op(op, rhs, lhs); @@ -644,10 +640,10 @@ mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) { mp_obj_t iter = rt_getiter(rhs); while ((next = rt_iternext(iter)) != mp_const_stop_iteration) { if (mp_obj_equal(next, lhs)) { - return MP_BOOL(op == RT_COMPARE_OP_IN); + return mp_const_true; } } - return MP_BOOL(op != RT_COMPARE_OP_IN); + return mp_const_false; } nlr_jump(mp_obj_new_exception_msg_varg( diff --git a/py/runtime0.h b/py/runtime0.h index a0f553a896..9edf7ec0e7 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -4,7 +4,7 @@ typedef enum { RT_UNARY_OP_POSITIVE, RT_UNARY_OP_NEGATIVE, RT_UNARY_OP_INVERT, - // Used only for CPython-compatible codegeneration + // these are not supported by the runtime and must be synthesised by the emitter RT_UNARY_OP_NOT, } rt_unary_op_t; @@ -34,18 +34,19 @@ typedef enum { RT_BINARY_OP_INPLACE_TRUE_DIVIDE, RT_BINARY_OP_INPLACE_MODULO, RT_BINARY_OP_INPLACE_POWER, - // TODO probably should rename these COMPARE->BINARY - RT_COMPARE_OP_LESS, - RT_COMPARE_OP_MORE, - RT_COMPARE_OP_EQUAL, - RT_COMPARE_OP_LESS_EQUAL, - RT_COMPARE_OP_MORE_EQUAL, - RT_COMPARE_OP_NOT_EQUAL, - RT_COMPARE_OP_IN, - RT_COMPARE_OP_NOT_IN, - RT_COMPARE_OP_IS, - RT_COMPARE_OP_IS_NOT, - RT_COMPARE_OP_EXCEPTION_MATCH, + // these should return a bool + RT_BINARY_OP_LESS, + RT_BINARY_OP_MORE, + RT_BINARY_OP_EQUAL, + RT_BINARY_OP_LESS_EQUAL, + RT_BINARY_OP_MORE_EQUAL, + RT_BINARY_OP_NOT_EQUAL, + RT_BINARY_OP_IN, + RT_BINARY_OP_IS, + RT_BINARY_OP_EXCEPTION_MATCH, + // these are not supported by the runtime and must be synthesised by the emitter + RT_BINARY_OP_NOT_IN, + RT_BINARY_OP_IS_NOT, } rt_binary_op_t; typedef enum { diff --git a/py/showbc.c b/py/showbc.c index 4c19a6becc..d765c81a5f 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -263,12 +263,14 @@ void mp_byte_code_print(const byte *ip, int len) { printf("POP_EXCEPT"); break; - /* + case MP_BC_NOT: + printf("NOT"); + break; + case MP_BC_UNARY_OP: unum = *ip++; - *sp = rt_unary_op(unum, *sp); + printf("UNARY_OP " UINT_FMT, unum); break; - */ case MP_BC_BINARY_OP: unum = *ip++; diff --git a/py/vm.c b/py/vm.c index 748e0e935b..1d47076dfb 100644 --- a/py/vm.c +++ b/py/vm.c @@ -428,6 +428,14 @@ unwind_jump: //sp -= 3; // pop 3 exception values break; + case MP_BC_NOT: + if (TOP() == mp_const_true) { + SET_TOP(mp_const_false); + } else { + SET_TOP(mp_const_true); + } + break; + case MP_BC_UNARY_OP: unum = *ip++; SET_TOP(rt_unary_op(unum, TOP()));