Add dynarec optimisation for UOP_MOV_IMM, to avoid register allocation

if the destination register won't be immediately used again.
This commit is contained in:
SarahW 2020-09-16 20:47:12 +01:00
commit 25fe224ea9
12 changed files with 216 additions and 1 deletions

View file

@ -10,3 +10,5 @@
#define HASH(l) ((l) & 0x1ffff)
#define BLOCK_MAX 0x3c0
#define CODEGEN_BACKEND_HAS_MOV_IMM

View file

@ -517,6 +517,26 @@ void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data)
codegen_addbyte(block, imm_data);
}
}
void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data)
{
int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
if (offset >= -128 && offset < 127)
{
codegen_alloc_bytes(block, 6);
codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/
codegen_addword(block, imm_data);
}
else
{
if ((uintptr_t)p >> 32)
fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p);
codegen_alloc_bytes(block, 10);
codegen_addbyte4(block, 0x66, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/
codegen_addlong(block, (uint32_t)(uintptr_t)p);
codegen_addword(block, imm_data);
}
}
void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data)
{
int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
@ -941,6 +961,30 @@ void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset
fatal("MOV64_BASE_OFFSET_REG - offset %i\n", offset);
}
void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data)
{
if (base_reg & 8)
fatal("host_x86_MOV32_BASE_OFFSET_IMM reg & 8\n");
if (offset >= -128 && offset < 127)
{
if (base_reg == REG_RSP)
{
codegen_alloc_bytes(block, 8);
codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset);
codegen_addlong(block, imm_data);
}
else
{
codegen_alloc_bytes(block, 7);
codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset);
codegen_addlong(block, imm_data);
}
}
else
fatal("MOV32_BASE_OFFSET_IMM - offset %i\n", offset);
}
void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data)
{
if (reg >= 8)

View file

@ -56,6 +56,7 @@ void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int sr
void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift);
void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data);
void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data);
void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data);
void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg);
@ -72,6 +73,8 @@ void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg
void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg);
void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg);
void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data);
void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p);
void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p);
void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p);

View file

@ -3141,4 +3141,21 @@ void codegen_set_jump_dest(codeblock_t *block, void *p)
*(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4);
}
void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data)
{
host_x86_MOV8_ABS_IMM(block, p, imm_data);
}
void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data)
{
host_x86_MOV16_ABS_IMM(block, p, imm_data);
}
void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data)
{
host_x86_MOV32_ABS_IMM(block, p, imm_data);
}
void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data)
{
host_x86_MOV32_BASE_OFFSET_IMM(block, REG_ESP, stack_offset, imm_data);
}
#endif

View file

@ -10,3 +10,5 @@
#define HASH(l) ((l) & 0x1ffff)
#define BLOCK_MAX 0x3c0
#define CODEGEN_BACKEND_HAS_MOV_IMM

View file

@ -445,6 +445,24 @@ void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data)
codegen_addbyte(block, imm_data);
}
}
void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data)
{
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
if (offset >= -128 && offset < 127)
{
codegen_alloc_bytes(block, 6);
codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/
codegen_addword(block, imm_data);
}
else
{
codegen_alloc_bytes(block, 9);
codegen_addbyte3(block, 0x66, 0xc7, 0x05); /*MOV p, imm_data*/
codegen_addlong(block, (uint32_t)p);
codegen_addword(block, imm_data);
}
}
void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data)
{
int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128);
@ -701,6 +719,27 @@ void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset
fatal("MOV32_BASE_OFFSET_REG - offset %i\n", offset);
}
void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data)
{
if (offset >= -128 && offset < 127)
{
if (base_reg == REG_ESP)
{
codegen_alloc_bytes(block, 8);
codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset);
codegen_addlong(block, imm_data);
}
else
{
codegen_alloc_bytes(block, 7);
codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset);
codegen_addlong(block, imm_data);
}
}
else
fatal("MOV32_BASE_OFFSET_IMM - offset %i\n", offset);
}
void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data)
{
codegen_alloc_bytes(block, 2);

View file

@ -60,6 +60,7 @@ void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int sr
void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift);
void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data);
void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data);
void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data);
void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg);
@ -75,6 +76,8 @@ void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg
void host_x86_MOV16_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg);
void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg);
void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data);
void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p);
void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p);
void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p);

View file

@ -2644,6 +2644,11 @@ static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop)
host_x86_MOV8_ABS_IMM(block, uop->p, uop->imm_data);
return 0;
}
static int codegen_STORE_PTR_IMM_16(codeblock_t *block, uop_t *uop)
{
host_x86_MOV16_ABS_IMM(block, uop->p, uop->imm_data);
return 0;
}
static int codegen_SUB(codeblock_t *block, uop_t *uop)
{
@ -2839,6 +2844,7 @@ const uOpFn uop_handlers[UOP_MAX] =
[UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM,
[UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8,
[UOP_STORE_P_IMM_16 & UOP_MASK] = codegen_STORE_PTR_IMM_16,
[UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS,
[UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG,
@ -3139,4 +3145,21 @@ void codegen_set_jump_dest(codeblock_t *block, void *p)
*(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4);
}
void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data)
{
host_x86_MOV8_ABS_IMM(block, p, imm_data);
}
void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data)
{
host_x86_MOV16_ABS_IMM(block, p, imm_data);
}
void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data)
{
host_x86_MOV32_ABS_IMM(block, p, imm_data);
}
void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data)
{
host_x86_MOV32_BASE_OFFSET_IMM(block, REG_ESP, stack_offset, imm_data);
}
#endif

