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:
parent
0d7103368a
commit
25fe224ea9
12 changed files with 216 additions and 1 deletions
|
|
@ -10,3 +10,5 @@
|
|||
#define HASH(l) ((l) & 0x1ffff)
|
||||
|
||||
#define BLOCK_MAX 0x3c0
|
||||
|
||||
#define CODEGEN_BACKEND_HAS_MOV_IMM
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -10,3 +10,5 @@
|
|||
#define HASH(l) ((l) & 0x1ffff)
|
||||
|
||||
#define BLOCK_MAX 0x3c0
|
||||
|
||||
#define CODEGEN_BACKEND_HAS_MOV_IMM
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue