diff --git a/src/codegen_backend_x86-64.h b/src/codegen_backend_x86-64.h index 150c8c8..3339224 100644 --- a/src/codegen_backend_x86-64.h +++ b/src/codegen_backend_x86-64.h @@ -10,3 +10,5 @@ #define HASH(l) ((l) & 0x1ffff) #define BLOCK_MAX 0x3c0 + +#define CODEGEN_BACKEND_HAS_MOV_IMM diff --git a/src/codegen_backend_x86-64_ops.c b/src/codegen_backend_x86-64_ops.c index c32cd26..41a88b2 100644 --- a/src/codegen_backend_x86-64_ops.c +++ b/src/codegen_backend_x86-64_ops.c @@ -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) diff --git a/src/codegen_backend_x86-64_ops.h b/src/codegen_backend_x86-64_ops.h index 3cd86fb..e1db22a 100644 --- a/src/codegen_backend_x86-64_ops.h +++ b/src/codegen_backend_x86-64_ops.h @@ -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); diff --git a/src/codegen_backend_x86-64_uops.c b/src/codegen_backend_x86-64_uops.c index 8b73909..b2ca7dc 100644 --- a/src/codegen_backend_x86-64_uops.c +++ b/src/codegen_backend_x86-64_uops.c @@ -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 diff --git a/src/codegen_backend_x86.h b/src/codegen_backend_x86.h index db521a7..7f9f233 100644 --- a/src/codegen_backend_x86.h +++ b/src/codegen_backend_x86.h @@ -10,3 +10,5 @@ #define HASH(l) ((l) & 0x1ffff) #define BLOCK_MAX 0x3c0 + +#define CODEGEN_BACKEND_HAS_MOV_IMM diff --git a/src/codegen_backend_x86_ops.c b/src/codegen_backend_x86_ops.c index 23726eb..7c8a18d 100644 --- a/src/codegen_backend_x86_ops.c +++ b/src/codegen_backend_x86_ops.c @@ -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); diff --git a/src/codegen_backend_x86_ops.h b/src/codegen_backend_x86_ops.h index 94f526c..a6ca19f 100644 --- a/src/codegen_backend_x86_ops.h +++ b/src/codegen_backend_x86_ops.h @@ -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); diff --git a/src/codegen_backend_x86_uops.c b/src/codegen_backend_x86_uops.c index 0acf07c..94092c3 100644 --- a/src/codegen_backend_x86_uops.c +++ b/src/codegen_backend_x86_uops.c @@ -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 diff --git a/src/codegen_ir.c b/src/codegen_ir.c index e902a1e..5406d6e 100644 --- a/src/codegen_ir.c +++ b/src/codegen_ir.c @@ -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)) { diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h index 76f4979..b1f4b3c 100644 --- a/src/codegen_ir_defs.h +++ b/src/codegen_ir_defs.h @@ -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 diff --git a/src/codegen_reg.c b/src/codegen_reg.c index c300a93..aed144b 100644 --- a/src/codegen_reg.c +++ b/src/codegen_reg.c @@ -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); diff --git a/src/codegen_reg.h b/src/codegen_reg.h index 5a30f65..80bc859 100644 --- a/src/codegen_reg.h +++ b/src/codegen_reg.h @@ -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);