py: Implement full func arg passing for native emitter.

This patch gets full function argument passing working with native
emitter.  Includes named args, keyword args, default args, var args
and var keyword args.  Fully Python compliant.

It reuses the bytecode mp_setup_code_state function to do all the hard
work.  This function is slightly adjusted to accommodate native calls,
and the native emitter is forced a bit to emit similar prelude and
code-info as bytecode.
NotImplemented
Damien George 2015-04-06 22:38:53 +01:00
parent 18bd51707c
commit 9988618e0e
17 changed files with 307 additions and 235 deletions

View File

@ -106,6 +106,10 @@ STATIC byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int num_bytes_to_
}
}
uint asm_thumb_get_code_pos(asm_thumb_t *as) {
return as->code_offset;
}
uint asm_thumb_get_code_size(asm_thumb_t *as) {
return as->code_size;
}

View File

@ -70,6 +70,7 @@ asm_thumb_t *asm_thumb_new(uint max_num_labels);
void asm_thumb_free(asm_thumb_t *as, bool free_code);
void asm_thumb_start_pass(asm_thumb_t *as, uint pass);
void asm_thumb_end_pass(asm_thumb_t *as);
uint asm_thumb_get_code_pos(asm_thumb_t *as);
uint asm_thumb_get_code_size(asm_thumb_t *as);
void *asm_thumb_get_code(asm_thumb_t *as);

View File

