py: Factor out common code from assemblers into asmbase.[ch].

All assemblers should "derive" from mp_asm_base_t.
This commit is contained in:
Damien George 2016-11-28 09:24:50 +11:00
parent 21e1703d37
commit 612599587b
13 changed files with 262 additions and 565 deletions

View File

@ -38,50 +38,6 @@
#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000) #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) { void asm_arm_end_pass(asm_arm_t *as) {
if (as->pass == ASM_ARM_PASS_EMIT) { if (as->pass == ASM_ARM_PASS_EMIT) {
#ifdef __arm__ #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 // Insert word into instruction flow
STATIC void emit(asm_arm_t *as, uint op) { STATIC void emit(asm_arm_t *as, uint op) {
*(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = 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)); 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) { 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)); emit_al(as, asm_arm_op_mov_reg(reg_dest, reg_src));
} }

View File

@ -28,9 +28,7 @@
#define __MICROPY_INCLUDED_PY_ASMARM_H__ #define __MICROPY_INCLUDED_PY_ASMARM_H__
#include "py/misc.h" #include "py/misc.h"
#include "py/asmbase.h"
#define ASM_ARM_PASS_COMPUTE (1)
#define ASM_ARM_PASS_EMIT (2)
#define ASM_ARM_REG_R0 (0) #define ASM_ARM_REG_R0 (0)
#define ASM_ARM_REG_R1 (1) #define ASM_ARM_REG_R1 (1)
@ -68,22 +66,16 @@
#define ASM_ARM_CC_LE (0xd << 28) #define ASM_ARM_CC_LE (0xd << 28)
#define ASM_ARM_CC_AL (0xe << 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); 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_entry(asm_arm_t *as, int num_locals);
void asm_arm_exit(asm_arm_t *as); 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); void asm_arm_bkpt(asm_arm_t *as);

104
py/asmbase.c Normal file
View File

@ -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

68
py/asmbase.h Normal file
View File

@ -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

View File

