Skip to content

Commit cdd96df

Browse files
committed
py: Implement more features in native emitter.
On x64, native emitter now passes 70 of the tests.
1 parent 65cad12 commit cdd96df

8 files changed

Lines changed: 107 additions & 35 deletions

File tree

py/compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3351,7 +3351,7 @@ mp_obj_t mp_compile(mp_parse_node_t pn, qstr source_file, uint emit_opt, bool is
33513351
#else
33523352
// return function that executes the outer module
33533353
// we can free the unique_code slot because no-one has reference to this unique_code_id anymore
3354-
return mp_make_function_from_id(unique_code_id, true, MP_OBJ_NULL, MP_OBJ_NULL);
3354+
return mp_make_function_from_id_and_free(unique_code_id, MP_OBJ_NULL, MP_OBJ_NULL);
33553355
#endif
33563356
}
33573357
}

py/emitglue.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ void mp_emit_glue_assign_inline_asm_code(uint unique_code_id, void *fun, uint le
190190
#endif
191191
}
192192

193-
mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args, mp_obj_t def_kw_args) {
193+
mp_obj_t mp_make_function_from_id(uint unique_code_id, mp_obj_t def_args, mp_obj_t def_kw_args) {
194194
DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
195195
if (unique_code_id >= unique_codes_total) {
196196
// illegal code id
@@ -224,20 +224,25 @@ mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp
224224
fun = mp_obj_new_gen_wrap(fun);
225225
}
226226

227+
return fun;
228+
}
229+
230+
mp_obj_t mp_make_function_from_id_and_free(uint unique_code_id, mp_obj_t def_args, mp_obj_t def_kw_args) {
231+
mp_obj_t f = mp_make_function_from_id(unique_code_id, def_args, def_kw_args);
232+
227233
// in some cases we can free the unique_code slot
228-
// any dynamically allocade memory is now owned by the fun object
229-
if (free_unique_code) {
230-
memset(c, 0, sizeof *c); // make sure all pointers are zeroed
231-
c->kind = MP_CODE_UNUSED;
232-
}
234+
// any dynamically allocated memory is now owned by the fun object
235+
mp_code_t *c = &unique_codes[unique_code_id];
236+
memset(c, 0, sizeof *c); // make sure all pointers are zeroed
237+
c->kind = MP_CODE_UNUSED;
233238

234-
return fun;
239+
return f;
235240
}
236241

237242
mp_obj_t mp_make_closure_from_id(uint unique_code_id, mp_obj_t closure_tuple, mp_obj_t def_args, mp_obj_t def_kw_args) {
238243
DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
239244
// make function object
240-
mp_obj_t ffun = mp_make_function_from_id(unique_code_id, false, def_args, def_kw_args);
245+
mp_obj_t ffun = mp_make_function_from_id(unique_code_id, def_args, def_kw_args);
241246
// wrap function in closure object
242247
return mp_obj_new_closure(ffun, closure_tuple);
243248
}

py/emitnative.c

Lines changed: 76 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@
3434
#include "obj.h"
3535
#include "runtime.h"
3636

37+
#if 0 // print debugging info
38+
#define DEBUG_PRINT (1)
39+
#define DEBUG_printf DEBUG_printf
40+
#else // don't print debugging info
41+
#define DEBUG_printf(...) (void)0
42+
#endif
43+
3744
// wrapper around everything in this file
3845
#if (MICROPY_EMIT_X64 && N_X64) || (MICROPY_EMIT_THUMB && N_THUMB)
3946

@@ -300,6 +307,7 @@ STATIC void emit_native_set_source_line(emit_t *emit, int source_line) {
300307
}
301308

302309
STATIC void adjust_stack(emit_t *emit, int stack_size_delta) {
310+
DEBUG_printf("adjust stack: stack:%d + delta:%d\n", emit->stack_size, stack_size_delta);
303311
emit->stack_size += stack_size_delta;
304312
assert(emit->stack_size >= 0);
305313
if (emit->pass > PASS_1 && emit->stack_size > emit->scope->stack_size) {
@@ -542,6 +550,18 @@ STATIC void emit_call_with_2_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, void
542550
#endif
543551
}
544552

553+
STATIC void emit_call_with_3_imm_args(emit_t *emit, mp_fun_kind_t fun_kind, void *fun, machine_int_t arg_val1, int arg_reg1, machine_int_t arg_val2, int arg_reg2, machine_int_t arg_val3, int arg_reg3) {
554+
need_reg_all(emit);
555+
ASM_MOV_IMM_TO_REG(arg_val1, arg_reg1);
556+
ASM_MOV_IMM_TO_REG(arg_val2, arg_reg2);
557+
ASM_MOV_IMM_TO_REG(arg_val3, arg_reg3);
558+
#if N_X64
559+
asm_x64_call_ind(emit->as, fun, REG_RAX);
560+
#elif N_THUMB
561+
asm_thumb_bl_ind(emit->as, mp_fun_table[fun_kind], fun_kind, REG_R3);
562+
#endif
563+
}
564+
545565
STATIC void emit_native_load_id(emit_t *emit, qstr qstr) {
546566
// check for built-ins
547567
if (strcmp(qstr_str(qstr), "v_int") == 0) {
@@ -577,22 +597,38 @@ STATIC void emit_native_label_assign(emit_t *emit, int l) {
577597
emit_post(emit);
578598
}
579599

580-
STATIC void emit_native_import_name(emit_t *emit, qstr qstr) {
581-
// not implemented
582-
assert(0);
600+
STATIC void emit_native_import_name(emit_t *emit, qstr qst) {
601+
DEBUG_printf("import_name %s\n", qstr_str(qst));
602+
vtype_kind_t vtype_fromlist;
603+
vtype_kind_t vtype_level;
604+
emit_pre_pop_reg_reg(emit, &vtype_fromlist, REG_ARG_2, &vtype_level, REG_ARG_3); // arg2 = fromlist, arg3 = level
605+
assert(vtype_fromlist == VTYPE_PYOBJ);
606+
assert(vtype_level == VTYPE_PYOBJ);
607+
emit_call_with_imm_arg(emit, MP_F_IMPORT_NAME, mp_import_name, qst, REG_ARG_1); // arg1 = import name
608+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
583609
}
584610

585-
STATIC void emit_native_import_from(emit_t *emit, qstr qstr) {
586-
// not implemented
587-
assert(0);
611+
STATIC void emit_native_import_from(emit_t *emit, qstr qst) {
612+
DEBUG_printf("import_from %s\n", qstr_str(qst));
613+
emit_native_pre(emit);
614+
vtype_kind_t vtype_module;
615+
emit_access_stack(emit, 1, &vtype_module, REG_ARG_1); // arg1 = module
616+
assert(vtype_module == VTYPE_PYOBJ);
617+
emit_call_with_imm_arg(emit, MP_F_IMPORT_FROM, mp_import_from, qst, REG_ARG_2); // arg2 = import name
618+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
588619
}
589620

590621
STATIC void emit_native_import_star(emit_t *emit) {
591-
// not implemented
592-
assert(0);
622+
DEBUG_printf("import_star\n");
623+
vtype_kind_t vtype_module;
624+
emit_pre_pop_reg(emit, &vtype_module, REG_ARG_1); // arg1 = module
625+
assert(vtype_module == VTYPE_PYOBJ);
626+
emit_call(emit, MP_F_IMPORT_ALL, mp_import_all);
627+
emit_post(emit);
593628
}
594629

595630
STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
631+
DEBUG_printf("load_const_tok %d\n", tok);
596632
emit_native_pre(emit);
597633
int vtype;
598634
machine_uint_t val;
@@ -616,6 +652,7 @@ STATIC void emit_native_load_const_tok(emit_t *emit, mp_token_kind_t tok) {
616652
}
617653

618654
STATIC void emit_native_load_const_small_int(emit_t *emit, machine_int_t arg) {
655+
DEBUG_printf("load_const_small_int %d\n", arg);
619656
emit_native_pre(emit);
620657
if (emit->do_viper_types) {
621658
emit_post_push_imm(emit, VTYPE_INT, arg);
@@ -624,10 +661,12 @@ STATIC void emit_native_load_const_small_int(emit_t *emit, machine_int_t arg) {
624661
}
625662
}
626663

627-
STATIC void emit_native_load_const_int(emit_t *emit, qstr qstr) {
628-
// not implemented
629-
// load integer, check fits in 32 bits
630-
assert(0);
664+
STATIC void emit_native_load_const_int(emit_t *emit, qstr qst) {
665+
DEBUG_printf("load_const_int %s\n", qstr_str(st));
666+
// for viper: load integer, check fits in 32 bits
667+
emit_native_pre(emit);
668+
emit_call_with_imm_arg(emit, MP_F_LOAD_CONST_INT, mp_obj_new_int_from_long_str, qst, REG_ARG_1);
669+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
631670
}
632671

633672
STATIC void emit_native_load_const_dec(emit_t *emit, qstr qstr) {
@@ -1125,12 +1164,26 @@ STATIC void emit_native_set_add(emit_t *emit, int set_index) {
11251164
}
11261165

11271166
STATIC void emit_native_build_slice(emit_t *emit, int n_args) {
1128-
assert(0);
1167+
DEBUG_printf("build_slice %d\n", n_args);
1168+
assert(n_args == 2);
1169+
vtype_kind_t vtype_start, vtype_stop;
1170+
emit_pre_pop_reg_reg(emit, &vtype_stop, REG_ARG_2, &vtype_start, REG_ARG_1); // arg1 = start, arg2 = stop
1171+
assert(vtype_start == VTYPE_PYOBJ);
1172+
assert(vtype_stop == VTYPE_PYOBJ);
1173+
emit_call_with_imm_arg(emit, MP_F_NEW_SLICE, mp_obj_new_slice, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3); // arg3 = step
1174+
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
11291175
}
1176+
11301177
STATIC void emit_native_unpack_sequence(emit_t *emit, int n_args) {
1131-
// call runtime, needs type decl
1132-
assert(0);
1178+
// TODO this is untested
1179+
DEBUG_printf("unpack_sequence %d\n", n_args);
1180+
vtype_kind_t vtype_base;
1181+
emit_pre_pop_reg(emit, &vtype_base, REG_ARG_1); // arg1 = seq
1182+
assert(vtype_base == VTYPE_PYOBJ);
1183+
emit_get_stack_pointer_to_reg_for_push(emit, REG_ARG_3, n_args); // arg3 = dest ptr
1184+
emit_call_with_imm_arg(emit, MP_F_UNPACK_SEQUENCE, mp_unpack_sequence, n_args, REG_ARG_2); // arg2 = n_args
11331185
}
1186+
11341187
STATIC void emit_native_unpack_ex(emit_t *emit, int n_left, int n_right) {
11351188
assert(0);
11361189
}
@@ -1139,7 +1192,7 @@ STATIC void emit_native_make_function(emit_t *emit, scope_t *scope, uint n_pos_d
11391192
// call runtime, with type info for args, or don't support dict/default params, or only support Python objects for them
11401193
assert(n_pos_defaults == 0 && n_kw_defaults == 0);
11411194
emit_native_pre(emit);
1142-
emit_call_with_imm_arg(emit, MP_F_MAKE_FUNCTION_FROM_ID, mp_make_function_from_id, scope->unique_code_id, REG_ARG_1);
1195+
emit_call_with_3_imm_args(emit, MP_F_MAKE_FUNCTION_FROM_ID, mp_make_function_from_id, scope->unique_code_id, REG_ARG_1, (machine_uint_t)MP_OBJ_NULL, REG_ARG_2, (machine_uint_t)MP_OBJ_NULL, REG_ARG_3);
11431196
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
11441197
}
11451198

@@ -1149,7 +1202,7 @@ STATIC void emit_native_make_closure(emit_t *emit, scope_t *scope, uint n_pos_de
11491202

11501203
STATIC void emit_native_call_function(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) {
11511204
// call special viper runtime routine with type info for args, and wanted type info for return
1152-
assert(n_keyword == 0 && !have_star_arg && !have_dbl_star_arg);
1205+
assert(!have_star_arg && !have_dbl_star_arg);
11531206

11541207
/* we no longer have these _n specific call_function's
11551208
* they anyway push args into an array
@@ -1176,18 +1229,18 @@ STATIC void emit_native_call_function(emit_t *emit, int n_positional, int n_keyw
11761229
*/
11771230

11781231
emit_native_pre(emit);
1179-
if (n_positional != 0) {
1180-
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional); // pointer to args
1232+
if (n_positional != 0 || n_keyword != 0) {
1233+
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2 * n_keyword); // pointer to args
11811234
}
11821235
vtype_kind_t vtype_fun;
11831236
emit_pre_pop_reg(emit, &vtype_fun, REG_ARG_1); // the function
11841237
assert(vtype_fun == VTYPE_PYOBJ);
1185-
emit_call_with_imm_arg(emit, MP_F_CALL_FUNCTION_N_KW_FOR_NATIVE, mp_call_function_n_kw_for_native, n_positional, REG_ARG_2);
1238+
emit_call_with_imm_arg(emit, MP_F_CALL_FUNCTION_N_KW_FOR_NATIVE, mp_call_function_n_kw_for_native, n_positional | (n_keyword << 8), REG_ARG_2);
11861239
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
11871240
}
11881241

11891242
STATIC void emit_native_call_method(emit_t *emit, int n_positional, int n_keyword, bool have_star_arg, bool have_dbl_star_arg) {
1190-
assert(n_keyword == 0 && !have_star_arg && !have_dbl_star_arg);
1243+
assert(!have_star_arg && !have_dbl_star_arg);
11911244

11921245
/*
11931246
if (n_positional == 0) {
@@ -1207,12 +1260,13 @@ STATIC void emit_native_call_method(emit_t *emit, int n_positional, int n_keywor
12071260
*/
12081261

12091262
emit_native_pre(emit);
1210-
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, n_positional + 2); // pointer to items, including meth and self
1263+
emit_get_stack_pointer_to_reg_for_pop(emit, REG_ARG_3, 2 + n_positional + 2 * n_keyword); // pointer to items, including meth and self
12111264
emit_call_with_2_imm_args(emit, MP_F_CALL_METHOD_N_KW, mp_call_method_n_kw, n_positional, REG_ARG_1, n_keyword, REG_ARG_2);
12121265
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
12131266
}
12141267

12151268
STATIC void emit_native_return_value(emit_t *emit) {
1269+
DEBUG_printf("return_value\n");
12161270
// easy. since we don't know who we return to, just return the raw value.
12171271
// runtime needs then to know our type signature, but I think that's possible.
12181272
vtype_kind_t vtype;

py/runtime.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,7 @@ void *m_malloc_fail(int num_bytes) {
10271027
// these must correspond to the respective enum
10281028
void *const mp_fun_table[MP_F_NUMBER_OF] = {
10291029
mp_load_const_dec,
1030+
mp_obj_new_int_from_long_str,
10301031
mp_load_const_str,
10311032
mp_load_name,
10321033
mp_load_global,
@@ -1050,6 +1051,11 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
10501051
mp_call_function_n_kw_for_native,
10511052
mp_call_method_n_kw,
10521053
mp_getiter,
1054+
mp_import_name,
1055+
mp_import_from,
1056+
mp_import_all,
1057+
mp_obj_new_slice,
1058+
mp_unpack_sequence,
10531059
mp_iternext,
10541060
};
10551061

py/runtime.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ mp_obj_t mp_load_const_dec(qstr qstr);
2828
mp_obj_t mp_load_const_str(qstr qstr);
2929
mp_obj_t mp_load_const_bytes(qstr qstr);
3030

31-
mp_obj_t mp_make_function_from_id(uint unique_code_id, bool free_unique_code, mp_obj_t def_args, mp_obj_t def_kw_args);
31+
mp_obj_t mp_make_function_from_id(uint unique_code_id, mp_obj_t def_args, mp_obj_t def_kw_args);
32+
mp_obj_t mp_make_function_from_id_and_free(uint unique_code_id, mp_obj_t def_args, mp_obj_t def_kw_args);
3233
mp_obj_t mp_make_function_n(int n_args, void *fun); // fun must have the correct signature for n_args fixed arguments
3334
mp_obj_t mp_make_function_var(int n_args_min, mp_fun_var_t fun);
3435
mp_obj_t mp_make_function_var_between(int n_args_min, int n_args_max, mp_fun_var_t fun); // min and max are inclusive

py/runtime0.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ typedef enum {
6565

6666
typedef enum {
6767
MP_F_LOAD_CONST_DEC = 0,
68+
MP_F_LOAD_CONST_INT,
6869
MP_F_LOAD_CONST_STR,
6970
MP_F_LOAD_NAME,
7071
MP_F_LOAD_GLOBAL,
@@ -89,6 +90,11 @@ typedef enum {
8990
MP_F_CALL_METHOD_N_KW,
9091
MP_F_GETITER,
9192
MP_F_ITERNEXT,
93+
MP_F_IMPORT_NAME,
94+
MP_F_IMPORT_FROM,
95+
MP_F_IMPORT_ALL,
96+
MP_F_NEW_SLICE,
97+
MP_F_UNPACK_SEQUENCE,
9298
MP_F_NUMBER_OF,
9399
} mp_fun_kind_t;
94100

py/vm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -653,14 +653,14 @@ mp_vm_return_kind_t mp_execute_byte_code_2(const byte *code_info, const byte **i
653653

654654
case MP_BC_MAKE_FUNCTION:
655655
DECODE_UINT;
656-
PUSH(mp_make_function_from_id(unum, false, MP_OBJ_NULL, MP_OBJ_NULL));
656+
PUSH(mp_make_function_from_id(unum, MP_OBJ_NULL, MP_OBJ_NULL));
657657
break;
658658

659659
case MP_BC_MAKE_FUNCTION_DEFARGS:
660660
DECODE_UINT;
661661
// Stack layout: def_dict def_tuple <- TOS
662662
obj1 = POP();
663-
SET_TOP(mp_make_function_from_id(unum, false, obj1, TOP()));
663+
SET_TOP(mp_make_function_from_id(unum, obj1, TOP()));
664664
break;
665665

666666
case MP_BC_MAKE_CLOSURE:

tests/run-tests

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ for test_file in tests:
5151
pyb.enter_raw_repl()
5252
output_mupy = pyb.execfile(test_file).replace(b'\r\n', b'\n')
5353
else:
54-
output_mupy = subprocess.check_output([MP_PY, test_file])
54+
output_mupy = subprocess.check_output([MP_PY, '-X', 'emit=bytecode', test_file])
5555
except subprocess.CalledProcessError:
5656
output_mupy = b'CRASH'
5757

0 commit comments

Comments
 (0)