From 612599587bef71e1deca9a77a8e2e16e69b045de Mon Sep 17 00:00:00 2001 From: Damien George <damien.p.george@gmail.com> Date: Mon, 28 Nov 2016 09:24:50 +1100 Subject: [PATCH] py: Factor out common code from assemblers into asmbase.[ch]. All assemblers should "derive" from mp_asm_base_t. --- py/asmarm.c | 99 -------------------------------- py/asmarm.h | 20 ++----- py/asmbase.c | 104 +++++++++++++++++++++++++++++++++ py/asmbase.h | 68 ++++++++++++++++++++++ py/asmthumb.c | 134 ++++++------------------------------------- py/asmthumb.h | 21 ++----- py/asmx64.c | 114 +++--------------------------------- py/asmx64.h | 24 +++----- py/asmx86.c | 102 -------------------------------- py/asmx86.h | 24 +++----- py/emitinlinethumb.c | 18 +++--- py/emitnative.c | 98 ++++++++----------------------- py/py.mk | 1 + 13 files changed, 262 insertions(+), 565 deletions(-) create mode 100644 py/asmbase.c create mode 100644 py/asmbase.h diff --git a/py/asmarm.c b/py/asmarm.c index 2c389ac8c..663f86156 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -38,50 +38,6 @@ #define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000) -struct _asm_arm_t { - uint pass; - mp_uint_t code_offset; - mp_uint_t code_size; - byte *code_base; - byte dummy_data[4]; - - mp_uint_t max_num_labels; - mp_uint_t *label_offsets; - uint push_reglist; - uint stack_adjust; -}; - -asm_arm_t *asm_arm_new(uint max_num_labels) { - asm_arm_t *as; - - as = m_new0(asm_arm_t, 1); - as->max_num_labels = max_num_labels; - as->label_offsets = m_new(mp_uint_t, max_num_labels); - - return as; -} - -void asm_arm_free(asm_arm_t *as, bool free_code) { - if (free_code) { - MP_PLAT_FREE_EXEC(as->code_base, as->code_size); - } - m_del(mp_uint_t, as->label_offsets, as->max_num_labels); - m_del_obj(asm_arm_t, as); -} - -void asm_arm_start_pass(asm_arm_t *as, uint pass) { - if (pass == ASM_ARM_PASS_COMPUTE) { - memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t)); - } else if (pass == ASM_ARM_PASS_EMIT) { - MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); - if (as->code_base == NULL) { - assert(0); - } - } - as->pass = pass; - as->code_offset = 0; -} - void asm_arm_end_pass(asm_arm_t *as) { if (as->pass == ASM_ARM_PASS_EMIT) { #ifdef __arm__ @@ -97,32 +53,6 @@ void asm_arm_end_pass(asm_arm_t *as) { } } -// all functions must go through this one to emit bytes -// if as->pass < ASM_ARM_PASS_EMIT, then this function only returns a buffer of 4 bytes length -STATIC byte *asm_arm_get_cur_to_write_bytes(asm_arm_t *as, int num_bytes_to_write) { - if (as->pass < ASM_ARM_PASS_EMIT) { - as->code_offset += num_bytes_to_write; - return as->dummy_data; - } else { - assert(as->code_offset + num_bytes_to_write <= as->code_size); - byte *c = as->code_base + as->code_offset; - as->code_offset += num_bytes_to_write; - return c; - } -} - -uint asm_arm_get_code_pos(asm_arm_t *as) { - return as->code_offset; -} - -uint asm_arm_get_code_size(asm_arm_t *as) { - return as->code_size; -} - -void *asm_arm_get_code(asm_arm_t *as) { - return as->code_base; -} - // Insert word into instruction flow STATIC void emit(asm_arm_t *as, uint op) { *(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = op; @@ -263,35 +193,6 @@ void asm_arm_pop(asm_arm_t *as, uint reglist) { emit_al(as, asm_arm_op_pop(reglist)); } -void asm_arm_label_assign(asm_arm_t *as, uint label) { - assert(label < as->max_num_labels); - if (as->pass < ASM_ARM_PASS_EMIT) { - // assign label offset - assert(as->label_offsets[label] == -1); - as->label_offsets[label] = as->code_offset; - } else { - // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT - assert(as->label_offsets[label] == as->code_offset); - } -} - -void asm_arm_align(asm_arm_t* as, uint align) { - // TODO fill unused data with NOPs? - as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); -} - -void asm_arm_data(asm_arm_t* as, uint bytesize, uint val) { - byte *c = asm_arm_get_cur_to_write_bytes(as, bytesize); - // only write to the buffer in the emit pass (otherwise we overflow dummy_data) - if (as->pass == ASM_ARM_PASS_EMIT) { - // little endian - for (uint i = 0; i < bytesize; i++) { - *c++ = val; - val >>= 8; - } - } -} - void asm_arm_mov_reg_reg(asm_arm_t *as, uint reg_dest, uint reg_src) { emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src)); } diff --git a/py/asmarm.h b/py/asmarm.h index 15e7a047b..263721057 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -28,9 +28,7 @@ #define __MICROPY_INCLUDED_PY_ASMARM_H__ #include "py/misc.h" - -#define ASM_ARM_PASS_COMPUTE (1) -#define ASM_ARM_PASS_EMIT (2) +#include "py/asmbase.h" #define ASM_ARM_REG_R0 (0) #define ASM_ARM_REG_R1 (1) @@ -68,22 +66,16 @@ #define ASM_ARM_CC_LE (0xd << 28) #define ASM_ARM_CC_AL (0xe << 28) -typedef struct _asm_arm_t asm_arm_t; +typedef struct _asm_arm_t { + mp_asm_base_t base; + uint push_reglist; + uint stack_adjust; +} asm_arm_t; -asm_arm_t *asm_arm_new(uint max_num_labels); -void asm_arm_free(asm_arm_t *as, bool free_code); -void asm_arm_start_pass(asm_arm_t *as, uint pass); void asm_arm_end_pass(asm_arm_t *as); -uint asm_arm_get_code_pos(asm_arm_t *as); -uint asm_arm_get_code_size(asm_arm_t *as); -void *asm_arm_get_code(asm_arm_t *as); void asm_arm_entry(asm_arm_t *as, int num_locals); void asm_arm_exit(asm_arm_t *as); -void asm_arm_label_assign(asm_arm_t *as, uint label); - -void asm_arm_align(asm_arm_t* as, uint align); -void asm_arm_data(asm_arm_t* as, uint bytesize, uint val); void asm_arm_bkpt(asm_arm_t *as); diff --git a/py/asmbase.c b/py/asmbase.c new file mode 100644 index 000000000..916f7c5ec --- /dev/null +++ b/py/asmbase.c @@ -0,0 +1,104 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <assert.h> +#include <string.h> + +#include "py/obj.h" +#include "py/misc.h" +#include "py/asmbase.h" + +#if MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB + +void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels) { + as->max_num_labels = max_num_labels; + as->label_offsets = m_new(size_t, max_num_labels); +} + +void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code) { + if (free_code) { + MP_PLAT_FREE_EXEC(as->code_base, as->code_size); + } + m_del(size_t, as->label_offsets, as->max_num_labels); +} + +void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { + if (pass == MP_ASM_PASS_COMPUTE) { + // reset all labels + memset(as->label_offsets, -1, as->max_num_labels * sizeof(size_t)); + } else if (pass == MP_ASM_PASS_EMIT) { + // allocating executable RAM is platform specific + MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); + assert(as->code_base != NULL); + } + as->pass = pass; + as->code_offset = 0; +} + +// all functions must go through this one to emit bytes +// if as->pass < MP_ASM_PASS_EMIT, then this function returns dummy_data +uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write) { + if (as->pass < MP_ASM_PASS_EMIT) { + as->code_offset += num_bytes_to_write; + return as->dummy_data; + } else { + assert(as->code_offset + num_bytes_to_write <= as->code_size); + uint8_t *c = as->code_base + as->code_offset; + as->code_offset += num_bytes_to_write; + return c; + } +} + +void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) { + assert(label < as->max_num_labels); + if (as->pass < MP_ASM_PASS_EMIT) { + // assign label offset + assert(as->label_offsets[label] == (size_t)-1); + as->label_offsets[label] = as->code_offset; + } else { + // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT + assert(as->label_offsets[label] == as->code_offset); + } +} + +// align must be a multiple of 2 +void mp_asm_base_align(mp_asm_base_t* as, unsigned int align) { + as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); +} + +// this function assumes a little endian machine +void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val) { + uint8_t *c = mp_asm_base_get_cur_to_write_bytes(as, bytesize); + // only write to the buffer in the emit pass (otherwise we may overflow dummy_data) + if (as->pass == MP_ASM_PASS_EMIT) { + for (unsigned int i = 0; i < bytesize; i++) { + *c++ = val; + val >>= 8; + } + } +} + +#endif // MICROPY_EMIT_NATIVE || MICROPY_EMIT_INLINE_THUMB diff --git a/py/asmbase.h b/py/asmbase.h new file mode 100644 index 000000000..bfc8ac7ff --- /dev/null +++ b/py/asmbase.h @@ -0,0 +1,68 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_PY_ASMBASE_H +#define MICROPY_INCLUDED_PY_ASMBASE_H + +#include <stdint.h> +#include <stdbool.h> + +#define MP_ASM_PASS_COMPUTE (1) +#define MP_ASM_PASS_EMIT (2) + +typedef struct _mp_asm_base_t { + int pass; + size_t code_offset; + size_t code_size; + uint8_t *code_base; + + size_t max_num_labels; + size_t *label_offsets; + + // must be last in struct + uint8_t dummy_data[4]; +} mp_asm_base_t; + +void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels); +void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code); +void mp_asm_base_start_pass(mp_asm_base_t *as, int pass); +uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write); +void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label); +void mp_asm_base_align(mp_asm_base_t* as, unsigned int align); +void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val); + +static inline size_t mp_asm_base_get_code_pos(mp_asm_base_t *as) { + return as->code_offset; +} + +static inline size_t mp_asm_base_get_code_size(mp_asm_base_t *as) { + return as->code_size; +} + +static inline void *mp_asm_base_get_code(mp_asm_base_t *as) { + return as->code_base; +} + +#endif // MICROPY_INCLUDED_PY_ASMBASE_H diff --git a/py/asmthumb.c b/py/asmthumb.c index 1aae3d38e..705c15a18 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -42,49 +42,8 @@ #define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800) #define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000) -struct _asm_thumb_t { - mp_uint_t pass; - mp_uint_t code_offset; - mp_uint_t code_size; - byte *code_base; - byte dummy_data[4]; - - mp_uint_t max_num_labels; - mp_uint_t *label_offsets; - mp_uint_t push_reglist; - mp_uint_t stack_adjust; -}; - -asm_thumb_t *asm_thumb_new(uint max_num_labels) { - asm_thumb_t *as; - - as = m_new0(asm_thumb_t, 1); - as->max_num_labels = max_num_labels; - as->label_offsets = m_new(mp_uint_t, max_num_labels); - - return as; -} - -void asm_thumb_free(asm_thumb_t *as, bool free_code) { - if (free_code) { - MP_PLAT_FREE_EXEC(as->code_base, as->code_size); - } - m_del(mp_uint_t, as->label_offsets, as->max_num_labels); - m_del_obj(asm_thumb_t, as); -} - -void asm_thumb_start_pass(asm_thumb_t *as, uint pass) { - if (pass == ASM_THUMB_PASS_COMPUTE) { - memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t)); - } else if (pass == ASM_THUMB_PASS_EMIT) { - MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); - if (as->code_base == NULL) { - assert(0); - } - //printf("code_size: %u\n", as->code_size); - } - as->pass = pass; - as->code_offset = 0; +static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) { + return mp_asm_base_get_cur_to_write_bytes(&as->base, n); } void asm_thumb_end_pass(asm_thumb_t *as) { @@ -92,7 +51,7 @@ void asm_thumb_end_pass(asm_thumb_t *as) { // could check labels are resolved... #if defined(MCU_SERIES_F7) - if (as->pass == ASM_THUMB_PASS_EMIT) { + if (as->base.pass == MP_ASM_PASS_EMIT) { // flush D-cache, so the code emited is stored in memory SCB_CleanDCache_by_Addr((uint32_t*)as->code_base, as->code_size); // invalidate I-cache @@ -101,33 +60,6 @@ void asm_thumb_end_pass(asm_thumb_t *as) { #endif } -// all functions must go through this one to emit bytes -// if as->pass < ASM_THUMB_PASS_EMIT, then this function only returns a buffer of 4 bytes length -STATIC byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int num_bytes_to_write) { - //printf("emit %d\n", num_bytes_to_write); - if (as->pass < ASM_THUMB_PASS_EMIT) { - as->code_offset += num_bytes_to_write; - return as->dummy_data; - } else { - assert(as->code_offset + num_bytes_to_write <= as->code_size); - byte *c = as->code_base + as->code_offset; - as->code_offset += num_bytes_to_write; - return c; - } -} - -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; -} - -void *asm_thumb_get_code(asm_thumb_t *as) { - return as->code_base; -} - /* STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) { byte *c = asm_thumb_get_cur_to_write_bytes(as, 1); @@ -223,39 +155,9 @@ void asm_thumb_exit(asm_thumb_t *as) { asm_thumb_op16(as, OP_POP_RLIST_PC(as->push_reglist)); } -void asm_thumb_label_assign(asm_thumb_t *as, uint label) { - assert(label < as->max_num_labels); - if (as->pass < ASM_THUMB_PASS_EMIT) { - // assign label offset - assert(as->label_offsets[label] == -1); - as->label_offsets[label] = as->code_offset; - } else { - // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT - //printf("l%d: (at %d=%ld)\n", label, as->label_offsets[label], as->code_offset); - assert(as->label_offsets[label] == as->code_offset); - } -} - -void asm_thumb_align(asm_thumb_t* as, uint align) { - // TODO fill unused data with NOPs? - as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); -} - -void asm_thumb_data(asm_thumb_t* as, uint bytesize, uint val) { - byte *c = asm_thumb_get_cur_to_write_bytes(as, bytesize); - // only write to the buffer in the emit pass (otherwise we overflow dummy_data) - if (as->pass == ASM_THUMB_PASS_EMIT) { - // little endian - for (uint i = 0; i < bytesize; i++) { - *c++ = val; - val >>= 8; - } - } -} - STATIC mp_uint_t get_label_dest(asm_thumb_t *as, uint label) { - assert(label < as->max_num_labels); - return as->label_offsets[label]; + assert(label < as->base.max_num_labels); + return as->base.label_offsets[label]; } void asm_thumb_op16(asm_thumb_t *as, uint op) { @@ -309,10 +211,10 @@ void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_ bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction asm_thumb_op16(as, OP_B_N(rel)); - return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT12(rel); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT12(rel); } #define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) @@ -323,11 +225,11 @@ bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (!wide) { asm_thumb_op16(as, OP_BCC_N(cond, rel)); - return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT9(rel); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT9(rel); } else { asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); return true; @@ -339,10 +241,10 @@ bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { bool asm_thumb_bl_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction asm_thumb_op32(as, OP_BL_HI(rel), OP_BL_LO(rel)); - return as->pass != ASM_THUMB_PASS_EMIT || SIGNED_FIT23(rel); + return as->base.pass != MP_ASM_PASS_EMIT || SIGNED_FIT23(rel); } void asm_thumb_mov_reg_i32(asm_thumb_t *as, uint reg_dest, mp_uint_t i32) { @@ -367,13 +269,13 @@ void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) { // TODO this is very inefficient, improve it! void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) { // align on machine-word + 2 - if ((as->code_offset & 3) == 0) { + if ((as->base.code_offset & 3) == 0) { asm_thumb_op16(as, ASM_THUMB_OP_NOP); } // jump over the i32 value (instruction prefetch adds 2 to PC) asm_thumb_op16(as, OP_B_N(2)); // store i32 on machine-word aligned boundary - asm_thumb_data(as, 4, i32); + mp_asm_base_data(&as->base, 4, i32); // do the actual load of the i32 value asm_thumb_mov_reg_i32_optimised(as, reg_dest, i32); } @@ -384,14 +286,14 @@ void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) { void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) { assert(rlo_src < ASM_THUMB_REG_R8); int word_offset = local_num; - assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0); + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_STR_TO_SP_OFFSET(rlo_src, word_offset)); } void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) { assert(rlo_dest < ASM_THUMB_REG_R8); int word_offset = local_num; - assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0); + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset)); } @@ -400,7 +302,7 @@ void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) { void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) { assert(rlo_dest < ASM_THUMB_REG_R8); int word_offset = local_num; - assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0); + assert(as->base.pass < MP_ASM_PASS_EMIT || word_offset >= 0); asm_thumb_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset)); } @@ -410,7 +312,7 @@ void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) void asm_thumb_b_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (dest != (mp_uint_t)-1 && rel <= -4) { // is a backwards jump, so we know the size of the jump on the first pass @@ -429,7 +331,7 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) { void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction if (dest != (mp_uint_t)-1 && rel <= -4) { // is a backwards jump, so we know the size of the jump on the first pass diff --git a/py/asmthumb.h b/py/asmthumb.h index 43d6c4286..c03b00da3 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -27,9 +27,7 @@ #define __MICROPY_INCLUDED_PY_ASMTHUMB_H__ #include "py/misc.h" - -#define ASM_THUMB_PASS_COMPUTE (1) -#define ASM_THUMB_PASS_EMIT (2) +#include "py/asmbase.h" #define ASM_THUMB_REG_R0 (0) #define ASM_THUMB_REG_R1 (1) @@ -64,24 +62,17 @@ #define ASM_THUMB_CC_GT (0xc) #define ASM_THUMB_CC_LE (0xd) -typedef struct _asm_thumb_t asm_thumb_t; +typedef struct _asm_thumb_t { + mp_asm_base_t base; + uint32_t push_reglist; + uint32_t stack_adjust; +} asm_thumb_t; -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); void asm_thumb_entry(asm_thumb_t *as, int num_locals); void asm_thumb_exit(asm_thumb_t *as); -void asm_thumb_label_assign(asm_thumb_t *as, uint label); - -void asm_thumb_align(asm_thumb_t* as, uint align); -void asm_thumb_data(asm_thumb_t* as, uint bytesize, uint val); - // argument order follows ARM, in general dest is first // note there is a difference between movw and mov.w, and many others! diff --git a/py/asmx64.c b/py/asmx64.c index 5e23a594e..c9dad2a66 100644 --- a/py/asmx64.c +++ b/py/asmx64.c @@ -116,80 +116,8 @@ #define UNSIGNED_FIT32(x) (((x) & 0xffffffff00000000) == 0) #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) -struct _asm_x64_t { - uint pass; - mp_uint_t code_offset; - mp_uint_t code_size; - byte *code_base; - byte dummy_data[8]; - - mp_uint_t max_num_labels; - mp_uint_t *label_offsets; - int num_locals; -}; - -asm_x64_t *asm_x64_new(mp_uint_t max_num_labels) { - asm_x64_t *as; - - as = m_new0(asm_x64_t, 1); - as->max_num_labels = max_num_labels; - as->label_offsets = m_new(mp_uint_t, max_num_labels); - - return as; -} - -void asm_x64_free(asm_x64_t *as, bool free_code) { - if (free_code) { - MP_PLAT_FREE_EXEC(as->code_base, as->code_size); - } - m_del(mp_uint_t, as->label_offsets, as->max_num_labels); - m_del_obj(asm_x64_t, as); -} - -void asm_x64_start_pass(asm_x64_t *as, uint pass) { - if (pass == ASM_X64_PASS_COMPUTE) { - // reset all labels - memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t)); - } if (pass == ASM_X64_PASS_EMIT) { - MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); - if (as->code_base == NULL) { - assert(0); - } - //printf("code_size: %u\n", as->code_size); - } - as->pass = pass; - as->code_offset = 0; -} - -void asm_x64_end_pass(asm_x64_t *as) { - // could check labels are resolved... - (void)as; -} - -// all functions must go through this one to emit bytes -STATIC byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int num_bytes_to_write) { - //printf("emit %d\n", num_bytes_to_write); - if (as->pass < ASM_X64_PASS_EMIT) { - as->code_offset += num_bytes_to_write; - return as->dummy_data; - } else { - assert(as->code_offset + num_bytes_to_write <= as->code_size); - byte *c = as->code_base + as->code_offset; - as->code_offset += num_bytes_to_write; - return c; - } -} - -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; -} - -void *asm_x64_get_code(asm_x64_t *as) { - return as->code_base; +static inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) { + return mp_asm_base_get_cur_to_write_bytes(&as->base, n); } STATIC void asm_x64_write_byte_1(asm_x64_t *as, byte b1) { @@ -230,21 +158,6 @@ 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; @@ -440,7 +353,7 @@ void asm_x64_mov_i64_to_r64_optimised(asm_x64_t *as, int64_t src_i64, int dest_r // src_i64 is stored as a full word in the code, and aligned to machine-word boundary void asm_x64_mov_i64_to_r64_aligned(asm_x64_t *as, int64_t src_i64, int dest_r64) { // mov instruction uses 2 bytes for the instruction, before the i64 - while (((as->code_offset + 2) & (WORD_SIZE - 1)) != 0) { + while (((as->base.code_offset + 2) & (WORD_SIZE - 1)) != 0) { asm_x64_nop(as); } asm_x64_mov_i64_to_r64(as, src_i64, dest_r64); @@ -552,27 +465,14 @@ void asm_x64_setcc_r8(asm_x64_t *as, int jcc_type, int dest_r8) { asm_x64_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R64(0) | MODRM_RM_REG | MODRM_RM_R64(dest_r8)); } -void asm_x64_label_assign(asm_x64_t *as, mp_uint_t label) { - assert(label < as->max_num_labels); - if (as->pass < ASM_X64_PASS_EMIT) { - // assign label offset - assert(as->label_offsets[label] == (mp_uint_t)-1); - as->label_offsets[label] = as->code_offset; - } else { - // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT - //printf("l%d: (at %ld=%ld)\n", label, as->label_offsets[label], as->code_offset); - assert(as->label_offsets[label] == as->code_offset); - } -} - STATIC mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) { - assert(label < as->max_num_labels); - return as->label_offsets[label]; + assert(label < as->base.max_num_labels); + return as->base.label_offsets[label]; } void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; if (dest != (mp_uint_t)-1 && rel < 0) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 8 bit relative jump @@ -594,7 +494,7 @@ void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) { void asm_x64_jcc_label(asm_x64_t *as, int jcc_type, mp_uint_t label) { mp_uint_t dest = get_label_dest(as, label); - mp_int_t rel = dest - as->code_offset; + mp_int_t rel = dest - as->base.code_offset; if (dest != (mp_uint_t)-1 && rel < 0) { // is a backwards jump, so we know the size of the jump on the first pass // calculate rel assuming 8 bit relative jump diff --git a/py/asmx64.h b/py/asmx64.h index 6fbc2c906..daf5b3d0b 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -28,6 +28,7 @@ #include "py/mpconfig.h" #include "py/misc.h" +#include "py/asmbase.h" // AMD64 calling convention is: // - args pass in: RDI, RSI, RDX, RCX, R08, R09 @@ -41,9 +42,6 @@ // NOTE: this is a change from the old convention used in this file and // some functions still use the old (reverse) convention. -#define ASM_X64_PASS_COMPUTE (1) -#define ASM_X64_PASS_EMIT (2) - #define ASM_X64_REG_RAX (0) #define ASM_X64_REG_RCX (1) #define ASM_X64_REG_RDX (2) @@ -72,18 +70,15 @@ #define ASM_X64_CC_JLE (0xe) // less or equal, signed #define ASM_X64_CC_JG (0xf) // greater, signed -typedef struct _asm_x64_t asm_x64_t; - -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); +typedef struct _asm_x64_t { + mp_asm_base_t base; + byte dummy_data[4]; // in addition to dummy_data in base + int num_locals; +} asm_x64_t; -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); +static inline void asm_x64_end_pass(asm_x64_t *as) { + (void)as; +} void asm_x64_nop(asm_x64_t* as); void asm_x64_push_r64(asm_x64_t* as, int src_r64); @@ -111,7 +106,6 @@ void asm_x64_mul_r64_r64(asm_x64_t* as, int dest_r64, int src_r64); void asm_x64_cmp_r64_with_r64(asm_x64_t* as, int src_r64_a, int src_r64_b); void asm_x64_test_r8_with_r8(asm_x64_t* as, int src_r64_a, int src_r64_b); void asm_x64_setcc_r8(asm_x64_t* as, int jcc_type, int dest_r8); -void asm_x64_label_assign(asm_x64_t* as, mp_uint_t label); void asm_x64_jmp_label(asm_x64_t* as, mp_uint_t label); void asm_x64_jcc_label(asm_x64_t* as, int jcc_type, mp_uint_t label); void asm_x64_entry(asm_x64_t* as, int num_locals); diff --git a/py/asmx86.c b/py/asmx86.c index 40958826f..cb9b30d40 100644 --- a/py/asmx86.c +++ b/py/asmx86.c @@ -100,80 +100,6 @@ #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) -struct _asm_x86_t { - uint pass; - mp_uint_t code_offset; - mp_uint_t code_size; - byte *code_base; - byte dummy_data[8]; - - mp_uint_t max_num_labels; - mp_uint_t *label_offsets; - int num_locals; -}; - -asm_x86_t *asm_x86_new(mp_uint_t max_num_labels) { - asm_x86_t *as; - - as = m_new0(asm_x86_t, 1); - as->max_num_labels = max_num_labels; - as->label_offsets = m_new(mp_uint_t, max_num_labels); - - return as; -} - -void asm_x86_free(asm_x86_t *as, bool free_code) { - if (free_code) { - MP_PLAT_FREE_EXEC(as->code_base, as->code_size); - } - m_del(mp_uint_t, as->label_offsets, as->max_num_labels); - m_del_obj(asm_x86_t, as); -} - -void asm_x86_start_pass(asm_x86_t *as, mp_uint_t pass) { - if (pass == ASM_X86_PASS_COMPUTE) { - // reset all labels - memset(as->label_offsets, -1, as->max_num_labels * sizeof(mp_uint_t)); - } else if (pass == ASM_X86_PASS_EMIT) { - MP_PLAT_ALLOC_EXEC(as->code_offset, (void**)&as->code_base, &as->code_size); - if (as->code_base == NULL) { - assert(0); - } - } - as->pass = pass; - as->code_offset = 0; -} - -void asm_x86_end_pass(asm_x86_t *as) { - (void)as; -} - -// all functions must go through this one to emit bytes -STATIC byte *asm_x86_get_cur_to_write_bytes(asm_x86_t *as, int num_bytes_to_write) { - //printf("emit %d\n", num_bytes_to_write); - if (as->pass < ASM_X86_PASS_EMIT) { - as->code_offset += num_bytes_to_write; - return as->dummy_data; - } else { - assert(as->code_offset + num_bytes_to_write <= as->code_size); - byte *c = as->code_base + as->code_offset; - as->code_offset += num_bytes_to_write; - return c; - } -} - -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; -} - -void *asm_x86_get_code(asm_x86_t *as) { - return as->code_base; -} - STATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) { byte* c = asm_x86_get_cur_to_write_bytes(as, 1); c[0] = b1; @@ -200,21 +126,6 @@ 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); @@ -419,19 +330,6 @@ void asm_x86_setcc_r8(asm_x86_t *as, mp_uint_t jcc_type, int dest_r8) { asm_x86_write_byte_3(as, OPCODE_SETCC_RM8_A, OPCODE_SETCC_RM8_B | jcc_type, MODRM_R32(0) | MODRM_RM_REG | MODRM_RM_R32(dest_r8)); } -void asm_x86_label_assign(asm_x86_t *as, mp_uint_t label) { - assert(label < as->max_num_labels); - if (as->pass < ASM_X86_PASS_EMIT) { - // assign label offset - assert(as->label_offsets[label] == (mp_uint_t)-1); - as->label_offsets[label] = as->code_offset; - } else { - // ensure label offset has not changed from PASS_COMPUTE to PASS_EMIT - //printf("l%d: (at %d=%ld)\n", label, as->label_offsets[label], as->code_offset); - assert(as->label_offsets[label] == as->code_offset); - } -} - STATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) { assert(label < as->max_num_labels); return as->label_offsets[label]; diff --git a/py/asmx86.h b/py/asmx86.h index e0c57722a..85352fff3 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -28,6 +28,7 @@ #include "py/mpconfig.h" #include "py/misc.h" +#include "py/asmbase.h" // x86 cdecl calling convention is: // - args passed on the stack in reverse order @@ -42,9 +43,6 @@ // NOTE: this is a change from the old convention used in this file and // some functions still use the old (reverse) convention. -#define ASM_X86_PASS_COMPUTE (1) -#define ASM_X86_PASS_EMIT (2) - #define ASM_X86_REG_EAX (0) #define ASM_X86_REG_ECX (1) #define ASM_X86_REG_EDX (2) @@ -75,18 +73,15 @@ #define ASM_X86_CC_JLE (0xe) // less or equal, signed #define ASM_X86_CC_JG (0xf) // greater, signed -typedef struct _asm_x86_t asm_x86_t; - -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); +typedef struct _asm_x86_t { + mp_asm_base_t base; + byte dummy_data[4]; // in addition to dummy_data in base + int num_locals; +} asm_x86_t; -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); +static inline void asm_x86_end_pass(asm_x86_t *as) { + (void)as; +} 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); @@ -108,7 +103,6 @@ void asm_x86_mul_r32_r32(asm_x86_t* as, int dest_r32, int src_r32); void asm_x86_cmp_r32_with_r32(asm_x86_t* as, int src_r32_a, int src_r32_b); void asm_x86_test_r8_with_r8(asm_x86_t* as, int src_r32_a, int src_r32_b); void asm_x86_setcc_r8(asm_x86_t* as, mp_uint_t jcc_type, int dest_r8); -void asm_x86_label_assign(asm_x86_t* as, mp_uint_t label); void asm_x86_jmp_label(asm_x86_t* as, mp_uint_t label); void asm_x86_jcc_label(asm_x86_t* as, mp_uint_t jcc_type, mp_uint_t label); void asm_x86_entry(asm_x86_t* as, mp_uint_t num_locals); diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 90a68caa6..760ec8cc0 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -63,13 +63,15 @@ emit_inline_asm_t *emit_inline_thumb_new(mp_uint_t max_num_labels) { emit_inline_asm_t *emit = m_new_obj(emit_inline_asm_t); emit->max_num_labels = max_num_labels; emit->label_lookup = m_new(qstr, max_num_labels); - emit->as = asm_thumb_new(max_num_labels); + emit->as = m_new0(asm_thumb_t, 1); + mp_asm_base_init(&emit->as->base, max_num_labels); return emit; } void emit_inline_thumb_free(emit_inline_asm_t *emit) { m_del(qstr, emit->label_lookup, emit->max_num_labels); - asm_thumb_free(emit->as, false); + mp_asm_base_deinit(&emit->as->base, false); + m_del_obj(asm_thumb_t, emit->as); m_del_obj(emit_inline_asm_t, emit); } @@ -80,7 +82,7 @@ STATIC void emit_inline_thumb_start_pass(emit_inline_asm_t *emit, pass_kind_t pa if (emit->pass == MP_PASS_CODE_SIZE) { memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); } - asm_thumb_start_pass(emit->as, pass == MP_PASS_EMIT ? ASM_THUMB_PASS_EMIT : ASM_THUMB_PASS_COMPUTE); + mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); asm_thumb_entry(emit->as, 0); } @@ -89,9 +91,9 @@ STATIC void emit_inline_thumb_end_pass(emit_inline_asm_t *emit, mp_uint_t type_s asm_thumb_end_pass(emit->as); if (emit->pass == MP_PASS_EMIT) { - void *f = asm_thumb_get_code(emit->as); + void *f = mp_asm_base_get_code(&emit->as->base); mp_emit_glue_assign_native(emit->scope->raw_code, MP_CODE_NATIVE_ASM, f, - asm_thumb_get_code_size(emit->as), NULL, emit->scope->num_pos_args, 0, type_sig); + mp_asm_base_get_code_size(&emit->as->base), NULL, emit->scope->num_pos_args, 0, type_sig); } } @@ -125,16 +127,16 @@ STATIC bool emit_inline_thumb_label(emit_inline_asm_t *emit, mp_uint_t label_num } } emit->label_lookup[label_num] = label_id; - asm_thumb_label_assign(emit->as, label_num); + mp_asm_base_label_assign(&emit->as->base, label_num); return true; } STATIC void emit_inline_thumb_align(emit_inline_asm_t *emit, mp_uint_t align) { - asm_thumb_align(emit->as, align); + mp_asm_base_align(&emit->as->base, align); } STATIC void emit_inline_thumb_data(emit_inline_asm_t *emit, mp_uint_t bytesize, mp_uint_t val) { - asm_thumb_data(emit->as, bytesize, val); + mp_asm_base_data(&emit->as->base, bytesize, val); } typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t; diff --git a/py/emitnative.c b/py/emitnative.c index 46e1076a9..d19dfe467 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -91,24 +91,11 @@ #define REG_LOCAL_3 ASM_X64_REG_R13 #define REG_LOCAL_NUM (3) -#define ASM_PASS_COMPUTE ASM_X64_PASS_COMPUTE -#define ASM_PASS_EMIT ASM_X64_PASS_EMIT - #define ASM_T asm_x64_t -#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) \ do { \ @@ -236,24 +223,11 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { #define REG_LOCAL_3 ASM_X86_REG_EDI #define REG_LOCAL_NUM (3) -#define ASM_PASS_COMPUTE ASM_X86_PASS_COMPUTE -#define ASM_PASS_EMIT ASM_X86_PASS_EMIT - #define ASM_T asm_x86_t -#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) \ do { \ @@ -331,24 +305,11 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { #define REG_LOCAL_3 ASM_THUMB_REG_R6 #define REG_LOCAL_NUM (3) -#define ASM_PASS_COMPUTE ASM_THUMB_PASS_COMPUTE -#define ASM_PASS_EMIT ASM_THUMB_PASS_EMIT - #define ASM_T asm_thumb_t -#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) \ do { \ @@ -425,24 +386,11 @@ STATIC byte mp_f_n_args[MP_F_NUMBER_OF] = { #define REG_LOCAL_3 ASM_ARM_REG_R6 #define REG_LOCAL_NUM (3) -#define ASM_PASS_COMPUTE ASM_ARM_PASS_COMPUTE -#define ASM_PASS_EMIT ASM_ARM_PASS_EMIT - #define ASM_T asm_arm_t -#define ASM_NEW asm_arm_new -#define ASM_FREE asm_arm_free -#define ASM_GET_CODE asm_arm_get_code -#define ASM_GET_CODE_POS asm_arm_get_code_pos -#define ASM_GET_CODE_SIZE asm_arm_get_code_size -#define ASM_START_PASS asm_arm_start_pass #define ASM_END_PASS asm_arm_end_pass #define ASM_ENTRY asm_arm_entry #define ASM_EXIT asm_arm_exit -#define ASM_ALIGN asm_arm_align -#define ASM_DATA asm_arm_data - -#define ASM_LABEL_ASSIGN asm_arm_label_assign #define ASM_JUMP asm_arm_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ do { \ @@ -582,12 +530,14 @@ struct _emit_t { emit_t *EXPORT_FUN(new)(mp_obj_t *error_slot, mp_uint_t max_num_labels) { emit_t *emit = m_new0(emit_t, 1); emit->error_slot = error_slot; - emit->as = ASM_NEW(max_num_labels); + emit->as = m_new0(ASM_T, 1); + mp_asm_base_init(&emit->as->base, max_num_labels); return emit; } void EXPORT_FUN(free)(emit_t *emit) { - ASM_FREE(emit->as, false); + mp_asm_base_deinit(&emit->as->base, false); + m_del_obj(ASM_T, emit->as); m_del(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc); m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc); m_del_obj(emit_t, emit); @@ -679,7 +629,7 @@ STATIC void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_info[i].vtype = VTYPE_UNBOUND; } - ASM_START_PASS(emit->as, pass == MP_PASS_EMIT ? ASM_PASS_EMIT : ASM_PASS_COMPUTE); + mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); // generate code for entry to function @@ -824,21 +774,21 @@ STATIC void emit_native_end_pass(emit_t *emit) { } if (!emit->do_viper_types) { - emit->prelude_offset = ASM_GET_CODE_POS(emit->as); - ASM_DATA(emit->as, 1, emit->scope->scope_flags); - ASM_DATA(emit->as, 1, emit->scope->num_pos_args); - ASM_DATA(emit->as, 1, emit->scope->num_kwonly_args); - ASM_DATA(emit->as, 1, emit->scope->num_def_pos_args); + emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base); + mp_asm_base_data(&emit->as->base, 1, emit->scope->scope_flags); + mp_asm_base_data(&emit->as->base, 1, emit->scope->num_pos_args); + mp_asm_base_data(&emit->as->base, 1, emit->scope->num_kwonly_args); + mp_asm_base_data(&emit->as->base, 1, emit->scope->num_def_pos_args); // write code info #if MICROPY_PERSISTENT_CODE - ASM_DATA(emit->as, 1, 5); - ASM_DATA(emit->as, 1, emit->scope->simple_name); - ASM_DATA(emit->as, 1, emit->scope->simple_name >> 8); - ASM_DATA(emit->as, 1, emit->scope->source_file); - ASM_DATA(emit->as, 1, emit->scope->source_file >> 8); + mp_asm_base_data(&emit->as->base, 1, 5); + mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name); + mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8); + mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file); + mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file >> 8); #else - ASM_DATA(emit->as, 1, 1); + mp_asm_base_data(&emit->as->base, 1, 1); #endif // bytecode prelude: initialise closed over variables @@ -846,13 +796,13 @@ STATIC void emit_native_end_pass(emit_t *emit) { 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 + mp_asm_base_data(&emit->as->base, 1, id->local_num); // write the local which should be converted to a cell } } - ASM_DATA(emit->as, 1, 255); // end of list sentinel + mp_asm_base_data(&emit->as->base, 1, 255); // end of list sentinel - ASM_ALIGN(emit->as, ASM_WORD_SIZE); - emit->const_table_offset = ASM_GET_CODE_POS(emit->as); + mp_asm_base_align(&emit->as->base, ASM_WORD_SIZE); + emit->const_table_offset = mp_asm_base_get_code_pos(&emit->as->base); // write argument names as qstr objects // see comment in corresponding part of emitbc.c about the logic here @@ -865,7 +815,7 @@ STATIC void emit_native_end_pass(emit_t *emit) { break; } } - ASM_DATA(emit->as, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); + mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (mp_uint_t)MP_OBJ_NEW_QSTR(qst)); } } @@ -878,8 +828,8 @@ STATIC void emit_native_end_pass(emit_t *emit) { } if (emit->pass == MP_PASS_EMIT) { - void *f = ASM_GET_CODE(emit->as); - mp_uint_t f_len = ASM_GET_CODE_SIZE(emit->as); + 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 @@ -1255,7 +1205,7 @@ STATIC void emit_native_label_assign(emit_t *emit, mp_uint_t l) { emit_native_pre(emit); // need to commit stack because we can jump here from elsewhere need_stack_settled(emit); - ASM_LABEL_ASSIGN(emit->as, l); + mp_asm_base_label_assign(&emit->as->base, l); emit_post(emit); } diff --git a/py/py.mk b/py/py.mk index ec67ac2a0..87a860f75 100644 --- a/py/py.mk +++ b/py/py.mk @@ -120,6 +120,7 @@ PY_O_BASENAME = \ compile.o \ emitcommon.o \ emitbc.o \ + asmbase.o \ asmx64.o \ emitnx64.o \ asmx86.o \ -- GitLab