Optimise out redundant uOPs, where the output register is never read.
This commit is contained in:
parent
84622584e2
commit
3f2d9ecf87
4 changed files with 200 additions and 57 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue