10000 esp32: support for native code generation by dpgeorge · Pull Request #5082 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

esp32: support for native code generation #5082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion mpy-cross/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ STATIC int usage(char **argv) {
"-msmall-int-bits=number : set the maximum bits used to encode a small-int\n"
"-mno-unicode : don't support unicode in compiled strings\n"
"-mcache-lookup-bc : cache map lookups in the bytecode\n"
"-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa\n"
"-march=<arch> : set architecture for native emitter; x86, x64, armv6, armv7m, xtensa, xtensawin\n"
"\n"
"Implementation specific options:\n", argv[0]
);
Expand Down Expand Up @@ -288,6 +288,9 @@ MP_NOINLINE int main_(int argc, char **argv) {
} else if (strcmp(arch, "xtensa") == 0) {
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSA;
mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSA;
} else if (strcmp(arch, "xtensawin") == 0) {
mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_XTENSAWIN;
mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_XTENSAWIN;
} else {
return usage(argv);
}
Expand Down
1 change: 1 addition & 0 deletions mpy-cross/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#define MICROPY_EMIT_ARM (1)
#define MICROPY_EMIT_XTENSA (1)
#define MICROPY_EMIT_INLINE_XTENSA (1)
#define MICROPY_EMIT_XTENSAWIN (1)

#define MICROPY_DYNAMIC_COMPILER (1)
#define MICROPY_COMP_CONST_FOLDING (1)
Expand Down
10 changes: 10 additions & 0 deletions ports/esp32/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,13 @@ void nlr_jump_fail(void *val) {
void mbedtls_debug_set_threshold(int threshold) {
(void)threshold;
}

void *esp_native_code_commit(void *buf, size_t len) {
len = (len + 3) & ~3;
uint32_t *p = heap_caps_malloc(len, MALLOC_CAP_EXEC);
if (p == NULL) {
m_malloc_fail(len);
}
memcpy(p, buf, len);
return p;
}
3 changes: 3 additions & 0 deletions ports/esp32/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

// emitters
#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_EMIT_XTENSAWIN (1)
void *esp_native_code_commit(void*, size_t);
#define MP_PLAT_COMMIT_EXEC(buf, len) esp_native_code_commit(buf, len)

// compiler configuration
#define MICROPY_COMP_MODULE_CONST (1)
Expand Down
42 changes: 33 additions & 9 deletions py/asmxtensa.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@
#include "py/mpconfig.h"

// wrapper around everything in this file
#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
#if MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN

#include "py/asmxtensa.h"

#define WORD_SIZE (4)
#define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80))
#define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800))
#define NUM_REGS_SAVED (5)

void asm_xtensa_end_pass(asm_xtensa_t *as) {
as->num_const = as->cur_const;
Expand Down Expand Up @@ -69,7 +68,7 @@ void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) {
as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);

// adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned
as->stack_adjust = (((NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15;
as->stack_adjust = (((ASM_XTENSA_NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15;
if (SIGNED_FIT8(-as->stack_adjust)) {
asm_xtensa_op_addi(as, ASM_XTENSA_REG_A1, ASM_XTENSA_REG_A1, -as->stack_adjust);
} else {
Expand All @@ -79,14 +78,14 @@ void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) {

// save return value (a0) and callee-save registers (a12, a13, a14, a15)
asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);
for (int i = 1; i < NUM_REGS_SAVED; ++i) {
for (int i = 1; i < ASM_XTENSA_NUM_REGS_SAVED; ++i) {
asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i);
}
}

void asm_xtensa_exit(asm_xtensa_t *as) {
// restore registers
for (int i = NUM_REGS_SAVED - 1; i >= 1; --i) {
for (int i = ASM_XTENSA_NUM_REGS_SAVED - 1; i >= 1; --i) {
asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A11 + i, ASM_XTENSA_REG_A1, i);
}
asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);
Expand All @@ -102,6 +101,22 @@ void asm_xtensa_exit(asm_xtensa_t *as) {
asm_xtensa_op_ret_n(as);
}

void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals) {
// jump over the constants
asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4);
mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte
as->const_table = (uint32_t*)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);

as->stack_adjust = 32 + ((((ASM_XTENSA_NUM_REGS_SAVED_WIN + num_locals) * WORD_SIZE) + 15) & ~15);
asm_xtensa_op_entry(as, ASM_XTENSA_REG_A1, as->stack_adjust);
asm_xtensa_op_s32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);
}

void asm_xtensa_exit_win(asm_xtensa_t *as) {
asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A0, ASM_XTENSA_REG_A1, 0);
asm_xtensa_op_retw_n(as);
}

STATIC uint32_t get_label_dest(asm_xtensa_t *as, uint label) {
assert(label < as->base.max_num_labels);
return as->base.label_offsets[label];
Expand Down Expand Up @@ -178,15 +193,15 @@ void asm_xtensa_mov_reg_i32_optimised(asm_xtensa_t *as, uint reg_dest, uint32_t
}

void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src) {
asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num);
asm_xtensa_op_s32i(as, reg_src, ASM_XTENSA_REG_A1, local_num);
}