@ -176,6 +176,10 @@ STATIC byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int num_bytes_to_writ
}
}
mp_uint_t asm_x64_get_code_pos(asm_x64_t *as) {
return as->code_offset;
}
mp_uint_t asm_x64_get_code_size(asm_x64_t *as) {
return as->code_size;
}
@ -222,6 +226,21 @@ STATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) {
c[7] = IMM64_L7(w64);
}
// align must be a multiple of 2
void asm_x64_align(asm_x64_t* as, mp_uint_t align) {
// TODO fill unused data with NOPs?
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
}
void asm_x64_data(asm_x64_t* as, mp_uint_t bytesize, mp_uint_t val) {
byte *c = asm_x64_get_cur_to_write_bytes(as, bytesize);
// machine is little endian
for (uint i = 0; i < bytesize; i++) {
*c++ = val;
val >>= 8;
}
}
/* unused
STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) {
byte* c;

View File

@ -78,9 +78,13 @@ asm_x64_t* asm_x64_new(mp_uint_t max_num_labels);
void asm_x64_free(asm_x64_t* as, bool free_code);
void asm_x64_start_pass(asm_x64_t *as, uint pass);
void asm_x64_end_pass(asm_x64_t *as);
mp_uint_t asm_x64_get_code_pos(asm_x64_t *as);
mp_uint_t asm_x64_get_code_size(asm_x64_t* as);
void* asm_x64_get_code(asm_x64_t* as);
void asm_x64_align(asm_x64_t *as, mp_uint_t align);
void asm_x64_data(asm_x64_t *as, mp_uint_t bytesize, mp_uint_t val);
void asm_x64_nop(asm_x64_t* as);
void asm_x64_push_r64(asm_x64_t* as, int src_r64);
void asm_x64_pop_r64(asm_x64_t* as, int dest_r64);

View File

@ -162,6 +162,10 @@ STATIC byte *asm_x86_get_cur_to_write_bytes(asm_x86_t *as, int num_bytes_to_writ
}
}
mp_uint_t asm_x86_get_code_pos(asm_x86_t *as) {
return as->code_offset;
}
mp_uint_t asm_x86_get_code_size(asm_x86_t *as) {
return as->code_size;
}
@ -196,6 +200,21 @@ STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) {
c[3] = IMM32_L3(w32);
}
// align must be a multiple of 2
void asm_x86_align(asm_x86_t* as, mp_uint_t align) {
// TODO fill unused data with NOPs?
as->code_offset = (as->code_offset + align - 1) & (~(align - 1));
}
void asm_x86_data(asm_x86_t* as, mp_uint_t bytesize, mp_uint_t val) {
byte *c = asm_x86_get_cur_to_write_bytes(as, bytesize);
// machine is little endian
for (uint i = 0; i < bytesize; i++) {
*c++ = val;
val >>= 8;
}
}
STATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) {
assert(disp_r32 != ASM_X86_REG_ESP);
@ -541,7 +560,13 @@ void asm_x86_push_local_addr(asm_x86_t *as, int local_num, int temp_r32)
void asm_x86_call_ind(asm_x86_t *as, void *ptr, mp_uint_t n_args, int temp_r32) {
// TODO align stack on 16-byte boundary before the call
assert(n_args <= 3);
assert(n_args <= 5);
if (n_args > 4) {
asm_x86_push_r32(as, ASM_X86_REG_ARG_5);
}
if (n_args > 3) {
asm_x86_push_r32(as, ASM_X86_REG_ARG_4);
}
if (n_args > 2) {
asm_x86_push_r32(as, ASM_X86_REG_ARG_3);
}

View File

@ -61,6 +61,8 @@
#define ASM_X86_REG_ARG_1 ASM_X86_REG_EAX
#define ASM_X86_REG_ARG_2 ASM_X86_REG_ECX
#define ASM_X86_REG_ARG_3 ASM_X86_REG_EDX
#define ASM_X86_REG_ARG_4 ASM_X86_REG_EBX
#define ASM_X86_REG_ARG_5 ASM_X86_REG_ESI
// condition codes, used for jcc and setcc (despite their j-name!)
#define ASM_X86_CC_JB (0x2) // below, unsigned
@ -79,9 +81,13 @@ asm_x86_t* asm_x86_new(mp_uint_t max_num_labels);
void asm_x86_free(asm_x86_t* as, bool free_code);
void asm_x86_start_pass(asm_x86_t *as, mp_uint_t pass);
void asm_x86_end_pass(asm_x86_t *as);
mp_uint_t asm_x86_get_code_pos(asm_x86_t *as);
mp_uint_t asm_x86_get_code_size(asm_x86_t* as);
void* asm_x86_get_code(asm_x86_t* as);
void asm_x86_align(asm_x86_t *as, mp_uint_t align);
void asm_x86_data(asm_x86_t *as, mp_uint_t bytesize, mp_uint_t val);
void asm_x86_mov_r32_r32(asm_x86_t* as, int dest_r32, int src_r32);
void asm_x86_mov_i32_to_r32(asm_x86_t *as, int32_t src_i32, int dest_r32);
void asm_x86_mov_i32_to_r32_aligned(asm_x86_t *as, int32_t src_i32, int dest_r32);

13
py/bc.c
View File

@ -78,8 +78,13 @@ STATIC void dump_args(const mp_obj_t *a, mp_uint_t sz) {
#define dump_args(...) (void)0
#endif
// code_state should have ->ip filled in (pointing past code info block),
// as well as ->n_state.
// On entry code_state should be allocated somewhere (stack/heap) and
// contain the following valid entries:
// - code_state->code_info should be the offset in bytes from the start of
// the bytecode chunk to the start of the code-info within the bytecode
// - code_state->ip should contain the offset in bytes from the start of
// the bytecode chunk to the start of the prelude within the bytecode
// - code_state->n_state should be set to the state size (locals plus stack)
void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
// This function is pretty complicated. It's main aim is to be efficient in speed and RAM
// usage for the common case of positional only args.
@ -89,7 +94,7 @@ void mp_setup_code_state(mp_code_state *code_state, mp_obj_t self_in, mp_uint_t
#if MICROPY_STACKLESS
code_state->prev = NULL;
#endif
code_state->code_info = self->bytecode;
code_state->code_info = self->bytecode + (mp_uint_t)code_state->code_info;
code_state->sp = &code_state->state[0] - 1;
code_state->exc_sp = (mp_exc_stack_t*)(code_state->state + n_state) - 1;
@ -227,7 +232,7 @@ continue2:;
}
// bytecode prelude: initialise closed over variables
const byte *ip = code_state->ip;
const byte *ip = self->bytecode + (mp_uint_t)code_state->ip;
mp_uint_t local_num;
while ((local_num = *ip++) != 255) {
code_state->state[n_state - 1 - local_num] =

View File

@ -86,16 +86,17 @@ void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len,
}
#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig) {
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags, mp_uint_t type_sig) {
assert(kind == MP_CODE_NATIVE_PY || kind == MP_CODE_NATIVE_VIPER || kind == MP_CODE_NATIVE_ASM);
rc->kind = kind;
rc->scope_flags = 0;
rc->n_pos_args = n_args;
rc->scope_flags = scope_flags;
rc->n_pos_args = n_pos_args;
rc->n_kwonly_args = n_kwonly_args;
rc->data.u_native.fun_data = fun_data;
rc->data.u_native.type_sig = type_sig;
#ifdef DEBUG_PRINT
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_args=" UINT_FMT "\n", kind, fun_data, fun_len, n_args);
DEBUG_printf("assign native: kind=%d fun=%p len=" UINT_FMT " n_pos_args=" UINT_FMT " n_kwonly_args=" UINT_FMT " flags=%x\n", kind, fun_data, fun_len, n_pos_args, n_kwonly_args, (uint)scope_flags);
for (mp_uint_t i = 0; i < fun_len; i++) {
if (i > 0 && i % 16 == 0) {
DEBUG_printf("\n");
@ -134,7 +135,7 @@ mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp
break;
#if MICROPY_EMIT_NATIVE
case MP_CODE_NATIVE_PY:
fun = mp_obj_new_fun_native(rc->n_pos_args, rc->data.u_native.fun_data);
fun = mp_obj_new_fun_native(rc->scope_flags, rc->n_pos_args, rc->n_kwonly_args, def_args, def_kw_args, rc->data.u_native.fun_data);
break;
case MP_CODE_NATIVE_VIPER:
fun = mp_obj_new_fun_viper(rc->n_pos_args, rc->data.u_native.fun_data, rc->data.u_native.type_sig);

View File

@ -44,7 +44,7 @@ typedef struct _mp_raw_code_t mp_raw_code_t;
mp_raw_code_t *mp_emit_glue_new_raw_code(void);
void mp_emit_glue_assign_bytecode(mp_raw_code_t *rc, byte *code, mp_uint_t len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_args, mp_uint_t type_sig);
void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, void *fun_data, mp_uint_t fun_len, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_uint_t scope_flags, mp_uint_t type_sig);
mp_obj_t mp_make_function_from_raw_code(mp_raw_code_t *rc, mp_obj_t def_args, mp_obj_t def_kw_args);
mp_obj_t mp_make_closure_from_raw_code(mp_raw_code_t *rc, mp_uint_t n_closed_over, const mp_obj_t *args);

View File

@ -90,7 +90,7 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) {
if (emit->pass == MP_PASS_EMIT) {
void *f = asm_thumb_get_code(emit->as);
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0);
mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, asm_thumb_get_code_size(emit->as), emit->scope->num_pos_args, 0, 0, 0);
}
}

View File

@ -48,6 +48,7 @@
#include "py/nlr.h"
#include "py/emit.h"
#include "py/bc.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
@ -70,11 +71,14 @@
#define EXPORT_FUN(name) emit_native_x64_##name
#define ASM_WORD_SIZE (8)
#define REG_RET ASM_X64_REG_RAX
#define REG_ARG_1 ASM_X64_REG_RDI
#define REG_ARG_2 ASM_X64_REG_RSI
#define REG_ARG_3 ASM_X64_REG_RDX
#define REG_ARG_4 ASM_X64_REG_RCX
#define REG_ARG_5 ASM_X64_REG_R08
// caller-save
#define REG_TEMP0 ASM_X64_REG_RAX
@ -94,12 +98,16 @@
#define ASM_NEW asm_x64_new
#define ASM_FREE asm_x64_free
#define ASM_GET_CODE asm_x64_get_code
#define ASM_GET_CODE_POS asm_x64_get_code_pos
#define ASM_GET_CODE_SIZE asm_x64_get_code_size
#define ASM_START_PASS asm_x64_start_pass
#define ASM_END_PASS asm_x64_end_pass
#define ASM_ENTRY asm_x64_entry
#define ASM_EXIT asm_x64_exit
#define ASM_ALIGN asm_x64_align
#define ASM_DATA asm_x64_data
#define ASM_LABEL_ASSIGN asm_x64_label_assign
#define ASM_JUMP asm_x64_jmp_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
@ -202,14 +210,19 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
[MP_F_DELETE_GLOBAL] = 1,
[MP_F_NEW_CELL] = 1,
[MP_F_MAKE_CLOSURE_FROM_RAW_CODE] = 3,
[MP_F_SETUP_CODE_STATE] = 5,
};
#define EXPORT_FUN(name) emit_native_x86_##name
#define ASM_WORD_SIZE (4)
#define REG_RET ASM_X86_REG_EAX
#define REG_ARG_1 ASM_X86_REG_ARG_1
#define REG_ARG_2 ASM_X86_REG_ARG_2
#define REG_ARG_3 ASM_X86_REG_ARG_3
#define REG_ARG_4 ASM_X86_REG_ARG_4
#define REG_ARG_5 ASM_X86_REG_ARG_5
// caller-save, so can be used as temporaries
#define REG_TEMP0 ASM_X86_REG_EAX
@ -229,12 +242,16 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
#define ASM_NEW asm_x86_new
#define ASM_FREE asm_x86_free
#define ASM_GET_CODE asm_x86_get_code
#define ASM_GET_CODE_POS asm_x86_get_code_pos
#define ASM_GET_CODE_SIZE asm_x86_get_code_size
#define ASM_START_PASS asm_x86_start_pass
#define ASM_END_PASS asm_x86_end_pass
#define ASM_ENTRY asm_x86_entry
#define ASM_EXIT asm_x86_exit
#define ASM_ALIGN asm_x86_align
#define ASM_DATA asm_x86_data
#define ASM_LABEL_ASSIGN asm_x86_label_assign
#define ASM_JUMP asm_x86_jmp_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
@ -292,11 +309,14 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
#define EXPORT_FUN(name) emit_native_thumb_##name
#define ASM_WORD_SIZE (4)
#define REG_RET ASM_THUMB_REG_R0
#define REG_ARG_1 ASM_THUMB_REG_R0
#define REG_ARG_2 ASM_THUMB_REG_R1
#define REG_ARG_3 ASM_THUMB_REG_R2
#define REG_ARG_4 ASM_THUMB_REG_R3
// rest of args go on stack
#define REG_TEMP0 ASM_THUMB_REG_R0
#define REG_TEMP1 ASM_THUMB_REG_R1
@ -314,12 +334,16 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = {
#define ASM_NEW asm_thumb_new
#define ASM_FREE asm_thumb_free
#define ASM_GET_CODE asm_thumb_get_code
#define ASM_GET_CODE_POS asm_thumb_get_code_pos
#define ASM_GET_CODE_SIZE asm_thumb_get_code_size
#define ASM_START_PASS asm_thumb_start_pass
#define ASM_END_PASS asm_thumb_end_pass
#define ASM_ENTRY asm_thumb_entry
#define ASM_EXIT asm_thumb_exit
#define ASM_ALIGN asm_thumb_align
#define ASM_DATA asm_thumb_data
#define ASM_LABEL_ASSIGN asm_thumb_label_assign
#define ASM_JUMP asm_thumb_b_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
@ -504,6 +528,10 @@ struct _emit_t {
stack_info_t *stack_info;
vtype_kind_t saved_stack_vtype;
int code_info_size;
int code_info_offset;
int prelude_offset;
int n_state;
int stack_start;
int stack_size;
@ -561,6 +589,8 @@ STATIC void emit_post_push_reg(emit_t *emit, vtype_kind_t vtype, int 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);
#define STATE_START (sizeof(mp_code_state) / sizeof(mp_uint_t))
STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope) {
DEBUG_printf("start_pass(pass=%u, scope=%p)\n", pass, scope);
@ -584,14 +614,23 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
emit->stack_info = m_new(stack_info_t, emit->stack_info_alloc);
}
// set default type for return and arguments
// set default type for return
emit->return_vtype = VTYPE_PYOBJ;
for (mp_uint_t i = 0; i < emit->scope->num_pos_args; i++) {
// set default type for arguments
mp_uint_t num_args = emit->scope->num_pos_args + emit->scope->num_kwonly_args;
if (scope->scope_flags & MP_SCOPE_FLAG_VARARGS) {
num_args += 1;
}
if (scope->scope_flags & MP_SCOPE_FLAG_VARKEYWORDS) {
num_args += 1;
}
for (mp_uint_t i = 0; i < num_args; i++) {
emit->local_vtype[i] = VTYPE_PYOBJ;
}
// local variables begin unbound, and have unknown type
for (mp_uint_t i = emit->scope->num_pos_args; i < emit->local_vtype_alloc; i++) {
for (mp_uint_t i = num_args; i < emit->local_vtype_alloc; i++) {
emit->local_vtype[i] = VTYPE_UNBOUND;
}
@ -603,107 +642,157 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop
ASM_START_PASS(emit->as, pass == MP_PASS_EMIT ? ASM_PASS_EMIT : ASM_PASS_COMPUTE);
// entry to function
int num_locals = 0;
if (pass > MP_PASS_SCOPE) {
num_locals = scope->num_locals - REG_LOCAL_NUM;
if (num_locals < 0) {
num_locals = 0;
}
emit->stack_start = num_locals;
num_locals += scope->stack_size;
}
ASM_ENTRY(emit->as, num_locals);
// generate code for entry to function
// initialise locals from parameters
#if N_X64
for (int i = 0; i < scope->num_pos_args; i++) {
if (i == 0) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
} else if (i == 1) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
} else if (i == 2) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
} else if (i == 3) {
asm_x64_mov_r64_to_local(emit->as, REG_ARG_4, i - REG_LOCAL_NUM);
} else {
// TODO not implemented
assert(0);
if (emit->do_viper_types) {
// entry to function
int num_locals = 0;
if (pass > MP_PASS_SCOPE) {
num_locals = scope->num_locals - REG_LOCAL_NUM;
if (num_locals < 0) {
num_locals = 0;
}
emit->stack_start = num_locals;
num_locals += scope->stack_size;
}
}
#elif N_X86
for (int i = 0; i < scope->num_pos_args; i++) {
if (i == 0) {
asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1);
} else if (i == 1) {
asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2);
} else if (i == 2) {
asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3);
} else {
asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0);
asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM);
ASM_ENTRY(emit->as, num_locals);
#if N_X86
for (int i = 0; i < scope->num_pos_args; i++) {
if (i == 0) {
asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_1);
} else if (i == 1) {
asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_2);
} else if (i == 2) {
asm_x86_mov_arg_to_r32(emit->as, i, REG_LOCAL_3);
} else {
asm_x86_mov_arg_to_r32(emit->as, i, REG_TEMP0);
asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, i - REG_LOCAL_NUM);
}
}
}
#elif N_THUMB
for (int i = 0; i < scope->num_pos_args; i++) {
if (i == 0) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
} else if (i == 1) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
} else if (i == 2) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
} else if (i == 3) {
asm_thumb_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
} else {
// TODO not implemented
assert(0);
#else
for (int i = 0; i < scope->num_pos_args; i++) {
if (i == 0) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
} else if (i == 1) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
} else if (i == 2) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
} else if (i == 3) {
ASM_MOV_REG_TO_LOCAL(emit->as, REG_ARG_4, i - REG_LOCAL_NUM);
} else {
// TODO not implemented
assert(0);
}
}
#endif
} else {
// work out size of state (locals plus stack)
emit->n_state = scope->num_locals + scope->stack_size;
// allocate space on C-stack for code_state structure, which includes state
ASM_ENTRY(emit->as, STATE_START + emit->n_state);
// prepare incoming arguments for call to mp_setup_code_state
#if N_X86
asm_x86_mov_arg_to_r32(emit->as, 0, REG_ARG_2);
asm_x86_mov_arg_to_r32(emit->as, 1, REG_ARG_3);
asm_x86_mov_arg_to_r32(emit->as, 2, REG_ARG_4);
asm_x86_mov_arg_to_r32(emit->as, 3, REG_ARG_5);
#else
#if N_THUMB
ASM_MOV_REG_REG(emit->as, ASM_THUMB_REG_R4, REG_ARG_4);
#else
ASM_MOV_REG_REG(emit->as, REG_ARG_5, REG_ARG_4);
#endif
ASM_MOV_REG_REG(emit->as, REG_ARG_4, REG_ARG_3);
ASM_MOV_REG_REG(emit->as, REG_ARG_3, REG_ARG_2);
ASM_MOV_REG_REG(emit->as, REG_ARG_2, REG_ARG_1);
#endif
// set code_state.code_info (offset from start of this function to code_info data)
// XXX this encoding may change size
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->code_info_offset, offsetof(mp_code_state, code_info) / sizeof(mp_uint_t), REG_ARG_1);
// set code_state.ip (offset from start of this function to prelude info)
// XXX this encoding may change size
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->prelude_offset, offsetof(mp_code_state, ip) / sizeof(mp_uint_t), REG_ARG_1);
// set code_state.n_state
ASM_MOV_IMM_TO_LOCAL_USING(emit->as, emit->n_state, offsetof(mp_code_state, n_state) / sizeof(mp_uint_t), REG_ARG_1);
// put address of code_state into first arg
ASM_MOV_LOCAL_ADDR_TO_REG(emit->as, 0, REG_ARG_1);
// call mp_setup_code_state to prepare code_state structure
#if N_THUMB
asm_thumb_op16(emit->as, 0xb400 | (1 << ASM_THUMB_REG_R4)); // push 5th arg
asm_thumb_bl_ind(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE, ASM_THUMB_REG_R4);
asm_thumb_op16(emit->as, 0xbc00 | (1 << REG_RET)); // pop dummy (was 5th arg)
#else
ASM_CALL_IND(emit->as, mp_fun_table[MP_F_SETUP_CODE_STATE], MP_F_SETUP_CODE_STATE);
#endif
// cache some locals in registers
if (scope->num_locals > 0) {
ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 0, REG_LOCAL_1);
if (scope->num_locals > 1) {
ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 1, REG_LOCAL_2);
if (scope->num_locals > 2) {
ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - 2, REG_LOCAL_3);
}
}
}
// set the type of closed over variables
for (mp_uint_t i = 0; i < scope->id_info_len; i++) {
id_info_t *id = &scope->id_info[i];
if (id->kind == ID_INFO_KIND_CELL) {
emit->local_vtype[id->local_num] = VTYPE_PYOBJ;
}
}
}
#if N_THUMB
// TODO don't load r7 if we don't need it
asm_thumb_mov_reg_i32(emit->as, ASM_THUMB_REG_R7, (mp_uint_t)mp_fun_table);
#elif N_ARM
for (int i = 0; i < scope->num_pos_args; i++) {
if (i == 0) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_1, REG_ARG_1);
} else if (i == 1) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_2, REG_ARG_2);
} else if (i == 2) {
ASM_MOV_REG_REG(emit->as, REG_LOCAL_3, REG_ARG_3);
} else if (i == 3) {
asm_arm_mov_local_reg(emit->as, i - REG_LOCAL_NUM, REG_ARG_4);
} else {
// TODO not implemented
assert(0);
}
}
#endif
#if N_ARM
// TODO don't load r7 if we don't need it
asm_arm_mov_reg_i32(emit->as, ASM_ARM_REG_R7, (mp_uint_t)mp_fun_table);
#else
#error not implemented
#endif
// initialise closed over variables
for (int i = 0; i < scope->id_info_len; i++) {
id_info_t *id = &scope->id_info[i];
if (id->kind == ID_INFO_KIND_CELL) {
if (emit->local_vtype[id->local_num] != VTYPE_UNBOUND) {
emit_native_load_fast(emit, id->qst, id->local_num);
vtype_kind_t vtype;
emit_pre_pop_reg(emit, &vtype, REG_ARG_1);
}
ASM_CALL_IND(emit->as, mp_fun_table[MP_F_NEW_CELL], MP_F_NEW_CELL);
emit_post_push_reg(emit, VTYPE_PYOBJ, REG_RET);
emit_native_store_fast(emit, id->qst, id->local_num);
}
}
#endif
}
STATIC void emit_native_end_pass(emit_t *emit) {
if (!emit->last_emit_was_return_value) {
ASM_EXIT(emit->as);
}
if (!emit->do_viper_types) {
// write dummy code info (for mp_setup_code_state to parse) and arg names
emit->code_info_offset = ASM_GET_CODE_POS(emit->as);
ASM_DATA(emit->as, 1, emit->code_info_size);
ASM_ALIGN(emit->as, ASM_WORD_SIZE);
emit->code_info_size = ASM_GET_CODE_POS(emit->as) - emit->code_info_offset;
for (int i = 0; i < emit->scope->num_pos_args + emit->scope->num_kwonly_args; i++) {
ASM_DATA(emit->as, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(emit->scope->id_info[i].qst));
}
// bytecode prelude: initialise closed over variables
emit->prelude_offset = ASM_GET_CODE_POS(emit->as);
for (int i = 0; i < emit->scope->id_info_len; i++) {
id_info_t *id = &emit->scope->id_info[i];
if (id->kind == ID_INFO_KIND_CELL) {
assert(id->local_num < 255);
ASM_DATA(emit->as, 1, id->local_num); // write the local which should be converted to a cell
}
}
ASM_DATA(emit->as, 1, 255); // end of list sentinel
}
ASM_END_PASS(emit->as);
// check stack is back to zero size
@ -722,7 +811,10 @@ STATIC void emit_native_end_pass(emit_t *emit) {
type_sig |= (emit->local_vtype[i] & 3) << (i * 2 + 2);
}
mp_emit_glue_assign_native(emit->scope->raw_code, emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY, f, f_len, emit->scope->num_pos_args, type_sig);
mp_emit_glue_assign_native(emit->scope->raw_code,
emit->do_viper_types ? MP_CODE_NATIVE_VIPER : MP_CODE_NATIVE_PY,
f, f_len, emit->scope->num_pos_args, emit->scope->num_kwonly_args,
emit->scope->scope_flags, type_sig);
}
}
@ -1199,7 +1291,6 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
printf("ViperTypeError: local %s used before type known\n", qstr_str(qst));
}
emit_native_pre(emit);
#if N_X64
if (local_num == 0) {
emit_post_push_reg(emit, vtype, REG_LOCAL_1);
} else if (local_num == 1) {
@ -1208,48 +1299,13 @@ STATIC void emit_native_load_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
emit_post_push_reg(emit, vtype, REG_LOCAL_3);
} else {
need_reg_single(emit, REG_TEMP0, 0);
asm_x64_mov_local_to_r64(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
if (emit->do_viper_types) {
ASM_MOV_LOCAL_TO_REG(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
} else {
ASM_MOV_LOCAL_TO_REG(emit->as, STATE_START + emit->n_state - 1 - local_num, REG_TEMP0);
}
emit_post_push_reg(emit, vtype, REG_TEMP0);
}
#elif N_X86
if (local_num == 0) {
emit_post_push_reg(emit, vtype, REG_LOCAL_1);
} else if (local_num == 1) {
emit_post_push_reg(emit, vtype, REG_LOCAL_2);
} else if (local_num == 2) {
emit_post_push_reg(emit, vtype, REG_LOCAL_3);
} else {
need_reg_single(emit, REG_TEMP0, 0);
asm_x86_mov_local_to_r32(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
emit_post_push_reg(emit, vtype, REG_TEMP0);
}
#elif N_THUMB
if (local_num == 0) {
emit_post_push_reg(emit, vtype, REG_LOCAL_1);
} else if (local_num == 1) {
emit_post_push_reg(emit, vtype, REG_LOCAL_2);
} else if (local_num == 2) {
emit_post_push_reg(emit, vtype, REG_LOCAL_3);
} else {
need_reg_single(emit, REG_TEMP0, 0);
asm_thumb_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
emit_post_push_reg(emit, vtype, REG_TEMP0);
}
#elif N_ARM
if (local_num == 0) {
emit_post_push_reg(emit, vtype, REG_LOCAL_1);
} else if (local_num == 1) {
emit_post_push_reg(emit, vtype, REG_LOCAL_2);
} else if (local_num == 2) {
emit_post_push_reg(emit, vtype, REG_LOCAL_3);
} else {
need_reg_single(emit, REG_TEMP0, 0);
asm_arm_mov_reg_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
emit_post_push_reg(emit, vtype, REG_TEMP0);
}
#else
#error not implemented
#endif
}
STATIC void emit_native_load_deref(emit_t *emit, qstr qst, mp_uint_t local_num) {
@ -1417,7 +1473,6 @@ STATIC void emit_native_load_subscr(emit_t *emit) {
STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num) {
vtype_kind_t vtype;
#if N_X64
if (local_num == 0) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
} else if (local_num == 1) {
@ -1426,45 +1481,12 @@ STATIC void emit_native_store_fast(emit_t *emit, qstr qst, mp_uint_t local_num)
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
} else {
emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
asm_x64_mov_r64_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
if (emit->do_viper_types) {
ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
} else {
ASM_MOV_REG_TO_LOCAL(emit->as, REG_TEMP0, STATE_START + emit->n_state - 1 - local_num);
}
}
#elif N_X86
if (local_num == 0) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
} else if (local_num == 1) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
} else if (local_num == 2) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
} else {
emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
asm_x86_mov_r32_to_local(emit->as, REG_TEMP0, local_num - REG_LOCAL_NUM);
}
#elif N_THUMB
if (local_num == 0) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
} else if (local_num == 1) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
} else if (local_num == 2) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
} else {
emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
asm_thumb_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
}
#elif N_ARM
if (local_num == 0) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_1);
} else if (local_num == 1) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_2);
} else if (local_num == 2) {
emit_pre_pop_reg(emit, &vtype, REG_LOCAL_3);
} else {
emit_pre_pop_reg(emit, &vtype, REG_TEMP0);
asm_arm_mov_local_reg(emit->as, local_num - REG_LOCAL_NUM, REG_TEMP0);
}
#else
#error not implemented
#endif
emit_post(emit);
// check types

View File

@ -32,6 +32,7 @@
#include "py/runtime0.h"
#include "py/runtime.h"
#include "py/emitglue.h"
#include "py/bc.h"
#if MICROPY_EMIT_NATIVE
@ -135,6 +136,7 @@ void *const mp_fun_table[MP_F_NUMBER_OF] = {
mp_delete_global,
mp_obj_new_cell,
mp_make_closure_from_raw_code,
mp_setup_code_state,
};
/*

View File

@ -469,7 +469,7 @@ mp_obj_t mp_obj_new_exception_args(const mp_obj_type_t *exc_type, mp_uint_t n_ar
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg);
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt, ...); // counts args by number of % symbols in fmt, excluding %%; can only handle void* sizes (ie no float/double!)
mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args, mp_obj_t def_kw_args, const byte *code);
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data);
mp_obj_t mp_obj_new_fun_native(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data);
mp_obj_t mp_obj_new_fun_viper(mp_uint_t n_args, void *fun_data, mp_uint_t type_sig);
mp_obj_t mp_obj_new_fun_asm(mp_uint_t n_args, void *fun_data);
mp_obj_t mp_obj_new_gen_wrap(mp_obj_t fun);

View File

@ -108,8 +108,18 @@ qstr mp_obj_code_get_name(const byte *code_info) {
return mp_decode_uint(&code_info);
}
#if MICROPY_EMIT_NATIVE
STATIC const mp_obj_type_t mp_type_fun_native;
#endif
qstr mp_obj_fun_get_name(mp_const_obj_t fun_in) {
const mp_obj_fun_bc_t *fun = fun_in;
#if MICROPY_EMIT_NATIVE
if (fun->base.type == &mp_type_fun_native) {
// TODO native functions don't have name stored
return MP_QSTR_;
}
#endif
const byte *code_info = fun->bytecode;
return mp_obj_code_get_name(code_info);
}
@ -168,7 +178,8 @@ mp_code_state *mp_obj_fun_bc_prepare_codestate(mp_obj_t self_in, mp_uint_t n_arg
}
code_state->n_state = n_state;
code_state->ip = ip;
code_state->code_info = 0; // offset to code-info
code_state->ip = ip - self->bytecode; // offset to prelude
mp_setup_code_state(code_state, self_in, n_args, n_kw, args);
// execute the byte code with the correct globals context
@ -216,7 +227,8 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw,
}
code_state->n_state = n_state;
code_state->ip = ip;
code_state->code_info = 0; // offset to code-info
code_state->ip = (byte*)(ip - self->bytecode); // offset to prelude
mp_setup_code_state(code_state, self_in, n_args, n_kw, args);
// execute the byte code with the correct globals context
@ -339,42 +351,11 @@ mp_obj_t mp_obj_new_fun_bc(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_
#if MICROPY_EMIT_NATIVE
typedef struct _mp_obj_fun_native_t {
mp_obj_base_t base;
mp_uint_t n_args;
void *fun_data; // GC must be able to trace this pointer
// TODO add mp_map_t *globals
} mp_obj_fun_native_t;
typedef mp_obj_t (*native_fun_0_t)(void);
typedef mp_obj_t (*native_fun_1_t)(mp_obj_t);
typedef mp_obj_t (*native_fun_2_t)(mp_obj_t, mp_obj_t);
typedef mp_obj_t (*native_fun_3_t)(mp_obj_t, mp_obj_t, mp_obj_t);
STATIC mp_obj_t fun_native_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) {
mp_obj_fun_native_t *self = self_in;
mp_arg_check_num(n_args, n_kw, self->n_args, self->n_args, false);
void *fun = MICROPY_MAKE_POINTER_CALLABLE(self->fun_data);
switch (n_args) {
case 0:
return ((native_fun_0_t)fun)();
case 1:
return ((native_fun_1_t)fun)(args[0]);
case 2:
return ((native_fun_2_t)fun)(args[0], args[1]);
case 3:
return ((native_fun_3_t)fun)(args[0], args[1], args[2]);
default:
assert(0);
return mp_const_none;
}
MP_STACK_CHECK();
mp_obj_fun_bc_t *self = self_in;
mp_call_fun_t fun = MICROPY_MAKE_POINTER_CALLABLE((void*)self->bytecode);
return fun(self_in, n_args, n_kw, args);
}
STATIC const mp_obj_type_t mp_type_fun_native = {
@ -383,12 +364,9 @@ STATIC const mp_obj_type_t mp_type_fun_native = {
.call = fun_native_call,
};
mp_obj_t mp_obj_new_fun_native(mp_uint_t n_args, void *fun_data) {
assert(0 <= n_args && n_args <= 3);
mp_obj_fun_native_t *o = m_new_obj(mp_obj_fun_native_t);
mp_obj_t mp_obj_new_fun_native(mp_uint_t scope_flags, mp_uint_t n_pos_args, mp_uint_t n_kwonly_args, mp_obj_t def_args_in, mp_obj_t def_kw_args, const void *fun_data) {
mp_obj_fun_bc_t *o = mp_obj_new_fun_bc(scope_flags, n_pos_args, n_kwonly_args, def_args_in, def_kw_args, (const byte*)fun_data);
o->base.type = &mp_type_fun_native;
o->n_args = n_args;
o->fun_data = fun_data;
return o;
}

View File

@ -73,7 +73,8 @@ STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw
o->globals = self_fun->globals;
o->code_state.n_state = n_state;
o->code_state.ip = ip;
o->code_state.code_info = 0; // offset to code-info
o->code_state.ip = (byte*)(ip - self_fun->bytecode); // offset to prelude
mp_setup_code_state(&o->code_state, self_fun, n_args, n_kw, args);
return o;
}

View File

@ -151,6 +151,7 @@ typedef enum {
MP_F_DELETE_GLOBAL,
MP_F_NEW_CELL,
MP_F_MAKE_CLOSURE_FROM_RAW_CODE,
MP_F_SETUP_CODE_STATE,
MP_F_NUMBER_OF,
} mp_fun_kind_t;

View File

@ -154,19 +154,22 @@ def run_tests(pyb, tests, args):
# Some tests are known to fail with native emitter
# Remove them from the below when they work
if args.emit == 'native':
skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class closure_defargs del_deref del_local fun3 fun_calldblstar fun_callstar fun_callstardblstar fun_defargs fun_defargs2 fun_kwargs fun_kwonly fun_kwonlydef fun_kwvarargs fun_varargs gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_throw generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send globals_del string_format string_join subclass_native2_list subclass_native2_tuple try_finally_loops try_finally_return try_reraise try_reraise2 unboundlocal with1 with_break with_continue with_return'.split()})
skip_tests.update({'basics/%s.py' % t for t in 'gen_yield_from gen_yield_from_close gen_yield_from_ducktype gen_yield_from_exc gen_yield_from_iter gen_yield_from_send gen_yield_from_throw generator1 generator2 generator_args generator_close generator_closure generator_exc generator_return generator_send'.split()}) # require yield
skip_tests.update({'basics/%s.py' % t for t in 'bytes_gen class_store_class globals_del string_join'.split()}) # require yield
skip_tests.update({'basics/%s.py' % t for t in 'try_reraise try_reraise2'.split()}) # require raise_varargs
skip_tests.update({'basics/%s.py' % t for t in 'with1 with_break with_continue with_return'.split()}) # require with
skip_tests.add('basics/array_construct2.py') # requires generators
skip_tests.add('basics/bool1.py') # seems to randomly fail
skip_tests.add('basics/boundmeth1.py') # requires support for many args
skip_tests.add('basics/closure_manyvars.py') # requires closures
skip_tests.add('float/string_format.py')
skip_tests.add('import/gen_context.py')
skip_tests.add('io/file_with.py')
skip_tests.add('io/stringio_with.py')
skip_tests.add('micropython/heapalloc.py')
skip_tests.add('misc/features.py')
skip_tests.add('misc/recursion.py')
skip_tests.add('misc/rge_sm.py')
skip_tests.add('basics/del_deref.py') # requires checking for unbound local
skip_tests.add('basics/del_local.py') # requires checking for unbound local
skip_tests.add('basics/try_finally_loops.py') # requires proper try finally code
skip_tests.add('basics/try_finally_return.py') # requires proper try finally code
skip_tests.add('basics/unboundlocal.py') # requires checking for unbound local
skip_tests.add('import/gen_context.py') # requires yield_value
skip_tests.add('io/file_with.py') # requires with
skip_tests.add('io/stringio_with.py') # requires with
skip_tests.add('misc/features.py') # requires raise_varargs
skip_tests.add('misc/rge_sm.py') # requires yield
skip_tests.add('misc/print_exception.py') # because native doesn't have proper traceback info
for test_file in tests: