py/emitnative: Add support for archs with windowed registers.
Such that args/return regs for the parent are different to args/return regs for child calls. For an architecture to use this feature it should define the REG_PARENT_xxx macros before including py/emitnative.c.
This commit is contained in:
parent
27fe84e661
commit
4107597b84
|
@ -94,6 +94,15 @@
|
|||
#define OFFSETOF_OBJ_FUN_BC_GLOBALS (offsetof(mp_obj_fun_bc_t, globals) / sizeof(uintptr_t))
|
||||
#define OFFSETOF_OBJ_FUN_BC_CONST_TABLE (offsetof(mp_obj_fun_bc_t, const_table) / sizeof(uintptr_t))
|
||||
|
||||
// If not already defined, set parent args to same as child call registers
|
||||
#ifndef REG_PARENT_RET
|
||||
#define REG_PARENT_RET REG_RET
|
||||
#define REG_PARENT_ARG_1 REG_ARG_1
|
||||
#define REG_PARENT_ARG_2 REG_ARG_2
|
||||
#define REG_PARENT_ARG_3 REG_ARG_3
|
||||
#define REG_PARENT_ARG_4 REG_ARG_4
|
||||
#endif
|
||||
|
||||
// Word index of nlr_buf_t.ret_val
|
||||
#define NLR_BUF_IDX_RET_VAL (1)
|
||||
|
||||
|
@ -413,16 +422,16 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||
ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs);
|
||||
|
||||
#if N_X86
|
||||
asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);
|
||||
#endif
|
||||
|
||||
// Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, 0);
|
||||
|
||||
// Store function object (passed as first arg) to stack if needed
|
||||
if (NEED_FUN_OBJ(emit)) {
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1);
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
|
||||
}
|
||||
|
||||
// Put n_args in REG_ARG_1, n_kw in REG_ARG_2, args array in REG_LOCAL_3
|
||||
|
@ -431,9 +440,9 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||
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
|
||||
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);
|
||||
ASM_MOV_REG_REG(emit->as, REG_ARG_1, REG_PARENT_ARG_2);
|
||||
ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_3);
|
||||
ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_PARENT_ARG_4);
|
||||
#endif
|
||||
|
||||
// Check number of args matches this function, and call mp_arg_check_num_sig if not
|
||||
|
@ -482,14 +491,14 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||
#if N_X86
|
||||
asm_x86_mov_arg_to_r32(emit->as, 0, REG_GENERATOR_STATE);
|
||||
#else
|
||||
ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_ARG_1);
|
||||
ASM_MOV_REG_REG(emit->as, REG_GENERATOR_STATE, REG_PARENT_ARG_1);
|
||||
#endif
|
||||
|
||||
// Put throw value into LOCAL_IDX_EXC_VAL slot, for yield/yield-from
|
||||
#if N_X86
|
||||
asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);
|
||||
#endif
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_ARG_2);
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_PARENT_ARG_2);
|
||||
|
||||
// Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, LOCAL_IDX_FUN_OBJ(emit));
|
||||
|
@ -505,22 +514,22 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||
// Prepare incoming arguments for call to mp_setup_code_state
|
||||
|
||||
#if N_X86
|
||||
asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_1);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_2);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_3);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_4);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 1, REG_PARENT_ARG_2);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 2, REG_PARENT_ARG_3);
|
||||
asm_x86_mov_arg_to_r32(emit->as, 3, REG_PARENT_ARG_4);
|
||||
#endif
|
||||
|
||||
// Load REG_FUN_TABLE with a pointer to mp_fun_table, found in the const_table
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_LOCAL_3, REG_PARENT_ARG_1, OFFSETOF_OBJ_FUN_BC_CONST_TABLE);
|
||||
ASM_LOAD_REG_REG_OFFSET(emit->as, REG_FUN_TABLE, REG_LOCAL_3, emit->scope->num_pos_args + emit->scope->num_kwonly_args);
|
||||
|
||||
// Set code_state.fun_bc
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_ARG_1);
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_FUN_OBJ(emit), REG_PARENT_ARG_1);
|
||||
|
||||
// Set code_state.ip (offset from start of this function to prelude info)
|
||||
// TODO this encoding may change size in the final pass, need to make it fixed
|
||||
emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_ARG_1);
|
||||
emit_native_mov_state_imm_via(emit, emit->code_state_start + OFFSETOF_CODE_STATE_IP, emit->prelude_offset, REG_PARENT_ARG_1);
|
||||
|
||||
// Set code_state.n_state (only works on little endian targets due to n_state being uint16_t)
|
||||
emit_native_mov_state_imm_via(emit, emit->code_state_start + offsetof(mp_code_state_t, n_state) / sizeof(uintptr_t), emit->n_state, REG_ARG_1);
|
||||
|
@ -528,6 +537,17 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
|
|||
// Put address of code_state into first arg
|
||||
ASM_MOV_REG_LOCAL_ADDR(emit->as, REG_ARG_1, emit->code_state_start);
|
||||
|
||||
// Copy next 3 args if needed
|
||||
#if REG_ARG_2 != REG_PARENT_ARG_2
|
||||
ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_PARENT_ARG_2);
|
||||
#endif
|
||||
#if REG_ARG_3 != REG_PARENT_ARG_3
|
||||
ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_PARENT_ARG_3);
|
||||
#endif
|
||||
#if REG_ARG_4 != REG_PARENT_ARG_4
|
||||
ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_PARENT_ARG_4);
|
||||
#endif
|
||||
|
||||
// Call mp_setup_code_state to prepare code_state structure
|
||||
#if N_THUMB
|
||||
asm_thumb_bl_ind(emit->as, MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4);
|
||||
|
@ -1174,7 +1194,7 @@ STATIC void emit_native_global_exc_entry(emit_t *emit) {
|
|||
ASM_STORE_REG_REG_OFFSET(emit->as, REG_TEMP0, REG_GENERATOR_STATE, OFFSETOF_CODE_STATE_STATE);
|
||||
|
||||
// Load return kind
|
||||
ASM_MOV_REG_IMM(emit->as, REG_RET, MP_VM_RETURN_EXCEPTION);
|
||||
ASM_MOV_REG_IMM(emit->as, REG_PARENT_RET, MP_VM_RETURN_EXCEPTION);
|
||||
|
||||
ASM_EXIT(emit->as);
|
||||
} else {
|
||||
|
@ -1229,7 +1249,7 @@ STATIC void emit_native_global_exc_exit(emit_t *emit) {
|
|||
}
|
||||
|
||||
// Load return value
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_RET, LOCAL_IDX_RET_VAL(emit));
|
||||
ASM_MOV_REG_LOCAL(emit->as, REG_PARENT_RET, LOCAL_IDX_RET_VAL(emit));
|
||||
}
|
||||
|
||||
ASM_EXIT(emit->as);
|
||||
|
@ -2617,13 +2637,13 @@ STATIC void emit_native_return_value(emit_t *emit) {
|
|||
if (peek_vtype(emit, 0) == VTYPE_PTR_NONE) {
|
||||
emit_pre_pop_discard(emit);
|
||||
if (return_vtype == VTYPE_PYOBJ) {
|
||||
emit_native_mov_reg_const(emit, REG_RET, MP_F_CONST_NONE_OBJ);
|
||||
emit_native_mov_reg_const(emit, REG_PARENT_RET, MP_F_CONST_NONE_OBJ);
|
||||
} else {
|
||||
ASM_MOV_REG_IMM(emit->as, REG_ARG_1, 0);
|
||||
}
|
||||
} else {
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_RET : REG_ARG_1);
|
||||
emit_pre_pop_reg(emit, &vtype, return_vtype == VTYPE_PYOBJ ? REG_PARENT_RET : REG_ARG_1);
|
||||
if (vtype != return_vtype) {
|
||||
EMIT_NATIVE_VIPER_TYPE_ERROR(emit,
|
||||
"return expected '%q' but got '%q'",
|
||||
|
@ -2632,15 +2652,18 @@ STATIC void emit_native_return_value(emit_t *emit) {
|
|||
}
|
||||
if (return_vtype != VTYPE_PYOBJ) {
|
||||
emit_call_with_imm_arg(emit, MP_F_CONVERT_NATIVE_TO_OBJ, return_vtype, REG_ARG_2);
|
||||
#if REG_RET != REG_PARENT_ARG_RET
|
||||
ASM_MOV_REG_REG(emit->as, REG_PARENT_RET, REG_RET);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
vtype_kind_t vtype;
|
||||
emit_pre_pop_reg(emit, &vtype, REG_RET);
|
||||
emit_pre_pop_reg(emit, &vtype, REG_PARENT_RET);
|
||||
assert(vtype == VTYPE_PYOBJ);
|
||||
}
|
||||
if (NEED_GLOBAL_EXC_HANDLER(emit)) {
|
||||
// Save return value for the global exception handler to use
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_RET);
|
||||
ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_RET_VAL(emit), REG_PARENT_RET);
|
||||
}
|
||||
emit_native_unwind_jump(emit, emit->exit_label, emit->exc_stack_size);
|
||||
emit->last_emit_was_return_value = true;
|
||||
|
|
Loading…
Reference in New Issue