summaryrefslogtreecommitdiff
path: root/py/emitnative.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/emitnative.c')
-rw-r--r--py/emitnative.c71
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);