diff options
Diffstat (limited to 'py')
-rw-r--r-- | py/asmthumb.c | 32 | ||||
-rw-r--r-- | py/asmthumb.h | 7 | ||||
-rw-r--r-- | py/compile.c | 127 | ||||
-rw-r--r-- | py/emitinlinethumb.c | 163 | ||||
-rw-r--r-- | py/obj.h | 1 | ||||
-rw-r--r-- | py/objlist.c | 7 | ||||
-rw-r--r-- | py/runtime.c | 64 | ||||
-rw-r--r-- | py/runtime.h | 1 | ||||
-rw-r--r-- | py/vm.c | 17 |
9 files changed, 277 insertions, 142 deletions
diff --git a/py/asmthumb.c b/py/asmthumb.c index 3fcd28a91d..f37b1ff8fe 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -275,6 +275,12 @@ void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src) { asm_thumb_write_op16(as, 0x4600 | op_lo); } +#define OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest)) + +void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) { + asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b)); +} + #define OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src) (0x1e00 | ((i3_src) << 6) | ((rlo_src) << 3) | (rlo_dest)) void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src) { @@ -283,6 +289,12 @@ void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int asm_thumb_write_op16(as, OP_SUBS_RLO_RLO_I3(rlo_dest, rlo_src, i3_src)); } +#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a)) + +void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b) { + asm_thumb_write_op16(as, OP_CMP_REG_REG(rlo_a, rlo_b)); +} + #define OP_CMP_RLO_I8(rlo, i8) (0x2800 | ((rlo) << 8) | (i8)) void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { @@ -290,6 +302,10 @@ void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8) { asm_thumb_write_op16(as, OP_CMP_RLO_I8(rlo, i8)); } +void asm_thumb_ite_ge(asm_thumb_t *as) { + asm_thumb_write_op16(as, 0xbfac); +} + #define OP_B_N(byte_offset) (0xe000 | (((byte_offset) >> 1) & 0x07ff)) void asm_thumb_b_n(asm_thumb_t *as, int label) { @@ -360,22 +376,6 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) asm_thumb_write_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset)); } -#define OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b) (0x1800 | ((rlo_src_b) << 6) | ((rlo_src_a) << 3) | (rlo_dest)) - -void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b) { - asm_thumb_write_op16(as, OP_ADD_REG_REG_REG(rlo_dest, rlo_src_a, rlo_src_b)); -} - -#define OP_CMP_REG_REG(rlo_a, rlo_b) (0x4280 | ((rlo_b) << 3) | (rlo_a)) - -void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b) { - asm_thumb_write_op16(as, OP_CMP_REG_REG(rlo_a, rlo_b)); -} - -void asm_thumb_ite_ge(asm_thumb_t *as) { - asm_thumb_write_op16(as, 0xbfac); -} - // this could be wrong, because it should have a range of +/- 16MiB... #define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) #define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff)) diff --git a/py/asmthumb.h b/py/asmthumb.h index dcd9c2e3ad..60a86ea50b 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -62,8 +62,11 @@ void asm_thumb_movs_rlo_i8(asm_thumb_t *as, uint rlo_dest, int i8_src); void asm_thumb_movw_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src); void asm_thumb_movt_reg_i16(asm_thumb_t *as, uint reg_dest, int i16_src); void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src); +void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b); void asm_thumb_subs_rlo_rlo_i3(asm_thumb_t *as, uint rlo_dest, uint rlo_src, int i3_src); +void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b); void asm_thumb_cmp_rlo_i8(asm_thumb_t *as, uint rlo, int i8); +void asm_thumb_ite_ge(asm_thumb_t *as); void asm_thumb_b_n(asm_thumb_t *as, int label); void asm_thumb_bcc_n(asm_thumb_t *as, int cond, int label); @@ -73,10 +76,6 @@ void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num_dest, uint rlo_src); void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience -void asm_thumb_add_reg_reg_reg(asm_thumb_t *as, uint rlo_dest, uint rlo_src_a, uint rlo_src_b); // convenience ? -void asm_thumb_cmp_reg_reg(asm_thumb_t *as, uint rlo_a, uint rlo_b); // convenience ? -void asm_thumb_ite_ge(asm_thumb_t *as); // convenience ? - void asm_thumb_b_label(asm_thumb_t *as, int label); // convenience ? void asm_thumb_bcc_label(asm_thumb_t *as, int cc, int label); // convenience: picks narrow or wide branch void asm_thumb_bl_ind(asm_thumb_t *as, void *fun_ptr, uint fun_id, uint reg_temp); // convenience ? diff --git a/py/compile.c b/py/compile.c index f1870bf36e..95fe1d759f 100644 --- a/py/compile.c +++ b/py/compile.c @@ -69,8 +69,13 @@ typedef struct _compiler_t { const emit_inline_asm_method_table_t *emit_inline_asm_method_table; // current emit method table for inline asm } compiler_t; -STATIC void compile_syntax_error(compiler_t *comp, const char *msg) { +STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) { // TODO store the error message to a variable in compiler_t instead of printing it + if (MP_PARSE_NODE_IS_STRUCT(pn)) { + printf(" File \"%s\", line " UINT_FMT "\n", qstr_str(comp->source_file), (machine_uint_t)((mp_parse_node_struct_t*)pn)->source_line); + } else { + printf(" File \"%s\"\n", qstr_str(comp->source_file)); + } printf("SyntaxError: %s\n", msg); comp->had_error = true; } @@ -351,7 +356,7 @@ STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vst case MP_TOKEN_KW_FALSE: vstr_printf(vstr, "False"); break; case MP_TOKEN_KW_NONE: vstr_printf(vstr, "None"); break; case MP_TOKEN_KW_TRUE: vstr_printf(vstr, "True"); break; - default: assert(0); + default: assert(0); // shouldn't happen } break; default: assert(0); @@ -588,8 +593,7 @@ void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t pns1 = (mp_parse_node_struct_t*)pns1->nodes[n - 1]; } if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_paren) { - compile_syntax_error(comp, "can't assign to function call"); - return; + goto cannot_assign; } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { if (assign_kind == ASSIGN_AUG_STORE) { EMIT(rot_three); @@ -615,18 +619,20 @@ void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); } } else { - // shouldn't happen - assert(0); + goto cannot_assign; } } else { - // shouldn't happen - assert(0); + goto cannot_assign; } if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { - // SyntaxError, cannot assign - assert(0); + goto cannot_assign; } + + return; + +cannot_assign: + compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); } void c_assign_tuple(compiler_t *comp, int n, mp_parse_node_t *nodes) { @@ -638,7 +644,7 @@ void c_assign_tuple(compiler_t *comp, int n, mp_parse_node_t *nodes) { EMIT_ARG(unpack_ex, i, n - i - 1); have_star_index = i; } else { - compile_syntax_error(comp, "two starred expressions in assignment"); + compile_syntax_error(comp, nodes[i], "two starred expressions in assignment"); return; } } @@ -673,7 +679,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { break; } } else { - compile_syntax_error(comp, "can't assign to literal"); + compile_syntax_error(comp, pn, "can't assign to literal"); return; } } else { @@ -697,7 +703,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { // lhs is something in parenthesis if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { // empty tuple - compile_syntax_error(comp, "can't assign to ()"); + compile_syntax_error(comp, pn, "can't assign to ()"); return; } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) { pns = (mp_parse_node_struct_t*)pns->nodes[0]; @@ -727,8 +733,8 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { break; default: - printf("unknown assign, %u\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns)); - assert(0); + compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); + return; } return; @@ -750,8 +756,9 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { c_assign(comp, pns2->nodes[i], ASSIGN_STORE); } } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) { - // TODO not implemented - assert(0); + // TODO can we ever get here? can it be compiled? + compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression"); + return; } else { // sequence with 2 items goto sequence_with_2_items; @@ -766,7 +773,7 @@ void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) { return; bad_aug: - compile_syntax_error(comp, "illegal expression for augmented assignment"); + compile_syntax_error(comp, pn, "illegal expression for augmented assignment"); } // stuff for lambda and comprehensions and generators @@ -841,6 +848,7 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) { pn_equal = pns->nodes[2]; } else { + // XXX what to do here? assert(0); return; } @@ -850,7 +858,7 @@ void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) { // check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid) if (!comp->have_bare_star && comp->param_pass_num_default_params != 0) { - compile_syntax_error(comp, "non-default argument follows default argument"); + compile_syntax_error(comp, pn, "non-default argument follows default argument"); return; } @@ -988,7 +996,7 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_ } if (name_len != 2) { - compile_syntax_error(comp, "invalid micropython decorator"); + compile_syntax_error(comp, name_nodes[0], "invalid micropython decorator"); return true; } @@ -1006,7 +1014,7 @@ STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_ *emit_options = MP_EMIT_OPT_ASM_THUMB; #endif } else { - compile_syntax_error(comp, "invalid micropython decorator"); + compile_syntax_error(comp, name_nodes[1], "invalid micropython decorator"); } return true; @@ -1100,8 +1108,8 @@ void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { pns1 = (mp_parse_node_struct_t*)pns1->nodes[n - 1]; } if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_paren) { - // SyntaxError: can't delete a function call - assert(0); + // can't delete function calls + goto cannot_delete; } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) { compile_node(comp, pns1->nodes[0]); EMIT(delete_subscr); @@ -1109,17 +1117,14 @@ void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0])); } else { - // shouldn't happen - assert(0); + goto cannot_delete; } } else { - // shouldn't happen - assert(0); + goto cannot_delete; } if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) { - // SyntaxError, cannot delete - assert(0); + goto cannot_delete; } } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) { pn = ((mp_parse_node_struct_t*)pn)->nodes[0]; @@ -1142,7 +1147,7 @@ void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { } } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) { // TODO not implemented; can't del comprehension? - assert(0); + goto cannot_delete; } else { // sequence with 2 items goto sequence_with_2_items; @@ -1158,9 +1163,14 @@ void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) { c_del_stmt(comp, pn); } } else { - // not implemented - assert(0); + // TODO is there anything else to implement? + goto cannot_delete; } + + return; + +cannot_delete: + compile_syntax_error(comp, (mp_parse_node_t)pn, "can't delete expression"); } void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -1169,21 +1179,21 @@ void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->break_label == 0) { - compile_syntax_error(comp, "'break' outside loop"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop"); } EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level); } void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->continue_label == 0) { - compile_syntax_error(comp, "'continue' outside loop"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop"); } EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level); } void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->scope_cur->kind != SCOPE_FUNCTION) { - compile_syntax_error(comp, "'return' outside function"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "'return' outside function"); return; } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { @@ -1280,14 +1290,14 @@ void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) { } else { // TODO not implemented // This covers relative imports starting with dot(s) like "from .foo import" - compile_syntax_error(comp, "Relative imports not implemented"); - assert(0); + compile_syntax_error(comp, pn, "Relative imports not implemented"); + return; } } else { // TODO not implemented // This covers relative imports with dots only like "from .. import" - compile_syntax_error(comp, "Relative imports not implemented"); - assert(0); + compile_syntax_error(comp, pn, "Relative imports not implemented"); + return; } } @@ -1699,7 +1709,7 @@ void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_except, if (MP_PARSE_NODE_IS_NULL(pns_except->nodes[0])) { // this is a catch all exception handler if (i + 1 != n_except) { - compile_syntax_error(comp, "default 'except:' must be last"); + compile_syntax_error(comp, pn_excepts[i], "default 'except:' must be last"); return; } } else { @@ -1923,6 +1933,11 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // optimisation for a, b = c, d; to match CPython's optimisation mp_parse_node_struct_t* pns10 = (mp_parse_node_struct_t*)pns1->nodes[0]; mp_parse_node_struct_t* pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; + if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) + || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr)) { + // can't optimise when it's a star expression on the lhs + goto no_optimisation; + } compile_node(comp, pns10->nodes[0]); // rhs compile_node(comp, pns10->nodes[1]); // rhs EMIT(rot_two); @@ -1935,6 +1950,12 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { // optimisation for a, b, c = d, e, f; to match CPython's optimisation mp_parse_node_struct_t* pns10 = (mp_parse_node_struct_t*)pns1->nodes[0]; mp_parse_node_struct_t* pns0 = (mp_parse_node_struct_t*)pns->nodes[0]; + if (MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[0], PN_star_expr) + || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[1], PN_star_expr) + || MP_PARSE_NODE_IS_STRUCT_KIND(pns0->nodes[2], PN_star_expr)) { + // can't optimise when it's a star expression on the lhs + goto no_optimisation; + } compile_node(comp, pns10->nodes[0]); // rhs compile_node(comp, pns10->nodes[1]); // rhs compile_node(comp, pns10->nodes[2]); // rhs @@ -1944,6 +1965,7 @@ void compile_expr_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) { c_assign(comp, pns0->nodes[1], ASSIGN_STORE); // lhs store c_assign(comp, pns0->nodes[2], ASSIGN_STORE); // lhs store } else { + no_optimisation: compile_node(comp, pns1->nodes[0]); // rhs c_assign(comp, pns->nodes[0], ASSIGN_STORE); // lhs store } @@ -2090,10 +2112,7 @@ void compile_comparison(compiler_t *comp, mp_parse_node_struct_t *pns) { } void compile_star_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { - // TODO - assert(0); - compile_node(comp, pns->nodes[0]); - //EMIT_ARG(unary_op, "UNARY_STAR"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "can use starred expression only as assignment target"); } void compile_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { @@ -2271,7 +2290,7 @@ void compile_atom_string(compiler_t *comp, mp_parse_node_struct_t *pns) { if (i == 0) { string_kind = pn_kind; } else if (pn_kind != string_kind) { - compile_syntax_error(comp, "cannot mix bytes and nonbytes literals"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "cannot mix bytes and nonbytes literals"); return; } n_bytes += qstr_len(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])); @@ -2431,13 +2450,13 @@ void compile_atom_brace(compiler_t *comp, mp_parse_node_struct_t *pns) { compile_node(comp, pn); if (is_dict) { if (!is_key_value) { - compile_syntax_error(comp, "?expecting key:value for dictiona"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting key:value for dictionary"); return; } EMIT(store_map); } else { if (is_key_value) { - compile_syntax_error(comp, "?expecting just a value for s"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "expecting just a value for set"); return; } } @@ -2557,7 +2576,7 @@ void compile_classdef(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_arglist_star(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->have_star_arg) { - compile_syntax_error(comp, "?can't have multiple *x"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "can't have multiple *x"); return; } comp->have_star_arg = true; @@ -2566,7 +2585,7 @@ void compile_arglist_star(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_arglist_dbl_star(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->have_dbl_star_arg) { - compile_syntax_error(comp, "?can't have multiple **x"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "can't have multiple **x"); return; } comp->have_dbl_star_arg = true; @@ -2578,7 +2597,7 @@ void compile_argument(compiler_t *comp, mp_parse_node_struct_t *pns) { mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1]; if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_argument_3) { if (!MP_PARSE_NODE_IS_ID(pns->nodes[0])) { - compile_syntax_error(comp, "?lhs of keyword argument must be an id"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "left-hand-side of keyword argument must be an id"); return; } EMIT_ARG(load_const_id, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0])); @@ -2594,7 +2613,7 @@ void compile_argument(compiler_t *comp, mp_parse_node_struct_t *pns) { void compile_yield_expr(compiler_t *comp, mp_parse_node_struct_t *pns) { if (comp->scope_cur->kind != SCOPE_FUNCTION) { - compile_syntax_error(comp, "'yield' outside function"); + compile_syntax_error(comp, (mp_parse_node_t)pns, "'yield' outside function"); return; } if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) { @@ -2658,7 +2677,7 @@ void compile_node(compiler_t *comp, mp_parse_node_t pn) { #if MICROPY_DEBUG_PRINTERS mp_parse_node_print(pn, 0); #endif - assert(0); + compile_syntax_error(comp, pn, "internal compiler error"); } else { f(comp, pns); } @@ -2744,7 +2763,7 @@ void compile_scope_func_lambda_param(compiler_t *comp, mp_parse_node_t pn, pn_ki bool added; id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, param_name, &added); if (!added) { - compile_syntax_error(comp, "?same name used for parameter"); + compile_syntax_error(comp, pn, "same name used for parameter"); return; } id_info->param = true; @@ -3049,7 +3068,7 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass // emit instructions if (strcmp(qstr_str(op), "label") == 0) { if (!(n_args == 1 && MP_PARSE_NODE_IS_ID(pn_arg[0]))) { - compile_syntax_error(comp, "inline assembler 'label' requires 1 argument"); + compile_syntax_error(comp, nodes[i], "inline assembler 'label' requires 1 argument"); return; } int lab = comp_next_label(comp); diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 9ea2cc24bc..c5136ab371 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -81,45 +81,36 @@ STATIC void emit_inline_thumb_label(emit_inline_asm_t *emit, int label_num, qstr asm_thumb_label_assign(emit->as, label_num); } -STATIC bool check_n_arg(qstr op, int n_args, int wanted_n_args) { - if (wanted_n_args == n_args) { - return true; - } else { - printf("SyntaxError: '%s' expects %d arguments'\n", qstr_str(op), wanted_n_args); - return false; - } -} - -STATIC uint get_arg_rlo(qstr op, mp_parse_node_t *pn_args, int wanted_arg_num) { +STATIC uint get_arg_rlo(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) { if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) { - printf("SyntaxError: '%s' expects a register in position %d\n", qstr_str(op), wanted_arg_num); + printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num); return 0; } qstr reg_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]); const char *reg_str = qstr_str(reg_qstr); if (!(strlen(reg_str) == 2 && reg_str[0] == 'r' && ('0' <= reg_str[1] && reg_str[1] <= '7'))) { - printf("SyntaxError: '%s' expects a register in position %d\n", qstr_str(op), wanted_arg_num); + printf("SyntaxError: '%s' expects a register in position %d\n", op, wanted_arg_num); return 0; } return reg_str[1] - '0'; } -STATIC int get_arg_i(qstr op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) { +STATIC int get_arg_i(const char *op, mp_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) { if (!MP_PARSE_NODE_IS_SMALL_INT(pn_args[wanted_arg_num])) { - printf("SyntaxError: '%s' expects an integer in position %d\n", qstr_str(op), wanted_arg_num); + printf("SyntaxError: '%s' expects an integer in position %d\n", op, wanted_arg_num); return 0; } int i = MP_PARSE_NODE_LEAF_SMALL_INT(pn_args[wanted_arg_num]); if ((i & (~fit_mask)) != 0) { - printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", qstr_str(op), i, fit_mask); + printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", op, i, fit_mask); return 0; } return i; } -STATIC int get_arg_label(emit_inline_asm_t *emit, qstr op, mp_parse_node_t *pn_args, int wanted_arg_num) { +STATIC int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_t *pn_args, int wanted_arg_num) { if (!MP_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) { - printf("SyntaxError: '%s' expects a label in position %d\n", qstr_str(op), wanted_arg_num); + printf("SyntaxError: '%s' expects a label in position %d\n", op, wanted_arg_num); return 0; } qstr label_qstr = MP_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]); @@ -135,6 +126,24 @@ STATIC int get_arg_label(emit_inline_asm_t *emit, qstr op, mp_parse_node_t *pn_a return 0; } +typedef struct _cc_name_t { byte cc; byte name[2]; } cc_name_t; +STATIC const cc_name_t cc_name_table[] = { + {THUMB_CC_EQ, "eq"}, + {THUMB_CC_NE, "ne"}, + {THUMB_CC_CS, "cs"}, + {THUMB_CC_CC, "cc"}, + {THUMB_CC_MI, "mi"}, + {THUMB_CC_PL, "pl"}, + {THUMB_CC_VS, "vs"}, + {THUMB_CC_VC, "vc"}, + {THUMB_CC_HI, "hi"}, + {THUMB_CC_LS, "ls"}, + {THUMB_CC_GE, "ge"}, + {THUMB_CC_LT, "lt"}, + {THUMB_CC_GT, "gt"}, + {THUMB_CC_LE, "le"}, +}; + STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args) { // TODO perhaps make two tables: // one_args = @@ -146,60 +155,86 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, m // three_args = // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3 - // 1 arg - if (strcmp(qstr_str(op), "b") == 0) { - if (!check_n_arg(op, n_args, 1)) { - return; - } - int label_num = get_arg_label(emit, op, pn_args, 0); - // TODO check that this succeeded, ie branch was within range - asm_thumb_b_n(emit->as, label_num); - } else if (strcmp(qstr_str(op), "bgt") == 0) { - if (!check_n_arg(op, n_args, 1)) { - return; - } - int label_num = get_arg_label(emit, op, pn_args, 0); - // TODO check that this succeeded, ie branch was within range - asm_thumb_bcc_n(emit->as, THUMB_CC_GT, label_num); - - // 2 args - } else if (strcmp(qstr_str(op), "movs") == 0) { - if (!check_n_arg(op, n_args, 2)) { - return; + const char *op_str = qstr_str(op); + uint op_len = strlen(op_str); + + if (n_args == 0) { + if (strcmp(op_str, "ite.ge") == 0) { // TODO correct name for this op? + asm_thumb_ite_ge(emit->as); + } else { + goto unknown_op; } - uint rlo_dest = get_arg_rlo(op, pn_args, 0); - int i_src = get_arg_i(op, pn_args, 1, 0xff); - asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src); - } else if (strcmp(qstr_str(op), "movw") == 0) { - if (!check_n_arg(op, n_args, 2)) { - return; + + } else if (n_args == 1) { + if (strcmp(op_str, "b") == 0) { + int label_num = get_arg_label(emit, op_str, pn_args, 0); + // TODO check that this succeeded, ie branch was within range + asm_thumb_b_n(emit->as, label_num); + } else if (op_str[0] == 'b' && op_len == 3) { + uint cc = -1; + for (uint i = 0; i < (sizeof cc_name_table) / (sizeof cc_name_table[0]); i++) { + if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) { + cc = cc_name_table[i].cc; + } + } + if (cc == -1) { + goto unknown_op; + } + int label_num = get_arg_label(emit, op_str, pn_args, 0); + // TODO check that this succeeded, ie branch was within range + asm_thumb_bcc_n(emit->as, cc, label_num); + } else { + goto unknown_op; } - uint rlo_dest = get_arg_rlo(op, pn_args, 0); // TODO can be reg lo or hi - int i_src = get_arg_i(op, pn_args, 1, 0xffff); - asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src); - } else if (strcmp(qstr_str(op), "cmp") == 0) { - if (!check_n_arg(op, n_args, 2)) { - return; + + } else if (n_args == 2) { + if (strcmp(op_str, "mov") == 0) { + uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); + uint rlo_src = get_arg_rlo(op_str, pn_args, 1); + asm_thumb_mov_reg_reg(emit->as, rlo_dest, rlo_src); + } else if (strcmp(op_str, "movs") == 0) { + uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); + int i_src = get_arg_i(op_str, pn_args, 1, 0xff); + asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src); + } else if (strcmp(op_str, "movw") == 0) { + uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi + int i_src = get_arg_i(op_str, pn_args, 1, 0xffff); + asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src); + } else if (strcmp(op_str, "movt") == 0) { + uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); // TODO can be reg lo or hi + int i_src = get_arg_i(op_str, pn_args, 1, 0xffff); + asm_thumb_movt_reg_i16(emit->as, rlo_dest, i_src); + } else if (strcmp(op_str, "cmp") == 0) { + uint rlo = get_arg_rlo(op_str, pn_args, 0); + int i8 = get_arg_i(op_str, pn_args, 1, 0xff); + asm_thumb_cmp_rlo_i8(emit->as, rlo, i8); + } else { + goto unknown_op; } - uint rlo = get_arg_rlo(op, pn_args, 0); - int i8 = get_arg_i(op, pn_args, 1, 0xff); - asm_thumb_cmp_rlo_i8(emit->as, rlo, i8); - - // 3 args - } else if (strcmp(qstr_str(op), "subs") == 0) { - if (!check_n_arg(op, n_args, 3)) { - return; + + } else if (n_args == 3) { + if (strcmp(op_str, "add") == 0) { + uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); + uint rlo_src_a = get_arg_rlo(op_str, pn_args, 1); + uint rlo_src_b = get_arg_rlo(op_str, pn_args, 2); + asm_thumb_add_reg_reg_reg(emit->as, rlo_dest, rlo_src_a, rlo_src_b); + } else if (strcmp(op_str, "subs") == 0) { + uint rlo_dest = get_arg_rlo(op_str, pn_args, 0); + uint rlo_src = get_arg_rlo(op_str, pn_args, 1); + int i3_src = get_arg_i(op_str, pn_args, 2, 0x7); + asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src); + } else { + goto unknown_op; } - uint rlo_dest = get_arg_rlo(op, pn_args, 0); - uint rlo_src = get_arg_rlo(op, pn_args, 1); - int i3_src = get_arg_i(op, pn_args, 2, 0x7); - asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src); - // unknown op } else { - printf("SyntaxError: unsupported ARM Thumb instruction '%s'\n", qstr_str(op)); - return; + goto unknown_op; } + + return; + +unknown_op: + printf("SyntaxError: unsupported ARM Thumb instruction '%s' with %d arguments\n", op_str, n_args); } const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { @@ -440,6 +440,7 @@ mp_obj_t mp_obj_tuple_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m // list mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); void mp_obj_list_get(mp_obj_t self_in, uint *len, mp_obj_t **items); +void mp_obj_list_set_len(mp_obj_t self_in, uint len); void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); mp_obj_t mp_obj_list_sort(uint n_args, const mp_obj_t *args, mp_map_t *kwargs); diff --git a/py/objlist.c b/py/objlist.c index 620bf2944a..371d1cb26e 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -378,6 +378,13 @@ void mp_obj_list_get(mp_obj_t self_in, uint *len, mp_obj_t **items) { *items = self->items; } +void mp_obj_list_set_len(mp_obj_t self_in, uint len) { + // trust that the caller knows what it's doing + // TODO realloc if len got much smaller than alloc + mp_obj_list_t *self = self_in; + self->len = len; +} + void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_list_t *self = self_in; uint i = mp_get_index(self->base.type, self->len, index, false); diff --git a/py/runtime.c b/py/runtime.c index 44e0ded507..3d1ae72c2f 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -672,6 +672,70 @@ too_long: nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", num)); } +// unpacked items are stored in reverse order into the array pointed to by items +void mp_unpack_ex(mp_obj_t seq_in, uint num_in, mp_obj_t *items) { + uint num_left = num_in & 0xff; + uint num_right = (num_in >> 8) & 0xff; + DEBUG_OP_printf("unpack ex %d %d\n", num_left, num_right); + uint seq_len; + if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) { + mp_obj_t *seq_items; + if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple)) { + mp_obj_tuple_get(seq_in, &seq_len, &seq_items); + } else { + if (num_left == 0 && num_right == 0) { + // *a, = b # sets a to b if b is a list + items[0] = seq_in; + return; + } + mp_obj_list_get(seq_in, &seq_len, &seq_items); + } + if (seq_len < num_left + num_right) { + goto too_short; + } + for (uint i = 0; i < num_right; i++) { + items[i] = seq_items[seq_len - 1 - i]; + } + items[num_right] = mp_obj_new_list(seq_len - num_left - num_right, seq_items + num_left); + for (uint i = 0; i < num_left; i++) { + items[num_right + 1 + i] = seq_items[num_left - 1 - i]; + } + } else { + // Generic iterable; this gets a bit messy: we unpack known left length to the + // items destination array, then the rest to a dynamically created list. Once the + // iterable is exhausted, we take from this list for the right part of the items. + // TODO Improve to waste less memory in the dynamically created list. + mp_obj_t iterable = mp_getiter(seq_in); + mp_obj_t item; + for (seq_len = 0; seq_len < num_left; seq_len++) { + item = mp_iternext(iterable); + if (item == MP_OBJ_NULL) { + goto too_short; + } + items[num_left + num_right + 1 - 1 - seq_len] = item; + } + mp_obj_t rest = mp_obj_new_list(0, NULL); + while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) { + mp_obj_list_append(rest, item); + } + uint rest_len; + mp_obj_t *rest_items; + mp_obj_list_get(rest, &rest_len, &rest_items); + if (rest_len < num_right) { + goto too_short; + } + items[num_right] = rest; + for (uint i = 0; i < num_right; i++) { + items[num_right - 1 - i] = rest_items[rest_len - num_right + i]; + } + mp_obj_list_set_len(rest, rest_len - num_right); + } + return; + +too_short: + nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", seq_len)); +} + mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) { DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr)); // use load_method diff --git a/py/runtime.h b/py/runtime.h index cc76186f4e..ab34be2da9 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -44,6 +44,7 @@ mp_obj_t mp_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args); mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args); void mp_unpack_sequence(mp_obj_t seq, uint num, mp_obj_t *items); +void mp_unpack_ex(mp_obj_t seq, uint num, mp_obj_t *items); mp_obj_t mp_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value); mp_obj_t mp_load_attr(mp_obj_t base, qstr attr); void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest); @@ -639,8 +639,10 @@ unwind_jump: obj1 = TOP(); SET_TOP(mp_obj_new_slice(obj1, obj2, NULL)); } else { - printf("3-argument slice is not supported\n"); - assert(0); + obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "3-argument slice is not supported"); + nlr_pop(); + fastn[0] = obj1; + return MP_VM_RETURN_EXCEPTION; } break; #endif @@ -651,6 +653,12 @@ unwind_jump: sp += unum - 1; break; + case MP_BC_UNPACK_EX: + DECODE_UINT; + mp_unpack_ex(sp[0], unum, sp); + sp += (unum & 0xff) + ((unum >> 8) & 0xff); + break; + case MP_BC_MAKE_FUNCTION: DECODE_UINT; PUSH(mp_make_function_from_id(unum, MP_OBJ_NULL, MP_OBJ_NULL)); @@ -833,9 +841,10 @@ yield: default: printf("code %p, byte code 0x%02x not implemented\n", ip, op); - assert(0); + obj1 = mp_obj_new_exception_msg(&mp_type_NotImplementedError, "byte code not implemented"); nlr_pop(); - return MP_VM_RETURN_NORMAL; + fastn[0] = obj1; + return MP_VM_RETURN_EXCEPTION; } } |