View file

@ -107,7 +107,15 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block)
if ((uop->type & UOP_MASK) == UOP_INVALID)
continue;
#ifdef CODEGEN_BACKEND_HAS_MOV_IMM
if ((uop->type & UOP_MASK) == (UOP_MOV_IMM & UOP_MASK) && reg_is_native_size(uop->dest_reg_a) && !codegen_reg_is_loaded(uop->dest_reg_a) && reg_version[IREG_GET_REG(uop->dest_reg_a.reg)][uop->dest_reg_a.version].refcount <= 0)
{
/*Special case for UOP_MOV_IMM - if destination not already in host register
and won't be used again then just store directly to memory*/
codegen_reg_write_imm(block, uop->dest_reg_a, uop->imm_data);
}
else
#endif
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))
{

View file

@ -55,6 +55,7 @@
/*UOP_JMP_DEST - jump to ptr*/
#define UOP_JMP_DEST (UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x17 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP)
#define UOP_NOP_BARRIER (UOP_TYPE_BARRIER | 0x18)
#define UOP_STORE_P_IMM_16 (UOP_TYPE_PARAMS_IMM | 0x19)
#ifdef DEBUG_EXTRA
/*UOP_LOG_INSTR - log non-recompiled instruction in imm_data*/
@ -765,6 +766,7 @@ static inline void uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, in
#define uop_STORE_PTR_IMM(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM, ir, p, imm)
#define uop_STORE_PTR_IMM_8(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_8, ir, p, imm)
#define uop_STORE_PTR_IMM_16(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_16, ir, p, imm)
#define uop_TEST_JNS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JNS_DEST, ir, src_reg)
#define uop_TEST_JS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JS_DEST, ir, src_reg)
@ -807,4 +809,9 @@ void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int
void codegen_set_jump_dest(codeblock_t *block, void *p);
void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data);
void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data);
void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data);
void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data);
#endif

View file

@ -449,6 +449,45 @@ static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, i
reg_set->dirty[c] = 0;
}
#ifdef CODEGEN_BACKEND_HAS_MOV_IMM
void codegen_reg_write_imm(codeblock_t *block, ir_reg_t ir_reg, uint32_t imm_data)
{
int reg_idx = IREG_GET_REG(ir_reg.reg);
void *p = ireg_data[reg_idx].p;
switch (ireg_data[reg_idx].native_size)
{
case REG_BYTE:
if ((uintptr_t)p < 256)
fatal("codegen_reg_write_imm - REG_BYTE %p\n", p);
codegen_direct_write_8_imm(block, p, imm_data);
break;
case REG_WORD:
if ((uintptr_t)p < 256)
fatal("codegen_reg_write_imm - REG_WORD %p\n", p);
codegen_direct_write_16_imm(block, p, imm_data);
break;
case REG_DWORD:
if ((uintptr_t)p < 256)
codegen_direct_write_32_imm_stack(block, (int)p, imm_data);
else
codegen_direct_write_32_imm(block, p, imm_data);
break;
case REG_POINTER:
case REG_QWORD:
case REG_DOUBLE:
case REG_FPU_ST_BYTE:
case REG_FPU_ST_QWORD:
case REG_FPU_ST_DOUBLE:
default:
fatal("codegen_reg_write_imm - native_size=%i\n", ireg_data[reg_idx].native_size);
}
}
#endif
static void alloc_reg(ir_reg_t ir_reg)
{
host_reg_set_t *reg_set = get_reg_set(ir_reg);
@ -671,6 +710,29 @@ 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);
}
#ifdef CODEGEN_BACKEND_HAS_MOV_IMM
int codegen_reg_is_loaded(ir_reg_t ir_reg)
{
host_reg_set_t *reg_set = get_reg_set(ir_reg);
int c;
/*Search for previous version in host 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(ir_reg.reg))
{
if (reg_set->regs[c].version <= ir_reg.version-1)
{
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");
return 1;
}
}
}
return 0;
}
#endif
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);

View file

@ -396,6 +396,11 @@ void codegen_reg_flush_invalidate(struct ir_data_t *ir, codeblock_t *block);
/*Register ir_reg usage for this uOP. This ensures that required registers aren't evicted*/
void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c);
#ifdef CODEGEN_BACKEND_HAS_MOV_IMM
int codegen_reg_is_loaded(ir_reg_t ir_reg);
void codegen_reg_write_imm(codeblock_t *block, ir_reg_t ir_reg, uint32_t imm_data);
#endif
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);