void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num) {
asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, NUM_REGS_SAVED + local_num);
asm_xtensa_op_l32i(as, reg_dest, ASM_XTENSA_REG_A1, local_num);
}

void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num) {
uint off = (NUM_REGS_SAVED + local_num) * WORD_SIZE;
uint off = local_num * WORD_SIZE;
if (SIGNED_FIT8(off)) {
asm_xtensa_op_addi(as, reg_dest, ASM_XTENSA_REG_A1, off);
} else {
Expand Down Expand Up @@ -226,4 +241,13 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx) {
asm_xtensa_op_callx0(as, ASM_XTENSA_REG_A0);
}

#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA
void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) {
if (idx < 16) {
asm_xtensa_op_l32i_n(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx);
} else {
asm_xtensa_op_l32i(as, ASM_XTENSA_REG_A8, ASM_XTENSA_REG_FUN_TABLE_WIN, idx);
}
asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8);
}

#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN
80 changes: 74 additions & 6 deletions py/asmxtensa.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@
// callee save: a1, a12, a13, a14, a15
// caller save: a3

// With windowed registers, size 8:
// - a0: return PC
// - a1: stack pointer, full descending, aligned to 16 bytes
// - a2-a7: incoming args, and essentially callee save
// - a2: return value
// - a8-a15: caller save temporaries
// - a10-a15: input args to called function
// - a10: return value of called function
// note: a0-a7 are saved automatically via window shift of called function

#define ASM_XTENSA_REG_A0 (0)
#define ASM_XTENSA_REG_A1 (1)
#define ASM_XTENSA_REG_A2 (2)
Expand Down Expand Up @@ -96,6 +106,10 @@
#define ASM_XTENSA_ENCODE_RI7(op0, s, imm7) \
((((imm7) & 0xf) << 12) | ((s) << 8) | ((imm7) & 0x70) | (op0))

// Number of registers saved on the stack upon entry to function
#define ASM_XTENSA_NUM_REGS_SAVED (5)
#define ASM_XTENSA_NUM_REGS_SAVED_WIN (1)

typedef struct _asm_xtensa_t {
mp_asm_base_t base;
uint32_t cur_const;
Expand All @@ -109,11 +123,18 @@ void asm_xtensa_end_pass(asm_xtensa_t *as);
void asm_xtensa_entry(asm_xtensa_t *as, int num_locals);
void asm_xtensa_exit(asm_xtensa_t *as);

void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals);
void asm_xtensa_exit_win(asm_xtensa_t *as);

void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op);
void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op);

// raw instructions

static inline void asm_xtensa_op_entry(asm_xtensa_t *as, uint reg_src, int32_t num_bytes) {
asm_xtensa_op24(as, ASM_XTENSA_ENCODE_BRI12(6, reg_src, 0, 3, (num_bytes / 8) & 0xfff));
}

static inline void asm_xtensa_op_add_n(asm_xtensa_t *as, uint reg_dest, uint reg_src_a, uint reg_src_b) {
asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(10, reg_dest, reg_src_a, reg_src_b));
}
Expand Down Expand Up @@ -142,6 +163,10 @@ static inline void asm_xtensa_op_callx0(asm_xtensa_t *as, uint reg) {
asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 0));
}