@ -42,49 +42,8 @@
#define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800) #define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)
#define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000) #define SIGNED_FIT23(x) (((x) & 0xffc00000) == 0) || (((x) & 0xffc00000) == 0xffc00000)
struct _asm_thumb_t { static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) {
mp_uint_t pass; return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
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;
} }
void asm_thumb_end_pass(asm_thumb_t *as) { 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... // could check labels are resolved...
#if defined(MCU_SERIES_F7) #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 // flush D-cache, so the code emited is stored in memory
SCB_CleanDCache_by_Addr((uint32_t*)as->code_base, as->code_size); SCB_CleanDCache_by_Addr((uint32_t*)as->code_base, as->code_size);
// invalidate I-cache // invalidate I-cache
@ -101,33 +60,6 @@ void asm_thumb_end_pass(asm_thumb_t *as) {
#endif #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) { STATIC void asm_thumb_write_byte_1(asm_thumb_t *as, byte b1) {
byte *c = asm_thumb_get_cur_to_write_bytes(as, 1); 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)); 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) { STATIC mp_uint_t get_label_dest(asm_thumb_t *as, uint label) {
assert(label < as->max_num_labels); assert(label < as->base.max_num_labels);
return as->label_offsets[label]; return as->base.label_offsets[label];
} }
void asm_thumb_op16(asm_thumb_t *as, uint op) { 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) { bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) {
mp_uint_t dest = get_label_dest(as, 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 rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
asm_thumb_op16(as, OP_B_N(rel)); 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)) #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) { 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_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 rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
if (!wide) { if (!wide) {
asm_thumb_op16(as, OP_BCC_N(cond, rel)); 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 { } else {
asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel));
return true; 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) { bool asm_thumb_bl_label(asm_thumb_t *as, uint label) {
mp_uint_t dest = get_label_dest(as, 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 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)); 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) { 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! // TODO this is very inefficient, improve it!
void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) { void asm_thumb_mov_reg_i32_aligned(asm_thumb_t *as, uint reg_dest, int i32) {
// align on machine-word + 2 // 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); asm_thumb_op16(as, ASM_THUMB_OP_NOP);
} }
// jump over the i32 value (instruction prefetch adds 2 to PC) // jump over the i32 value (instruction prefetch adds 2 to PC)
asm_thumb_op16(as, OP_B_N(2)); asm_thumb_op16(as, OP_B_N(2));
// store i32 on machine-word aligned boundary // 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 // do the actual load of the i32 value
asm_thumb_mov_reg_i32_optimised(as, reg_dest, i32); 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) { void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) {
assert(rlo_src < ASM_THUMB_REG_R8); assert(rlo_src < ASM_THUMB_REG_R8);
int word_offset = local_num; 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)); 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) { void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num) {
assert(rlo_dest < ASM_THUMB_REG_R8); assert(rlo_dest < ASM_THUMB_REG_R8);
int word_offset = local_num; 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)); 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) { void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num) {
assert(rlo_dest < ASM_THUMB_REG_R8); assert(rlo_dest < ASM_THUMB_REG_R8);
int word_offset = local_num; 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)); 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) { void asm_thumb_b_label(asm_thumb_t *as, uint label) {
mp_uint_t dest = get_label_dest(as, 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 rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
if (dest != (mp_uint_t)-1 && rel <= -4) { if (dest != (mp_uint_t)-1 && rel <= -4) {
// is a backwards jump, so we know the size of the jump on the first pass // 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) { void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) {
mp_uint_t dest = get_label_dest(as, 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 rel -= 4; // account for instruction prefetch, PC is 4 bytes ahead of this instruction
if (dest != (mp_uint_t)-1 && rel <= -4) { if (dest != (mp_uint_t)-1 && rel <= -4) {
// is a backwards jump, so we know the size of the jump on the first pass // is a backwards jump, so we know the size of the jump on the first pass

View File

@ -27,9 +27,7 @@
#define __MICROPY_INCLUDED_PY_ASMTHUMB_H__ #define __MICROPY_INCLUDED_PY_ASMTHUMB_H__
#include "py/misc.h" #include "py/misc.h"
#include "py/asmbase.h"
#define ASM_THUMB_PASS_COMPUTE (1)
#define ASM_THUMB_PASS_EMIT (2)
#define ASM_THUMB_REG_R0 (0) #define ASM_THUMB_REG_R0 (0)
#define ASM_THUMB_REG_R1 (1) #define ASM_THUMB_REG_R1 (1)
@ -64,24 +62,17 @@
#define ASM_THUMB_CC_GT (0xc) #define ASM_THUMB_CC_GT (0xc)
#define ASM_THUMB_CC_LE (0xd) #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); 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_entry(asm_thumb_t *as, int num_locals);
void asm_thumb_exit(asm_thumb_t *as); 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 // argument order follows ARM, in general dest is first
// note there is a difference between movw and mov.w, and many others! // note there is a difference between movw and mov.w, and many others!

View File

@ -116,80 +116,8 @@
#define UNSIGNED_FIT32(x) (((x) & 0xffffffff00000000) == 0) #define UNSIGNED_FIT32(x) (((x) & 0xffffffff00000000) == 0)
#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
struct _asm_x64_t { static inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) {
uint pass; return mp_asm_base_get_cur_to_write_bytes(&as->base, n);
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 void asm_x64_write_byte_1(asm_x64_t *as, byte b1) { 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); 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 /* unused
STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) { STATIC void asm_x64_write_word32_to(asm_x64_t *as, int offset, int w32) {
byte* c; 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 // 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) { 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 // 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_nop(as);
} }
asm_x64_mov_i64_to_r64(as, src_i64, dest_r64); 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)); 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) { STATIC mp_uint_t get_label_dest(asm_x64_t *as, mp_uint_t label) {
assert(label < as->max_num_labels); assert(label < as->base.max_num_labels);
return as->label_offsets[label]; return as->base.label_offsets[label];
} }
void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) { void asm_x64_jmp_label(asm_x64_t *as, mp_uint_t label) {
mp_uint_t dest = get_label_dest(as, 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) { if (dest != (mp_uint_t)-1 && rel < 0) {
// is a backwards jump, so we know the size of the jump on the first pass // is a backwards jump, so we know the size of the jump on the first pass
// calculate rel assuming 8 bit relative jump // 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) { 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_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) { if (dest != (mp_uint_t)-1 && rel < 0) {
// is a backwards jump, so we know the size of the jump on the first pass // is a backwards jump, so we know the size of the jump on the first pass
// calculate rel assuming 8 bit relative jump // calculate rel assuming 8 bit relative jump

View File

@ -28,6 +28,7 @@
#include "py/mpconfig.h" #include "py/mpconfig.h"
#include "py/misc.h" #include "py/misc.h"
#include "py/asmbase.h"
// AMD64 calling convention is: // AMD64 calling convention is:
// - args pass in: RDI, RSI, RDX, RCX, R08, R09 // - 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 // NOTE: this is a change from the old convention used in this file and
// some functions still use the old (reverse) convention. // 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_RAX (0)
#define ASM_X64_REG_RCX (1) #define ASM_X64_REG_RCX (1)
#define ASM_X64_REG_RDX (2) #define ASM_X64_REG_RDX (2)
@ -72,18 +70,15 @@
#define ASM_X64_CC_JLE (0xe) // less or equal, signed #define ASM_X64_CC_JLE (0xe) // less or equal, signed
#define ASM_X64_CC_JG (0xf) // greater, signed #define ASM_X64_CC_JG (0xf) // greater, signed
typedef struct _asm_x64_t asm_x64_t; 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;
asm_x64_t* asm_x64_new(mp_uint_t max_num_labels); static inline void asm_x64_end_pass(asm_x64_t *as) {
void asm_x64_free(asm_x64_t* as, bool free_code); (void)as;
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_nop(asm_x64_t* as);
void asm_x64_push_r64(asm_x64_t* as, int src_r64); 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_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_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_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_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_jcc_label(asm_x64_t* as, int jcc_type, mp_uint_t label);
void asm_x64_entry(asm_x64_t* as, int num_locals); void asm_x64_entry(asm_x64_t* as, int num_locals);

View File

@ -100,80 +100,6 @@
#define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80) #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) { STATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) {
byte* c = asm_x86_get_cur_to_write_bytes(as, 1); byte* c = asm_x86_get_cur_to_write_bytes(as, 1);
c[0] = b1; c[0] = b1;
@ -200,21 +126,6 @@ STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) {
c[3] = IMM32_L3(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) { 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); 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)); 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) { STATIC mp_uint_t get_label_dest(asm_x86_t *as, mp_uint_t label) {
assert(label < as->max_num_labels); assert(label < as->max_num_labels);
return as->label_offsets[label]; return as->label_offsets[label];

View File

@ -28,6 +28,7 @@
#include "py/mpconfig.h" #include "py/mpconfig.h"
#include "py/misc.h" #include "py/misc.h"
#include "py/asmbase.h"
// x86 cdecl calling convention is: // x86 cdecl calling convention is:
// - args passed on the stack in reverse order // - 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 // NOTE: this is a change from the old convention used in this file and
// some functions still use the old (reverse) convention. // 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_EAX (0)
#define ASM_X86_REG_ECX (1) #define ASM_X86_REG_ECX (1)
#define ASM_X86_REG_EDX (2) #define ASM_X86_REG_EDX (2)
@ -75,18 +73,15 @@
#define ASM_X86_CC_JLE (0xe) // less or equal, signed #define ASM_X86_CC_JLE (0xe) // less or equal, signed
#define ASM_X86_CC_JG (0xf) // greater, signed #define ASM_X86_CC_JG (0xf) // greater, signed
typedef struct _asm_x86_t asm_x86_t; 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;
asm_x86_t* asm_x86_new(mp_uint_t max_num_labels); static inline void asm_x86_end_pass(asm_x86_t *as) {
void asm_x86_free(asm_x86_t* as, bool free_code); (void)as;
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_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(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_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_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_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_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_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); void asm_x86_entry(asm_x86_t* as, mp_uint_t num_locals);

View File

@ -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_inline_asm_t *emit = m_new_obj(emit_inline_asm_t);
emit->max_num_labels = max_num_labels; emit->max_num_labels = max_num_labels;
emit->label_lookup = m_new(qstr, 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; return emit;
} }
void emit_inline_thumb_free(emit_inline_asm_t *emit) { void emit_inline_thumb_free(emit_inline_asm_t *emit) {
m_del(qstr, emit->label_lookup, emit->max_num_labels); 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); 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) { if (emit->pass == MP_PASS_CODE_SIZE) {
memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr)); 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); 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); asm_thumb_end_pass(emit->as);
if (emit->pass == MP_PASS_EMIT) { 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, 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; 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; return true;
} }
STATIC void emit_inline_thumb_align(emit_inline_asm_t *emit, mp_uint_t align) { 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) { 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; typedef struct _reg_name_t { byte reg; byte name[3]; } reg_name_t;

View File

@ -91,24 +91,11 @@
#define REG_LOCAL_3 ASM_X64_REG_R13 #define REG_LOCAL_3 ASM_X64_REG_R13
#define REG_LOCAL_NUM (3) #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_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_END_PASS asm_x64_end_pass
#define ASM_ENTRY asm_x64_entry #define ASM_ENTRY asm_x64_entry
#define ASM_EXIT asm_x64_exit #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 asm_x64_jmp_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
do { \ 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_3 ASM_X86_REG_EDI
#define REG_LOCAL_NUM (3) #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_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_END_PASS asm_x86_end_pass
#define ASM_ENTRY asm_x86_entry #define ASM_ENTRY asm_x86_entry
#define ASM_EXIT asm_x86_exit #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 asm_x86_jmp_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
do { \ 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_3 ASM_THUMB_REG_R6
#define REG_LOCAL_NUM (3) #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_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_END_PASS asm_thumb_end_pass
#define ASM_ENTRY asm_thumb_entry #define ASM_ENTRY asm_thumb_entry
#define ASM_EXIT asm_thumb_exit #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 asm_thumb_b_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
do { \ 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_3 ASM_ARM_REG_R6
#define REG_LOCAL_NUM (3) #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_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_END_PASS asm_arm_end_pass
#define ASM_ENTRY asm_arm_entry #define ASM_ENTRY asm_arm_entry
#define ASM_EXIT asm_arm_exit #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 asm_arm_b_label
#define ASM_JUMP_IF_REG_ZERO(as, reg, label) \ #define ASM_JUMP_IF_REG_ZERO(as, reg, label) \
do { \ 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 *EXPORT_FUN(new)(mp_obj_t *error_slot, mp_uint_t max_num_labels) {
emit_t *emit = m_new0(emit_t, 1); emit_t *emit = m_new0(emit_t, 1);
emit->error_slot = error_slot; 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; return emit;
} }
void EXPORT_FUN(free)(emit_t *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(vtype_kind_t, emit->local_vtype, emit->local_vtype_alloc);
m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc); m_del(stack_info_t, emit->stack_info, emit->stack_info_alloc);
m_del_obj(emit_t, emit); 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; 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 // generate code for entry to function
@ -824,21 +774,21 @@ STATIC void emit_native_end_pass(emit_t *emit) {
} }
if (!emit->do_viper_types) { if (!emit->do_viper_types) {
emit->prelude_offset = ASM_GET_CODE_POS(emit->as); emit->prelude_offset = mp_asm_base_get_code_pos(&emit->as->base);
ASM_DATA(emit->as, 1, emit->scope->scope_flags); mp_asm_base_data(&emit->as->base, 1, emit->scope->scope_flags);
ASM_DATA(emit->as, 1, emit->scope->num_pos_args); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_pos_args);
ASM_DATA(emit->as, 1, emit->scope->num_kwonly_args); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_kwonly_args);
ASM_DATA(emit->as, 1, emit->scope->num_def_pos_args); mp_asm_base_data(&emit->as->base, 1, emit->scope->num_def_pos_args);
// write code info // write code info
#if MICROPY_PERSISTENT_CODE #if MICROPY_PERSISTENT_CODE
ASM_DATA(emit->as, 1, 5); mp_asm_base_data(&emit->as->base, 1, 5);
ASM_DATA(emit->as, 1, emit->scope->simple_name); mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name);
ASM_DATA(emit->as, 1, emit->scope->simple_name >> 8); mp_asm_base_data(&emit->as->base, 1, emit->scope->simple_name >> 8);
ASM_DATA(emit->as, 1, emit->scope->source_file); mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file);
ASM_DATA(emit->as, 1, emit->scope->source_file >> 8); mp_asm_base_data(&emit->as->base, 1, emit->scope->source_file >> 8);
#else #else
ASM_DATA(emit->as, 1, 1); mp_asm_base_data(&emit->as->base, 1, 1);
#endif #endif
// bytecode prelude: initialise closed over variables // 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]; id_info_t *id = &emit->scope->id_info[i];
if (id->kind == ID_INFO_KIND_CELL) { if (id->kind == ID_INFO_KIND_CELL) {
assert(id->local_num < 255); 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); mp_asm_base_align(&emit->as->base, ASM_WORD_SIZE);
emit->const_table_offset = ASM_GET_CODE_POS(emit->as); emit->const_table_offset = mp_asm_base_get_code_pos(&emit->as->base);
// write argument names as qstr objects // write argument names as qstr objects
// see comment in corresponding part of emitbc.c about the logic here // 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; 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) { if (emit->pass == MP_PASS_EMIT) {
void *f = ASM_GET_CODE(emit->as); void *f = mp_asm_base_get_code(&emit->as->base);
mp_uint_t f_len = ASM_GET_CODE_SIZE(emit->as); mp_uint_t f_len = mp_asm_base_get_code_size(&emit->as->base);
// compute type signature // compute type signature
// note that the lower 4 bits of a vtype are tho correct MP_NATIVE_TYPE_xxx // 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); emit_native_pre(emit);
// need to commit stack because we can jump here from elsewhere // need to commit stack because we can jump here from elsewhere
need_stack_settled(emit); need_stack_settled(emit);
ASM_LABEL_ASSIGN(emit->as, l); mp_asm_base_label_assign(&emit->as->base, l);
emit_post(emit); emit_post(emit);
} }

View File

@ -120,6 +120,7 @@ PY_O_BASENAME = \
compile.o \ compile.o \
emitcommon.o \ emitcommon.o \
emitbc.o \ emitbc.o \
asmbase.o \
asmx64.o \ asmx64.o \
emitnx64.o \ emitnx64.o \
asmx86.o \ asmx86.o \