From 0d7103368a5ee05be1e85ae7364107bfacacee96 Mon Sep 17 00:00:00 2001 From: SarahW Date: Mon, 14 Sep 2020 20:46:56 +0100 Subject: [PATCH] Add register rename optimisation to dynarec to eliminate some redundant UOP_MOVs. --- src/codegen_ir.c | 69 ++++++++++++++++++++++++++++------------------- src/codegen_reg.c | 36 +++++++++++++++++++++++++ src/codegen_reg.h | 2 ++ 3 files changed, 80 insertions(+), 27 deletions(-) diff --git a/src/codegen_ir.c b/src/codegen_ir.c index d7e6157..e902a1e 100644 --- a/src/codegen_ir.c +++ b/src/codegen_ir.c @@ -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) { diff --git a/src/codegen_reg.c b/src/codegen_reg.c index da6dd8c..c300a93 100644 --- a/src/codegen_reg.c +++ b/src/codegen_reg.c @@ -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; diff --git a/src/codegen_reg.h b/src/codegen_reg.h index 6bdb7c2..5a30f65 100644 --- a/src/codegen_reg.h +++ b/src/codegen_reg.h @@ -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