From 3f2d9ecf870e64a11c60ab49c2ee1f652734e11c Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 10 Feb 2019 12:32:25 +0000 Subject: [PATCH] Optimise out redundant uOPs, where the output register is never read. --- src/codegen_ir.c | 5 ++ src/codegen_ir_defs.h | 69 ++++++++++++------------ src/codegen_reg.c | 119 ++++++++++++++++++++++++++++++++++++------ src/codegen_reg.h | 64 +++++++++++++++++++---- 4 files changed, 200 insertions(+), 57 deletions(-) diff --git a/src/codegen_ir.c b/src/codegen_ir.c index 556cb8c..56d58f7 100644 --- a/src/codegen_ir.c +++ b/src/codegen_ir.c @@ -21,6 +21,8 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) int jump_target_at_end = -1; int c; + codegen_reg_mark_as_required(); + codegen_reg_process_dead_list(ir); block_write_data = codeblock_allocator_get_ptr(block->head_mem_block); block_pos = 0; codegen_backend_prologue(block); @@ -45,6 +47,9 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) } } + if ((uop->type & UOP_MASK) == UOP_INVALID) + continue; + if (uop->type & UOP_TYPE_PARAMS_REGS) { codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c); diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h index a69f346..74b0043 100644 --- a/src/codegen_ir_defs.h +++ b/src/codegen_ir_defs.h @@ -312,6 +312,8 @@ #define UOP_MAX 0xc6 +#define UOP_INVALID 0xff + #define UOP_MASK 0xffff typedef struct uop_t @@ -338,7 +340,7 @@ typedef struct ir_data_t int wr_pos; } ir_data_t; -static inline uop_t *uop_alloc(ir_data_t *ir) +static inline uop_t *uop_alloc(ir_data_t *ir, uint32_t uop_type) { uop_t *uop; @@ -353,7 +355,10 @@ static inline uop_t *uop_alloc(ir_data_t *ir) uop->src_reg_c = invalid_ir_reg; uop->jump_list_next = -1; - + + if (uop_type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER)) + codegen_reg_mark_as_required(); + return uop; } @@ -366,7 +371,7 @@ static inline void uop_set_jump_dest(ir_data_t *ir, int jump_uop) static inline int uop_gen(uint32_t uop_type, ir_data_t *ir) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; @@ -375,7 +380,7 @@ static inline int uop_gen(uint32_t uop_type, ir_data_t *ir) static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -385,7 +390,7 @@ static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -393,7 +398,7 @@ static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int ar static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src_reg, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg); @@ -404,86 +409,86 @@ static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src static inline void uop_gen_reg_dst_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->imm_data = imm; } static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int dest_reg, void *p) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->p = p; } static inline void uop_gen_reg_dst_src1(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg); - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); } static inline void uop_gen_reg_dst_src1_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->imm_data = imm; } static inline void uop_gen_reg_dst_src2(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); uop->src_reg_b = codegen_reg_read(src_reg_b); - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); } static inline void uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); uop->src_reg_b = codegen_reg_read(src_reg_b); - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->imm_data = imm; } static inline void uop_gen_reg_dst_src3(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, int src_reg_c) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); uop->src_reg_b = codegen_reg_read(src_reg_b); uop->src_reg_c = codegen_reg_read(src_reg_c); - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); } static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg); - uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); uop->imm_data = imm; } static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -494,7 +499,7 @@ static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -504,7 +509,7 @@ static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int sr static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -514,7 +519,7 @@ static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_re static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -525,7 +530,7 @@ static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int sr static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->imm_data = imm; @@ -533,7 +538,7 @@ static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->p = p; @@ -541,7 +546,7 @@ static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p) static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->p = p; @@ -550,7 +555,7 @@ static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p static inline void uop_gen_reg_src_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -559,7 +564,7 @@ static inline void uop_gen_reg_src_pointer(uint32_t uop_type, ir_data_t *ir, int static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p, uint32_t imm) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); @@ -569,7 +574,7 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, static inline void uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, void *p) { - uop_t *uop = uop_alloc(ir); + uop_t *uop = uop_alloc(ir, uop_type); uop->type = uop_type; uop->src_reg_a = codegen_reg_read(src_reg_a); diff --git a/src/codegen_reg.c b/src/codegen_reg.c index f352d0a..dda256c 100644 --- a/src/codegen_reg.c +++ b/src/codegen_reg.c @@ -4,8 +4,10 @@ #include "codegen_ir_defs.h" #include "codegen_reg.h" +uint16_t reg_dead_list = 0; + uint8_t reg_last_version[IREG_COUNT]; -uint8_t reg_version_refcount[IREG_COUNT][256]; +reg_version_t reg_version[IREG_COUNT][256]; ir_reg_t invalid_ir_reg = {IREG_INVALID}; @@ -175,6 +177,19 @@ struct [IREG_temp1d] = {REG_DOUBLE, (void *)48, REG_FP, REG_VOLATILE}, }; +void codegen_reg_mark_as_required() +{ + int reg; + + for (reg = 0; reg < IREG_COUNT; reg++) + { + int last_version = reg_last_version[reg]; + + if (last_version > 0 && ireg_data[reg].is_volatile == REG_PERMANENT) + reg_version[reg][last_version].flags |= REG_FLAGS_REQUIRED; + } +} + static int reg_is_native_size(ir_reg_t ir_reg) { int native_size = ireg_data[IREG_GET_REG(ir_reg.reg)].native_size; @@ -220,7 +235,7 @@ void codegen_reg_reset() for (c = 0; c < IREG_COUNT; c++) { reg_last_version[c] = 0; - reg_version_refcount[c][0] = 0; + reg_version[c][0].refcount = 0; } for (c = 0; c < CODEGEN_HOST_REGS; c++) { @@ -232,6 +247,8 @@ void codegen_reg_reset() host_fp_reg_set.regs[c] = invalid_ir_reg; host_fp_reg_set.dirty[c] = 0; } + + reg_dead_list = 0; } static inline int ir_reg_is_invalid(ir_reg_t ir_reg) @@ -239,9 +256,9 @@ static inline int ir_reg_is_invalid(ir_reg_t ir_reg) return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID); } -static inline int ir_get_get_refcount(ir_reg_t ir_reg) +static inline int ir_get_refcount(ir_reg_t ir_reg) { - return reg_version_refcount[IREG_GET_REG(ir_reg.reg)][ir_reg.version]; + return reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version].refcount; } static inline host_reg_set_t *get_reg_set(ir_reg_t ir_reg) @@ -342,7 +359,7 @@ static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, i int ir_reg = IREG_GET_REG(reg_set->regs[c].reg); void *p = ireg_data[ir_reg].p; - if (!reg_version_refcount[ir_reg][reg_set->regs[c].version] && + if (!reg_version[ir_reg][reg_set->regs[c].version].refcount && ireg_data[ir_reg].is_volatile) return; @@ -463,10 +480,30 @@ static void alloc_dest_reg(ir_reg_t ir_reg, int dest_reference) { if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) { - if (reg_set->regs[c].version == ir_reg.version || (reg_set->regs[c].version == (ir_reg.version-1) && reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] == dest_reference)) + if (reg_set->regs[c].version == ir_reg.version) + { reg_set->locked |= (1 << c); + } else + { + /*The immediate prior version may have been + optimised out, so search backwards to find the + last valid version*/ + int prev_version = ir_reg.version-1; +// pclog("prev_version search from %i\n", prev_version); + while (prev_version >= 0) + { + reg_version_t *regv = ®_version[IREG_GET_REG(reg_set->regs[c].reg)][prev_version]; + + if (!(regv->flags & REG_FLAGS_DEAD) && regv->refcount == dest_reference) + { + reg_set->locked |= (1 << c); + return; + } + prev_version--; + } fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", reg_set->regs[c].version, ir_reg.version, dest_reference); + } return; } } @@ -513,7 +550,13 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version == ir_reg.version) break; - if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version]) + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version <= ir_reg.version) + { + reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount++; + break; + } + + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount) fatal("codegen_reg_alloc_read_reg - version mismatch!\n"); } @@ -522,7 +565,7 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in /*No unused registers. Search for an unlocked register with no pending reads*/ for (c = 0; c < reg_set->nr_regs; c++) { - if (!(reg_set->locked & (1 << c)) && !ir_get_get_refcount(reg_set->regs[c])) + if (!(reg_set->locked & (1 << c)) && IREG_GET_REG(reg_set->regs[c].reg) != IREG_INVALID && !ir_get_refcount(reg_set->regs[c])) break; } if (c == reg_set->nr_regs) @@ -548,13 +591,13 @@ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, in // else // pclog(" already loaded %i\n", c); - reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version]--; - if (reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] == (uint8_t)-1) + reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount--; + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount == (uint8_t)-1) fatal("codegen_reg_alloc_read_reg - refcount < 0\n"); if (host_reg_idx) *host_reg_idx = c; -// pclog(" codegen_reg_alloc_read_reg: %i.%i %i %02x.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c], host_regs[c].reg,host_regs[c].version, c); +// pclog(" codegen_reg_alloc_read_reg: %i.%i %i %02x.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c], reg_set->regs[c].reg,reg_set->regs[c].version, c); return reg_set->reg_list[c] | IREG_GET_SIZE(ir_reg.reg); } @@ -570,11 +613,11 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) parent_reg.reg = IREG_GET_REG(ir_reg.reg) | IREG_SIZE_L; parent_reg.version = ir_reg.version - 1; - reg_version_refcount[IREG_GET_REG(ir_reg.reg)][ir_reg.version - 1]++; + reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version - 1].refcount++; codegen_reg_alloc_read_reg(block, parent_reg, &c); - if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version != ir_reg.version-1) + if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version > ir_reg.version-1) fatal("codegen_reg_alloc_write_reg sub_reg - doesn't match %i %02x.%i %02x.%i\n", c, reg_set->regs[c].reg,reg_set->regs[c].version, ir_reg.reg,ir_reg.version); @@ -591,9 +634,9 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) { if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) { - if (reg_set->regs[c].version == ir_reg.version-1) + if (reg_set->regs[c].version <= ir_reg.version-1) { - if (reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] != 0) + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount != 0) fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); break; } @@ -682,3 +725,49 @@ void codegen_reg_flush_invalidate(ir_data_t *ir, codeblock_t *block) reg_set->dirty[c] = 0; } } + +/*Process dead register list, and optimise out register versions and uOPs where + possible*/ +void codegen_reg_process_dead_list(ir_data_t *ir) +{ + while (reg_dead_list) + { + int version = reg_dead_list & 0xff; + int reg = reg_dead_list >> 8; + reg_version_t *regv = ®_version[reg][version]; + uop_t *uop = &ir->uops[regv->parent_uop]; + + /*Barrier uOPs should be preserved*/ + if (!(uop->type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER))) + { +// pclog(" codegen_process_dead_list: reg=%i version=%i uop=%i\n", reg, version, regv->parent_uop); + uop->type = UOP_INVALID; + /*Adjust refcounts on source registers. If these drop to + zero then those registers can be considered for removal*/ + if (uop->src_reg_a.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_a.reg)][uop->src_reg_a.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_a.reg), uop->src_reg_a.version); + } + if (uop->src_reg_b.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_b.reg)][uop->src_reg_b.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_b.reg), uop->src_reg_b.version); + } + if (uop->src_reg_c.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_c.reg)][uop->src_reg_c.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_c.reg), uop->src_reg_c.version); + } + regv->flags |= REG_FLAGS_DEAD; + } + + reg_dead_list = regv->next; + } +} diff --git a/src/codegen_reg.h b/src/codegen_reg.h index 448518e..01272bc 100644 --- a/src/codegen_reg.h +++ b/src/codegen_reg.h @@ -272,7 +272,36 @@ static inline int ireg_seg_limit_high(x86seg *seg) } extern uint8_t reg_last_version[IREG_COUNT]; -extern uint8_t reg_version_refcount[IREG_COUNT][256]; + +/*This version of the register must be calculated, regardless of whether it is + apparently required or not. Do not optimise out.*/ +#define REG_FLAGS_REQUIRED (1 << 0) +/*This register and the parent uOP have been optimised out.*/ +#define REG_FLAGS_DEAD (1 << 1) + +typedef struct +{ + /*Refcount of pending reads on this register version*/ + uint8_t refcount; + /*Flags*/ + uint8_t flags; + /*uOP that generated this register version*/ + uint16_t parent_uop; + /*Pointer to next register version in dead register list*/ + uint16_t next; +} reg_version_t; + +extern reg_version_t reg_version[IREG_COUNT][256]; + +/*Head of dead register list; a list of register versions that are not used and + can be optimised out*/ +extern uint16_t reg_dead_list; + +static inline void add_to_dead_list(reg_version_t *regv, int reg, int version) +{ + regv->next = reg_dead_list; + reg_dead_list = version | (reg << 8); +} typedef struct { @@ -289,37 +318,50 @@ typedef uint16_t ir_host_reg_t; static inline ir_reg_t codegen_reg_read(int reg) { ir_reg_t ireg; + reg_version_t *version; if (IREG_GET_REG(reg) == IREG_INVALID) fatal("codegen_reg_read - IREG_INVALID\n"); ireg.reg = reg; ireg.version = reg_last_version[IREG_GET_REG(reg)]; - reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]++; - if (!reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]) + version = ®_version[IREG_GET_REG(ireg.reg)][ireg.version]; + version->flags = 0; + version->refcount++; + if (!version->refcount) fatal("codegen_reg_read - refcount overflow\n"); - else if (reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version] > REG_VERSION_MAX) + else if (version->refcount > REG_VERSION_MAX) CPU_BLOCK_END(); - +// pclog("codegen_reg_read: %i %i %i\n", reg & IREG_REG_MASK, ireg.version, reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]); return ireg; } -static inline ir_reg_t codegen_reg_write(int reg) +static inline ir_reg_t codegen_reg_write(int reg, int uop_nr) { ir_reg_t ireg; - + int last_version = reg_last_version[IREG_GET_REG(reg)]; + reg_version_t *version; + if (IREG_GET_REG(reg) == IREG_INVALID) fatal("codegen_reg_write - IREG_INVALID\n"); ireg.reg = reg; - ireg.version = reg_last_version[IREG_GET_REG(reg)] + 1; + ireg.version = last_version + 1; + + if (IREG_GET_REG(reg) > IREG_EBX && last_version && !reg_version[IREG_GET_REG(reg)][last_version].refcount && + !(reg_version[IREG_GET_REG(reg)][last_version].flags & REG_FLAGS_REQUIRED)) + add_to_dead_list(®_version[IREG_GET_REG(reg)][last_version], IREG_GET_REG(reg), last_version); + reg_last_version[IREG_GET_REG(reg)]++; if (!reg_last_version[IREG_GET_REG(reg)]) fatal("codegen_reg_write - version overflow\n"); else if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX) CPU_BLOCK_END(); - reg_version_refcount[IREG_GET_REG(reg)][ireg.version] = 0; - + version = ®_version[IREG_GET_REG(reg)][ireg.version]; + version->refcount = 0; + version->flags = 0; + version->parent_uop = uop_nr; +// pclog("codegen_reg_write: %i\n", reg & IREG_REG_MASK); return ireg; } @@ -337,4 +379,6 @@ void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_ ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx); ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg); +void codegen_reg_mark_as_required(); +void codegen_reg_process_dead_list(struct ir_data_t *ir); #endif