static inline void asm_xtensa_op_callx8(asm_xtensa_t *as, uint reg) {
asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALLX(0, 0, 0, 0, reg, 3, 2));
}

static inline void asm_xtensa_op_j(asm_xtensa_t *as, int32_t rel18) {
asm_xtensa_op24(as, ASM_XTENSA_ENCODE_CALL(6, 0, rel18 & 0x3ffff));
}
Expand Down Expand Up @@ -194,6 +219,10 @@ static inline void asm_xtensa_op_ret_n(asm_xtensa_t *as) {
asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 0));
}

static inline void asm_xtensa_op_retw_n(asm_xtensa_t *as) {
asm_xtensa_op16(as, ASM_XTENSA_ENCODE_RRRN(13, 15, 0, 1));
}

static inline void asm_xtensa_op_s8i(asm_xtensa_t *as, uint reg_src, uint reg_base, uint byte_offset) {
asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 4, reg_base, reg_src, byte_offset & 0xff));
}
Expand Down Expand Up @@ -246,9 +275,11 @@ void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num);
void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num);
void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label);
void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx);
void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx);

// Holds a pointer to mp_fun_table
#define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15
#define ASM_XTENSA_REG_FUN_TABLE_WIN ASM_XTENSA_REG_A7

#if GENERIC_ASM_API

Expand All @@ -257,6 +288,9 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx);

#define ASM_WORD_SIZE (4)

#if !GENERIC_ASM_API_WIN
// Configuration for non-windowed calls

#define REG_RET ASM_XTENSA_REG_A2
#define REG_ARG_1 ASM_XTENSA_REG_A2
#define REG_ARG_2 ASM_XTENSA_REG_A3
Expand All @@ -273,12 +307,47 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx);
#define REG_LOCAL_3 ASM_XTENSA_REG_A14
#define REG_LOCAL_NUM (3)

#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED
#define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE

#define ASM_ENTRY(as, nlocal) asm_xtensa_entry((as), (nlocal))
#define ASM_EXIT(as) asm_xtensa_exit((as))
#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx))

#else
// Configuration for windowed calls with window size 8

#define REG_PARENT_RET ASM_XTENSA_REG_A2
#define REG_PARENT_ARG_1 ASM_XTENSA_REG_A2
#define REG_PARENT_ARG_2 ASM_XTENSA_REG_A3
#define REG_PARENT_ARG_3 ASM_XTENSA_REG_A4
#define REG_PARENT_ARG_4 ASM_XTENSA_REG_A5
#define REG_RET ASM_XTENSA_REG_A10
#define REG_ARG_1 ASM_XTENSA_REG_A10
#define REG_ARG_2 ASM_XTENSA_REG_A11
#define REG_ARG_3 ASM_XTENSA_REG_A12
#define REG_ARG_4 ASM_XTENSA_REG_A13

#define REG_TEMP0 ASM_XTENSA_REG_A10
#define REG_TEMP1 ASM_XTENSA_REG_A11
#define REG_TEMP2 ASM_XTENSA_REG_A12

#define REG_LOCAL_1 ASM_XTENSA_REG_A4
#define REG_LOCAL_2 ASM_XTENSA_REG_A5
#define REG_LOCAL_3 ASM_XTENSA_REG_A6
#define REG_LOCAL_NUM (3)

#define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED_WIN
#define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE_WIN

#define ASM_ENTRY(as, nlocal) asm_xtensa_entry_win((as), (nlocal))
#define ASM_EXIT(as) asm_xtensa_exit_win((as))
#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx))

#endif

#define ASM_T asm_xtensa_t
#define ASM_END_PASS asm_xtensa_end_pass
#define ASM_ENTRY asm_xtensa_entry
#define ASM_EXIT asm_xtensa_exit

#define ASM_JUMP asm_xtensa_j_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \
Expand All @@ -288,15 +357,14 @@ void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx);
#define ASM_JUMP_IF_REG_EQ(as, reg1, reg2, label) \
asm_xtensa_bcc_reg_reg_label(as, ASM_XTENSA_CC_EQ, reg1, reg2, label)
#define ASM_JUMP_REG(as, reg) asm_xtensa_op_jx((as), (reg))
#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx))

