py, compiler: Improve passes; add an extra pass for native emitter.

This commit is contained in:
Damien George
2014-05-07 17:24:22 +01:00
parent ca25c15d56
commit 36db6bcf54
12 changed files with 216 additions and 201 deletions

View File

@@ -42,7 +42,7 @@
#define SIGNED_FIT12(x) (((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)
struct _asm_thumb_t {
int pass;
uint pass;
uint code_offset;
uint code_size;
byte *code_base;
@@ -58,14 +58,9 @@ struct _asm_thumb_t {
asm_thumb_t *asm_thumb_new(uint max_num_labels) {
asm_thumb_t *as;
as = m_new(asm_thumb_t, 1);
as->pass = 0;
as->code_offset = 0;
as->code_size = 0;
as->code_base = NULL;
as = m_new0(asm_thumb_t, 1);
as->max_num_labels = max_num_labels;
as->label_offsets = m_new(int, max_num_labels);
as->num_locals = 0;
return as;
}
@@ -89,16 +84,16 @@ void asm_thumb_free(asm_thumb_t *as, bool free_code) {
m_del_obj(asm_thumb_t, as);
}
void asm_thumb_start_pass(asm_thumb_t *as, int pass) {
void asm_thumb_start_pass(asm_thumb_t *as, uint pass) {
as->pass = pass;
as->code_offset = 0;
if (pass == ASM_THUMB_PASS_2) {
if (pass == ASM_THUMB_PASS_COMPUTE) {
memset(as->label_offsets, -1, as->max_num_labels * sizeof(int));
}
}
void asm_thumb_end_pass(asm_thumb_t *as) {
if (as->pass == ASM_THUMB_PASS_2) {
if (as->pass == ASM_THUMB_PASS_COMPUTE) {
// calculate size of code in bytes
as->code_size = as->code_offset;
as->code_base = m_new(byte, as->code_size);
@@ -120,7 +115,7 @@ void asm_thumb_end_pass(asm_thumb_t *as) {
// all functions must go through this one to emit bytes
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_3) {
if (as->pass < ASM_THUMB_PASS_EMIT) {
as->code_offset += num_bytes_to_write;
return as->dummy_data;
} else {
@@ -224,12 +219,12 @@ void asm_thumb_exit(asm_thumb_t *as) {
void asm_thumb_label_assign(asm_thumb_t *as, uint label) {
assert(label < as->max_num_labels);
if (as->pass == ASM_THUMB_PASS_2) {
if (as->pass < ASM_THUMB_PASS_EMIT) {
// assign label offset
assert(as->label_offsets[label] == -1);
as->label_offsets[label] = as->code_offset;
} else if (as->pass == ASM_THUMB_PASS_3) {
// ensure label offset has not changed from PASS_2 to PASS_3
} 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);
}
@@ -383,20 +378,35 @@ void asm_thumb_mov_reg_i32_optimised(asm_thumb_t *as, uint reg_dest, int i32) {
}
}
// i32 is stored as a full word in the code, and aligned to machine-word boundary
// 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) {
asm_thumb_op16(as, ASM_THUMB_OP_NOP);
}
// jump over the i32 value (instruction prefect adds 4 to PC)
asm_thumb_op16(as, OP_B_N(0));
// store i32 on machine-word aligned boundary
asm_thumb_data(as, 4, i32);
// do the actual load of the i32 value
asm_thumb_mov_reg_i32_optimised(as, reg_dest, i32);
}
#define OP_STR_TO_SP_OFFSET(rlo_dest, word_offset) (0x9000 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
#define OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset) (0x9800 | ((rlo_dest) << 8) | ((word_offset) & 0x00ff))
void asm_thumb_mov_local_reg(asm_thumb_t *as, int local_num, uint rlo_src) {
assert(rlo_src < REG_R8);
int word_offset = as->num_locals - local_num - 1;
assert(as->pass < ASM_THUMB_PASS_3 || word_offset >= 0);
assert(as->pass < ASM_THUMB_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 < REG_R8);
int word_offset = as->num_locals - local_num - 1;
assert(as->pass < ASM_THUMB_PASS_3 || word_offset >= 0);
assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0);
asm_thumb_op16(as, OP_LDR_FROM_SP_OFFSET(rlo_dest, word_offset));
}
@@ -405,7 +415,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 < REG_R8);
int word_offset = as->num_locals - local_num - 1;
assert(as->pass < ASM_THUMB_PASS_3 || word_offset >= 0);
assert(as->pass < ASM_THUMB_PASS_EMIT || word_offset >= 0);
asm_thumb_op16(as, OP_ADD_REG_SP_OFFSET(rlo_dest, word_offset));
}