diff options
Diffstat (limited to 'py/emitnative.c')
-rw-r--r-- | py/emitnative.c | 71 |
1 files changed, 45 insertions, 26 deletions
diff --git a/py/emitnative.c b/py/emitnative.c index c95ef889b..b26beb407 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -207,7 +207,6 @@ struct _emit_t { ASM_T *as; }; -STATIC const uint8_t reg_arg_table[REG_ARG_NUM] = {REG_ARG_1, REG_ARG_2, REG_ARG_3, REG_ARG_4}; STATIC const uint8_t reg_local_table[REG_LOCAL_NUM] = {REG_LOCAL_1, REG_LOCAL_2, REG_LOCAL_3}; STATIC void emit_native_global_exc_entry(emit_t *emit); @@ -237,6 +236,7 @@ void EXPORT_FUN(free)(emit_t *emit) { STATIC void emit_pre_pop_reg(emit_t *emit, vtype_kind_t *vtype, int reg_dest); STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int reg); +STATIC void emit_call_with_imm_arg(emit_t *emit, mp_fun_kind_t fun_kind, mp_int_t arg_val, int arg_reg); STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num); STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num); @@ -311,6 +311,10 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop if (num_locals_in_regs > REG_LOCAL_NUM) { num_locals_in_regs = REG_LOCAL_NUM; } + // Need a spot for REG_LOCAL_3 if 4 or more args (see below) + if (scope->num_pos_args >= 4) { + --num_locals_in_regs; + } } // The locals and stack start at the beginning of the C stack @@ -326,26 +330,45 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table); #endif - // Store arguments into locals + // Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_3 #if N_X86 - for (int i = 0; i < scope->num_pos_args; i++) { - if (i < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit)) { - asm_x86_mov_arg_to_r32(emit->as, i, reg_local_table[i]); - } else { - asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0); - asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, LOCAL_IDX_LOCAL_VAR(emit, i)); - } - } + asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_1); + asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_2); + asm_x86_mov_arg_to_r32(emit->as, 3, REG_LOCAL_3); #else - for (int i = 0; i < scope->num_pos_args; i++) { - if (i < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit)) { - ASM_MOV_REG_REG(emit->as, reg_local_table[i], reg_arg_table[i]); + ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_ARG_2); + ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_3); + ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_4); + #endif + + // Check number of args matches this function, and call mp_arg_check_num_sig if not + ASM_JUMP_IF_REG_NONZERO(emit->as, REG_ARG_2, *emit->label_slot + 4, true); + ASM_MOV_REG_IMM(emit->as, REG_ARG_3, scope->num_pos_args); + ASM_JUMP_IF_REG_EQ(emit->as, REG_ARG_1, REG_ARG_3, *emit->label_slot + 5); + mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 4); + ASM_MOV_REG_IMM(emit->as, REG_ARG_3, MP_OBJ_FUN_MAKE_SIG(scope->num_pos_args, scope->num_pos_args, false)); + ASM_CALL_IND(emit->as, mp_fun_table[MP_F_ARG_CHECK_NUM_SIG], MP_F_ARG_CHECK_NUM_SIG); + mp_asm_base_label_assign(&emit->as->base, *emit->label_slot + 5); + + // Store arguments into locals (reg or stack), converting to native if needed + for (int i = 0; i < emit->scope->num_pos_args; i++) { + int r = REG_ARG_1; + ASM_LOAD_REG_REG_OFFSET(emit->as, REG_ARG_1, REG_LOCAL_3, i); + if (emit->local_vtype[i] != VTYPE_PYOBJ) { + emit_call_with_imm_arg(emit, MP_F_CONVERT_OBJ_TO_NATIVE, emit->local_vtype[i], REG_ARG_2); + r = REG_RET; + } + // REG_LOCAL_3 points to the args array so be sure not to overwrite it if it's still needed + if (i < REG_LOCAL_NUM && CAN_USE_REGS_FOR_LOCALS(emit) && (i != 2 || emit->scope->num_pos_args == 3)) { + ASM_MOV_REG_REG(emit->as, reg_local_table[i], r); } else { - assert(i < REG_ARG_NUM); // should be true; max args is checked above - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_LOCAL_VAR(emit, i), reg_arg_table[i]); + ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_LOCAL_VAR(emit, i), r); } } - #endif + // Get 3rd local from the stack back into REG_LOCAL_3 if this reg couldn't be written to above + if (emit->scope->num_pos_args >= 4 && CAN_USE_REGS_FOR_LOCALS(emit)) { + ASM_MOV_REG_LOCAL(emit->as, REG_LOCAL_3, LOCAL_IDX_LOCAL_VAR(emit, 2)); + } emit_native_global_exc_entry(emit); @@ -477,17 +500,10 @@ STATIC void emit_native_end_pass(emit_t *emit) { void *f = mp_asm_base_get_code(&emit->as->base); mp_uint_t f_len = mp_asm_base_get_code_size(&emit->as->base); - // compute type signature - // note that the lower 4 bits of a vtype are tho correct MP_NATIVE_TYPE_xxx - mp_uint_t type_sig = emit->scope->scope_flags >> MP_SCOPE_FLAG_VIPERRET_POS; - for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) { - type_sig |= (emit->local_vtype[i] & 0xf) << (i * 4 + 4); - } - mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, (mp_uint_t*)((byte*)f + emit->const_table_offset), - emit->scope->num_pos_args, emit->scope->scope_flags, type_sig); + emit->scope->num_pos_args, emit->scope->scope_flags, 0); } } @@ -2409,17 +2425,20 @@ STATIC void emit_native_return_value(emit_t *emit) { if (return_vtype == VTYPE_PYOBJ) { ASM_MOV_REG_IMM(emit->as, REG_RET, (mp_uint_t)mp_const_none); } else { - ASM_MOV_REG_IMM(emit->as, REG_RET, 0); + ASM_MOV_REG_IMM(emit->as, REG_ARG_1, 0); } } else { vtype_kind_t vtype; - emit_pre_pop_reg(emit, &vtype, REG_RET); + emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_RET : REG_ARG_1); if (vtype != return_vtype) { EMIT_NATIVE_VIPER_TYPE_ERROR(emit, "return expected '%q' but got '%q'", vtype_to_qstr(return_vtype), vtype_to_qstr(vtype)); } } + if (return_vtype != VTYPE_PYOBJ) { + emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2); + } } else { vtype_kind_t vtype; emit_pre_pop_reg(emit, &vtype, REG_RET); |