#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), (local_num), (reg_src))
#define ASM_MOV_LOCAL_REG(as, local_num, reg_src) asm_xtensa_mov_local_reg((as), ASM_NUM_REGS_SAVED + (local_num), (reg_src))
#define ASM_MOV_REG_IMM(as, reg_dest, imm) asm_xtensa_mov_reg_i32_optimised((as), (reg_dest), (imm))
#define ASM_MOV_REG_IMM_FIX_U16(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm))
#define ASM_MOV_REG_IMM_FIX_WORD(as, reg_dest, imm) asm_xtensa_mov_reg_i32((as), (reg_dest), (imm))
#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), (local_num))
#define ASM_MOV_REG_LOCAL(as, reg_dest, local_num) asm_xtensa_mov_reg_local((as), (reg_dest), ASM_NUM_REGS_SAVED + (local_num))
#define ASM_MOV_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mov_n((as), (reg_dest), (reg_src))
#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), (local_num))
#define ASM_MOV_REG_LOCAL_ADDR(as, reg_dest, local_num) asm_xtensa_mov_reg_local_addr((as), (reg_dest), ASM_NUM_REGS_SAVED + (local_num))
#define ASM_MOV_REG_PCREL(as, reg_dest, label) asm_xtensa_mov_reg_pcrel((as), (reg_dest), (label))

#define ASM_LSL_REG_REG(as, reg_dest, reg_shift) \
Expand Down
4 changes: 4 additions & 0 deletions py/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ STATIC const emit_method_table_t *emit_native_table[] = {
&emit_native_thumb_method_table,
&emit_native_thumb_method_table,
&emit_native_xtensa_method_table,
&emit_native_xtensawin_method_table,
};

#elif MICROPY_EMIT_NATIVE
Expand All @@ -109,6 +110,8 @@ STATIC const emit_method_table_t *emit_native_table[] = {
#define NATIVE_EMITTER(f) emit_native_arm_##f
#elif MICROPY_EMIT_XTENSA
#define NATIVE_EMITTER(f) emit_native_xtensa_##f
#elif MICROPY_EMIT_XTENSAWIN
#define NATIVE_EMITTER(f) emit_native_xtensawin_##f
#else
#error "unknown native emitter"
#endif
Expand All @@ -131,6 +134,7 @@ STATIC const emit_inline_asm_method_table_t *emit_asm_table[] = {
&emit_inline_thumb_method_table,
&emit_inline_thumb_method_table,
&emit_inline_xtensa_method_table,
NULL,
};

#elif MICROPY_EMIT_INLINE_ASM
Expand Down
3 changes: 3 additions & 0 deletions py/emit.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ extern const emit_method_table_t emit_native_x86_method_table;
extern const emit_method_table_t emit_native_thumb_method_table;
extern const emit_method_table_t emit_native_arm_method_table;
extern const emit_method_table_t emit_native_xtensa_method_table;
extern const emit_method_table_t emit_native_xtensawin_method_table;

extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_load_id_ops;
extern const mp_emit_method_table_id_ops_t mp_emit_bc_method_table_store_id_ops;
Expand All @@ -185,6 +186,7 @@ emit_t *emit_native_x86_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t ma
emit_t *emit_native_thumb_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
emit_t *emit_native_arm_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
emit_t *emit_native_xtensa_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);
emit_t *emit_native_xtensawin_new(mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels);

void emit_bc_set_max_num_labels(emit_t* emit, mp_uint_t max_num_labels);

Expand All @@ -194,6 +196,7 @@ void emit_native_x86_free(emit_t *emit);
void emit_native_thumb_free(emit_t *emit);
void emit_native_arm_free(emit_t *emit);
void emit_native_xtensa_free(emit_t *emit);
void emit_native_xtensawin_free(emit_t *emit);

void mp_emit_bc_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scope);
void mp_emit_bc_end_pass(emit_t *emit);
Expand Down
Loading
0