Add register rename optimisation to dynarec to eliminate some redundant
UOP_MOVs.
This commit is contained in:
parent
cccaf86fd3
commit
0d7103368a
3 changed files with 77 additions and 24 deletions
|
|
@ -107,37 +107,52 @@ 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);
|
||||
if (uop->src_reg_a.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL);
|
||||
}
|
||||
if (uop->src_reg_b.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b, NULL);
|
||||
}
|
||||
if (uop->src_reg_c.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_c_real = codegen_reg_alloc_read_reg(block, uop->src_reg_c, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (uop->type & UOP_TYPE_ORDER_BARRIER)
|
||||
codegen_reg_flush(ir, block);
|
||||
|
||||
if (uop->type & UOP_TYPE_PARAMS_REGS)
|
||||
if ((uop->type & UOP_MASK) == (UOP_MOV & UOP_MASK) && reg_version[IREG_GET_REG(uop->src_reg_a.reg)][uop->src_reg_a.version].refcount <= 1 &&
|
||||
reg_is_native_size(uop->src_reg_a) && reg_is_native_size(uop->dest_reg_a))
|
||||
{
|
||||
if (uop->dest_reg_a.reg != IREG_INVALID)
|
||||
{
|
||||
uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a);
|
||||
}
|
||||
/*Special case for UOP_MOV - if source register won't be used again then
|
||||
just rename it to dest register instead of moving*/
|
||||
codegen_reg_alloc_register(invalid_ir_reg, uop->src_reg_a, invalid_ir_reg, invalid_ir_reg);
|
||||
uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL);
|
||||
codegen_reg_rename(block, uop->src_reg_a, uop->dest_reg_a);
|
||||
if (uop->type & UOP_TYPE_ORDER_BARRIER)
|
||||
codegen_reg_flush(ir, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
if (uop->src_reg_a.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL);
|
||||
}
|
||||
if (uop->src_reg_b.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b, NULL);
|
||||
}
|
||||
if (uop->src_reg_c.reg != IREG_INVALID)
|
||||
{
|
||||
uop->src_reg_c_real = codegen_reg_alloc_read_reg(block, uop->src_reg_c, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (uop->type & UOP_TYPE_ORDER_BARRIER)
|
||||
codegen_reg_flush(ir, block);
|
||||
|
||||
if (uop->type & UOP_TYPE_PARAMS_REGS)
|
||||
{
|
||||
if (uop->dest_reg_a.reg != IREG_INVALID)
|
||||
{
|
||||
uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a);
|
||||
}
|
||||
}
|
||||
|
||||
if (!uop_handlers[uop->type & UOP_MASK])
|
||||
fatal("!uop_handlers[uop->type & UOP_MASK] %08x\n", uop->type);
|
||||
uop_handlers[uop->type & UOP_MASK](block, uop);
|
||||
if (!uop_handlers[uop->type & UOP_MASK])
|
||||
fatal("!uop_handlers[uop->type & UOP_MASK] %08x\n", uop->type);
|
||||
uop_handlers[uop->type & UOP_MASK](block, uop);
|
||||
}
|
||||
|
||||
if (uop->type & UOP_TYPE_JUMP)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -671,6 +671,42 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg)
|
|||
return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg);
|
||||
}
|
||||
|
||||
void codegen_reg_rename(codeblock_t *block, ir_reg_t src, ir_reg_t dst)
|
||||
{
|
||||
host_reg_set_t *reg_set = get_reg_set(src);
|
||||
int c;
|
||||
int target;
|
||||
|
||||
// pclog("rename: %i.%i -> %i.%i\n", src.reg,src.version, dst.reg, dst.version);
|
||||
/*Search for required register*/
|
||||
for (c = 0; c < reg_set->nr_regs; c++)
|
||||
{
|
||||
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(src.reg) && reg_set->regs[c].version == src.version)
|
||||
break;
|
||||
}
|
||||
if (c == reg_set->nr_regs)
|
||||
fatal("codegen_reg_rename: Can't find register to rename\n");
|
||||
|
||||
target = c;
|
||||
if (reg_set->dirty[target])
|
||||
codegen_reg_writeback(reg_set, block, target, 0);
|
||||
reg_set->regs[target] = dst;
|
||||
reg_set->dirty[target] = 1;
|
||||
// pclog("renamed reg %i dest=%i.%i\n", target, dst.reg, dst.version);
|
||||
|
||||
/*Invalidate any stale copies of the dest register*/
|
||||
for (c = 0; c < reg_set->nr_regs; c++)
|
||||
{
|
||||
if (c == target)
|
||||
continue;
|
||||
if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(dst.reg))
|
||||
{
|
||||
reg_set->regs[c] = invalid_ir_reg;
|
||||
reg_set->dirty[c] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_reg_flush(ir_data_t *ir, codeblock_t *block)
|
||||
{
|
||||
host_reg_set_t *reg_set;
|
||||
|
|
|
|||
|
|
@ -399,6 +399,8 @@ 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_rename(codeblock_t *block, ir_reg_t src, ir_reg_t dst);
|
||||
|
||||
void codegen_reg_mark_as_required();
|
||||
void codegen_reg_process_dead_list(struct ir_data_t *ir);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue