From ee3f9210dc02e30f75f057ec48fa5bc8fdea5f10 Mon Sep 17 00:00:00 2001 From: SarahW Date: Sat, 23 Jun 2018 19:04:36 +0100 Subject: [PATCH] Implemented basic register allocation. Mainly handles 'virtual' registers at the moment (eg current and last PC values, segment override status, etc). --- src/Makefile.am | 2 +- src/codegen.c | 105 ++++++++++++++++++++-- src/codegen.h | 1 + src/codegen_backend.c | 3 + src/codegen_backend.h | 2 + src/codegen_backend_arm.c | 9 ++ src/codegen_backend_arm.h | 2 + src/codegen_backend_arm64.c | 9 ++ src/codegen_backend_arm64.h | 2 + src/codegen_backend_arm64_defs.h | 4 +- src/codegen_backend_arm64_uops.c | 52 ++++++++++- src/codegen_backend_arm_defs.h | 2 + src/codegen_backend_arm_uops.c | 51 ++++++++++- src/codegen_backend_x86-64.c | 7 ++ src/codegen_backend_x86-64_uops.c | 135 ++++++++++++++++++++++++++--- src/codegen_backend_x86.c | 7 ++ src/codegen_backend_x86.h | 2 + src/codegen_backend_x86_defs.h | 7 ++ src/codegen_backend_x86_uops.c | 119 ++++++++++++++++++++++--- src/codegen_ir.c | 14 ++- src/codegen_ir_defs.h | 87 +++++++++---------- src/codegen_reg.c | 139 ++++++++++++++++++++++++++++++ src/codegen_reg.h | 99 +++++++++++++++++++++ 23 files changed, 780 insertions(+), 80 deletions(-) create mode 100644 src/codegen_reg.c create mode 100644 src/codegen_reg.h diff --git a/src/Makefile.am b/src/Makefile.am index ff90dfa..c672b74 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,7 @@ wx-resources.cpp : pc.xrc # PCem pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acc2036.c acer386sx.c ali1429.c amstrad.c cbm_io.c cdrom-image.cc cdrom-null.c \ -cmd640.c codegen.c codegen_backend.c codegen_ir.c codegen_timing_486.c codegen_timing_686.c codegen_timing_common.c codegen_timing_pentium.c codegen_timing_winchip.c compaq.c config.c cpu.c \ +cmd640.c codegen.c codegen_backend.c codegen_ir.c codegen_reg.c codegen_timing_486.c codegen_timing_686.c codegen_timing_common.c codegen_timing_pentium.c codegen_timing_winchip.c compaq.c config.c cpu.c \ dells200.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c esdi_at.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \ hdd.c hdd_esdi.c hdd_file.c headland.c i430lx.c i430fx.c i430vx.c ide.c ide_atapi.c intel.c intel_flash.c io.c jim.c joystick_ch_flightstick_pro.c joystick_standard.c joystick_sw_pad.c \ joystick_tm_fcs.c keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ diff --git a/src/codegen.c b/src/codegen.c index 7e0dc9f..238f4f6 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -4,6 +4,8 @@ #include "codegen.h" #include "x86.h" +#include "386_common.h" + #include "codegen_backend.h" #include "codegen_ir.h" @@ -27,6 +29,16 @@ void codegen_timing_set(codegen_timing_t *timing) int codegen_in_recompile; +static int last_op_ssegs; +static x86seg *last_op_ea_seg; +static uint32_t last_op_32; + +void codegen_generate_reset() +{ + last_op_ssegs = -1; + last_op_ea_seg = NULL; + last_op_32 = -1; +} void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) { @@ -37,19 +49,99 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t int opcode_shift = 0; int opcode_mask = 0x3ff; uint32_t op_32 = use32; + x86seg *op_ea_seg = &_ds; + int op_ssegs = 0; + int over = 0; + op_ea_seg = &_ds; + while (!over) + { + switch (opcode) + { + case 0x0f: + op_table = x86_dynarec_opcodes_0f; +// recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xf0: /*LOCK*/ + break; + + case 0xf2: /*REPNE*/ + op_table = x86_dynarec_opcodes_REPNE; +// recomp_op_table = recomp_opcodes_REPNE; + break; + case 0xf3: /*REPE*/ + op_table = x86_dynarec_opcodes_REPE; +// recomp_op_table = recomp_opcodes_REPE; + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); +// codegen_timing_prefix(opcode, fetchdat); + if (cpu_state.abrt) + return; + opcode = fetchdat & 0xff; +// if (!pc_off) + fetchdat >>= 8; + + op_pc++; + } + +generate_call: //pclog("%04x:%08x : %02x\n", CS, new_pc, opcode); op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; - uop_STORE_PTR_IMM(ir, &cpu_state.pc, op_pc); - uop_STORE_PTR_IMM(ir, &cpu_state.oldpc, old_pc); - uop_STORE_PTR_IMM(ir, &cpu_state.op32, op_32); - uop_STORE_PTR_IMM(ir, &cpu_state.ea_seg, (uintptr_t)&_ds); - uop_STORE_PTR_IMM_8(ir, &cpu_state.ssegs, 0); + uop_MOV_IMM(ir, IREG_pc, op_pc); + uop_MOV_IMM(ir, IREG_oldpc, old_pc); + if (op_32 != last_op_32) + uop_MOV_IMM(ir, IREG_op32, op_32); +/*Lazy ea_seg/ssegs updating isn't safe until EA calculation is implemented*/ +// if (op_ea_seg != last_op_ea_seg) + uop_MOV_PTR(ir, IREG_ea_seg, (void *)op_ea_seg); +// if (op_ssegs != last_op_ssegs) + uop_MOV_IMM(ir, IREG_ssegs, op_ssegs); uop_LOAD_FUNC_ARG_IMM(ir, 0, fetchdat); uop_CALL_INSTRUCTION_FUNC(ir, op); + last_op_32 = op_32; + last_op_ea_seg = op_ea_seg; + last_op_ssegs = op_ssegs; //codegen_block_ins++; block->ins++; @@ -57,8 +149,5 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t if (block->ins >= 50) CPU_BLOCK_END(); -// addbyte(0xE8); /*CALL*/ -// addlong(((uint8_t *)codegen_debug - (uint8_t *)(&block->data[block_pos + 4]))); - codegen_endpc = (cs + cpu_state.pc) + 8; } diff --git a/src/codegen.h b/src/codegen.h index def016c..8106c1c 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -325,4 +325,5 @@ extern int codegen_reg_loaded[8]; extern int codegen_in_recompile; +void codegen_generate_reset(); #endif diff --git a/src/codegen_backend.c b/src/codegen_backend.c index a6ece39..2754f5e 100644 --- a/src/codegen_backend.c +++ b/src/codegen_backend.c @@ -12,6 +12,7 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_ir.h" +#include "codegen_reg.h" int codegen_flat_ds, codegen_flat_ss; int mmx_ebx_ecx_loaded; @@ -308,6 +309,8 @@ void codegen_block_start_recompile(codeblock_t *block) codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); ir_data = codegen_ir_init(); + codegen_reg_reset(); + codegen_generate_reset(); } diff --git a/src/codegen_backend.h b/src/codegen_backend.h index f281b75..0f73290 100644 --- a/src/codegen_backend.h +++ b/src/codegen_backend.h @@ -63,3 +63,5 @@ struct ir_data_t *codegen_get_ir_data(); typedef int (*uOpFn)(codeblock_t *codeblock, struct uop_t *uop); extern const uOpFn uop_handlers[]; + +extern int codegen_host_reg_list[CODEGEN_HOST_REGS]; diff --git a/src/codegen_backend_arm.c b/src/codegen_backend_arm.c index 9f0be91..fa0b57c 100644 --- a/src/codegen_backend_arm.c +++ b/src/codegen_backend_arm.c @@ -15,6 +15,15 @@ #include #endif +int codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + REG_R4, + REG_R5, + REG_R6, +// REG_X22, +// REG_X23 +}; + void codegen_backend_init() { int c; diff --git a/src/codegen_backend_arm.h b/src/codegen_backend_arm.h index 43b3fad..fd63315 100644 --- a/src/codegen_backend_arm.h +++ b/src/codegen_backend_arm.h @@ -1,3 +1,5 @@ +#include "codegen_backend_arm_defs.h" + #define BLOCK_SIZE 0x1000 #define BLOCK_MASK 0x0fff #define BLOCK_START 32 diff --git a/src/codegen_backend_arm64.c b/src/codegen_backend_arm64.c index 5fb6115..e433f43 100644 --- a/src/codegen_backend_arm64.c +++ b/src/codegen_backend_arm64.c @@ -15,6 +15,15 @@ #include #endif +int codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + REG_X19, + REG_X20, + REG_X21, + REG_X22, + REG_X23 +}; + void codegen_backend_init() { int c; diff --git a/src/codegen_backend_arm64.h b/src/codegen_backend_arm64.h index 6943eb6..21bef6d 100644 --- a/src/codegen_backend_arm64.h +++ b/src/codegen_backend_arm64.h @@ -1,3 +1,5 @@ +#include "codegen_backend_arm64_defs.h" + #define BLOCK_SIZE 0x1000 #define BLOCK_MASK 0x0fff #define BLOCK_START 64 diff --git a/src/codegen_backend_arm64_defs.h b/src/codegen_backend_arm64_defs.h index d70990a..56deb25 100644 --- a/src/codegen_backend_arm64_defs.h +++ b/src/codegen_backend_arm64_defs.h @@ -69,4 +69,6 @@ #define REG_ARG2 REG_X2 #define REG_ARG3 REG_X3 -#define REG_CPUSTATE REG_X29 \ No newline at end of file +#define REG_CPUSTATE REG_X29 + +#define CODEGEN_HOST_REGS 5 \ No newline at end of file diff --git a/src/codegen_backend_arm64_uops.c b/src/codegen_backend_arm64_uops.c index ee29eb2..2da9964 100644 --- a/src/codegen_backend_arm64_uops.c +++ b/src/codegen_backend_arm64_uops.c @@ -40,6 +40,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_LDP_POSTIDX_X (0x2a3 << 22) #define OPCODE_STP_PREIDX_X (0x2a6 << 22) #define OPCODE_STR_IMM_W (0x2e4 << 22) +#define OPCODE_STR_IMM_Q (0x3e4 << 22) #define OPCODE_STRB_IMM (0x0e4 << 22) #define OPCODE_BLR (0xd63f0000) @@ -55,6 +56,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OFFSET12_B(offset) (offset << 10) #define OFFSET12_W(offset) ((offset >> 2) << 10) +#define OFFSET12_Q(offset) ((offset >> 3) << 10) static int literal_offset = 0; void codegen_reset_literal_pool(codeblock_t *block) @@ -75,6 +77,7 @@ static int offset_is_19bit(int offset) #define in_range7_x(offset) (((offset) >= -0x200) && ((offset) < (0x200)) && !((offset) & 7)) #define in_range12_b(offset) (((offset) >= 0) && ((offset) < 0x1000)) #define in_range12_w(offset) (((offset) >= 0) && ((offset) < 0x4000) && !((offset) & 3)) +#define in_range12_q(offset) (((offset) >= 0) && ((offset) < 0x8000) && !((offset) & 7)) int add_literal(codeblock_t *block, uint32_t data) { @@ -201,6 +204,12 @@ void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int of fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); codegen_addlong(block, OPCODE_STR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); } +void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_q(offset)) + fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STR_IMM_Q | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) { if (!in_range12_b(offset)) @@ -261,6 +270,20 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, uop->dest_reg_a_real, uop->imm_data); + + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + int offset = add_literal_q(block, (uintptr_t)uop->p); + host_arm64_LDR_LITERAL_X(block, uop->dest_reg_a_real, offset); + + return 0; +} + static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) { host_arm64_mov_imm(block, REG_W16, uop->imm_data); @@ -294,7 +317,34 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, [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_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM }; +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_8 - not in range\n"); +} + +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_32 - not in range\n"); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_Q(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_ptr - not in range\n"); +} + #endif diff --git a/src/codegen_backend_arm_defs.h b/src/codegen_backend_arm_defs.h index a9253ab..f6fe556 100644 --- a/src/codegen_backend_arm_defs.h +++ b/src/codegen_backend_arm_defs.h @@ -42,3 +42,5 @@ #define REG_MASK_LOCAL (REG_MASK_R4 | REG_MASK_R5 | REG_MASK_R6 | REG_MASK_R7 | \ REG_MASK_R8 | REG_MASK_R9 | REG_MASK_R10 | REG_MASK_R11) + +#define CODEGEN_HOST_REGS 3 \ No newline at end of file diff --git a/src/codegen_backend_arm_uops.c b/src/codegen_backend_arm_uops.c index 5152fe4..40d1409 100644 --- a/src/codegen_backend_arm_uops.c +++ b/src/codegen_backend_arm_uops.c @@ -269,6 +269,28 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + uint32_t arm_imm; + + if (get_arm_imm(uop->imm_data, &arm_imm)) + host_arm_MOV_IMM(block, uop->dest_reg_a_real, uop->imm_data); + else + { + int offset = add_literal(block, uop->imm_data); + host_arm_LDR_IMM(block, uop->dest_reg_a_real, REG_LITERAL, offset); + } + + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + int offset = add_literal(block, (uintptr_t)uop->p); + host_arm_LDR_IMM(block, uop->dest_reg_a_real, REG_LITERAL, offset); + + return 0; +} + static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) { uint32_t arm_imm; @@ -308,7 +330,34 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, [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_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM }; +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_8 - not in range\n"); +} + +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_32 - not in range\n"); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_ptr - not in range\n"); +} + #endif diff --git a/src/codegen_backend_x86-64.c b/src/codegen_backend_x86-64.c index e123823..36b4567 100644 --- a/src/codegen_backend_x86-64.c +++ b/src/codegen_backend_x86-64.c @@ -13,6 +13,13 @@ #include #endif +int codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + REG_EAX, + REG_EBX, + REG_EDX +}; + static void *mem_abrt_rout; void codegen_backend_init() diff --git a/src/codegen_backend_x86-64_uops.c b/src/codegen_backend_x86-64_uops.c index f64636f..e5c231a 100644 --- a/src/codegen_backend_x86-64_uops.c +++ b/src/codegen_backend_x86-64_uops.c @@ -115,18 +115,95 @@ static void host_x86_JNZ(codeblock_t *block, void *p) codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); } -static void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) -{ - codegen_addbyte3(block, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ - codegen_addlong(block, (uint32_t)p); - codegen_addlong(block, imm_data); -} static void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { - codegen_addbyte3(block, 0xc6, 0x04, 0x25); /*MOVB p, imm_data*/ - codegen_addlong(block, (uint32_t)p); - codegen_addbyte(block, imm_data); + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_IMM - out of range %p\n", p); + codegen_addbyte3(block, 0xc6, 0x04, 0x25); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addbyte(block, imm_data); + } } +static 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); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); + codegen_addbyte3(block, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addlong(block, imm_data); + } +} + +static void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p); + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +static void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +static void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte4(block, 0x48, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p); + codegen_addbyte4(block, 0x48, 0x89, 0x04 | (src_reg << 3), 0x25); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} + + static void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data) { @@ -136,6 +213,15 @@ static void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_dat codegen_addlong(block, imm_data); } +static void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data) +{ + if (reg & 8) + fatal("host_x86_MOV64_REG_IMM reg & 8\n"); + codegen_addbyte2(block, 0x48, 0xb8 | reg); /*MOVQ reg, imm_data*/ + codegen_addquad(block, imm_data); +} + + static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) { if (!offset) @@ -201,6 +287,17 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_REG_IMM(block, uop->dest_reg_a_real, uop->imm_data); + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV64_REG_IMM(block, uop->dest_reg_a_real, (uint64_t)uop->p); + return 0; +} + static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) { if (((uintptr_t)uop->p) >> 32) @@ -226,7 +323,25 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, [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_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM }; +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV8_ABS_REG(block, p, host_reg); +} + +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV64_ABS_REG(block, p, host_reg); +} + #endif diff --git a/src/codegen_backend_x86.c b/src/codegen_backend_x86.c index 01a27b2..55430e0 100644 --- a/src/codegen_backend_x86.c +++ b/src/codegen_backend_x86.c @@ -13,6 +13,13 @@ #include #endif +int codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + REG_EAX, + REG_EBX, + REG_EDX +}; + static void *mem_abrt_rout; void codegen_backend_init() diff --git a/src/codegen_backend_x86.h b/src/codegen_backend_x86.h index 36361ec..5face4e 100644 --- a/src/codegen_backend_x86.h +++ b/src/codegen_backend_x86.h @@ -1,3 +1,5 @@ +#include "codegen_backend_x86_defs.h" + #define BLOCK_SIZE 0x4000 #define BLOCK_MASK 0x3fff #define BLOCK_START 0 diff --git a/src/codegen_backend_x86_defs.h b/src/codegen_backend_x86_defs.h index dcb9a58..f28915e 100644 --- a/src/codegen_backend_x86_defs.h +++ b/src/codegen_backend_x86_defs.h @@ -1,3 +1,6 @@ +#ifndef _CODEGEN_BACKEND_X86_DEFS_H_ +#define _CODEGEN_BACKEND_X86_DEFS_H_ + #define REG_EAX 0 #define REG_ECX 1 #define REG_EDX 2 @@ -6,3 +9,7 @@ #define REG_EBP 5 #define REG_ESI 6 #define REG_EDI 7 + +#define CODEGEN_HOST_REGS 3 + +#endif diff --git a/src/codegen_backend_x86_uops.c b/src/codegen_backend_x86_uops.c index 365382b..c19df3e 100644 --- a/src/codegen_backend_x86_uops.c +++ b/src/codegen_backend_x86_uops.c @@ -98,17 +98,81 @@ static void host_x86_JNZ(codeblock_t *block, void *p) codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block->data[block_pos + 4]); } -static void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) -{ - codegen_addbyte2(block, 0xc7, 0x05); /*MOV p, imm_data*/ - codegen_addlong(block, (uint32_t)p); - codegen_addlong(block, imm_data); -} static void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { - codegen_addbyte2(block, 0xc6, 0x05); /*MOVB p, imm_data*/ - codegen_addlong(block, (uint32_t)p); - codegen_addbyte(block, imm_data); + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + codegen_addbyte2(block, 0xc6, 0x05); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addbyte(block, imm_data); + } +} +static 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); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0xc7, 0x05); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addlong(block, imm_data); + } +} + +static void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/ + } + else + { + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} +static void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +static void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (!imm_data) + { + codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ + } + else + { + codegen_addbyte(block, 0xb8 + dst_reg); /*MOV reg, imm_data*/ + codegen_addlong(block, imm_data); + } } static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) @@ -138,11 +202,17 @@ static void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_ho codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ } +/*void codegen_debug() +{ + pclog(" %04x:%04x : %08x %08x %08x %08x\n", CS, cpu_state.pc, AX, BX, CX, DX); +}*/ + static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) { host_x86_CALL(block, uop->p); host_x86_TEST32_REG(block, REG_EAX, REG_EAX); host_x86_JNZ(block, &block->data[BLOCK_EXIT_OFFSET]); +// host_x86_CALL(block, codegen_debug); return 0; } @@ -168,6 +238,17 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_REG_IMM(block, uop->dest_reg_a_real, uop->imm_data); + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_REG_IMM(block, uop->dest_reg_a_real, (uint32_t)uop->p); + return 0; +} + static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) { host_x86_MOV32_ABS_IMM(block, uop->p, uop->imm_data); @@ -189,7 +270,25 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, [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_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM }; +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV8_ABS_REG(block, p, host_reg); +} + +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} + #endif diff --git a/src/codegen_ir.c b/src/codegen_ir.c index 4f8e1b4..692b9b4 100644 --- a/src/codegen_ir.c +++ b/src/codegen_ir.c @@ -2,6 +2,7 @@ #include "codegen.h" #include "codegen_backend.h" #include "codegen_ir.h" +#include "codegen_reg.h" static ir_data_t ir_block; @@ -25,10 +26,21 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) //pclog("uOP %i : %08x\n", c, uop->type); + 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->type & UOP_TYPE_BARRIER) + codegen_reg_flush(ir, block); + uop_handlers[uop->type & UOP_MASK](block, uop); } codegen_backend_epilogue(block); -// fatal("IR compilation complete\n"); + //fatal("IR compilation complete\n"); } diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h index 9293447..5bb310a 100644 --- a/src/codegen_ir_defs.h +++ b/src/codegen_ir_defs.h @@ -1,45 +1,10 @@ #ifndef _CODEGEN_IR_DEFS_ #define _CODEGEN_IR_DEFS_ -#define IREG_L (0 << 6) -#define IREG_W (1 << 6) -#define IREG_B (2 << 6) -#define IREG_BH (3 << 6) - -enum -{ - ireg_EAX = 0, - ireg_ECX = 1, - ireg_EDX = 2, - ireg_EBX = 3, - ireg_ESP = 4, - ireg_EBP = 5, - ireg_ESI = 6, - ireg_EDI = 7, - - ireg_flags_op = 8, - ireg_flags_reg = 9, - ireg_flags_op1 = 10, - ireg_flags_op2 = 11, - - ireg_flags_pc = 12, - ireg_flags_oldpc = 13, - - ireg_eaaddr = 14, - - /*Temporary registers are stored on the stack, and are not guaranteed to - be preserved across uOPs. They will not be written back if they will - not be read again.*/ - ireg_temp0 = 16, - ireg_temp1 = 17, - ireg_temp2 = 18, - ireg_temp3 = 19 -}; +#include "codegen_reg.h" #define UOP_REG(reg, size, version) ((reg) | (size) | (version << 8)) -#define UOP_REG_UNUSED 0xffff - /*uOP is a barrier. All previous uOPs must have completed before this one executes. All registers must have been written back or discarded*/ #define UOP_TYPE_BARRIER (1 << 31) @@ -65,20 +30,23 @@ enum #define UOP_CALL_INSTRUCTION_FUNC (UOP_TYPE_PARAMS_POINTER | 0x11 | UOP_TYPE_BARRIER) #define UOP_STORE_P_IMM (UOP_TYPE_PARAMS_IMM | 0x12) #define UOP_STORE_P_IMM_8 (UOP_TYPE_PARAMS_IMM | 0x13) +#define UOP_MOV_PTR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x20) +#define UOP_MOV_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x21) -#define UOP_MAX 0x14 +#define UOP_MAX 0x22 #define UOP_MASK 0xffff typedef struct uop_t { uint32_t type; - uint16_t dest_reg_a; - uint16_t src_reg_a; - uint16_t src_reg_b; - uint16_t src_reg_c; + ir_reg_t dest_reg_a; + ir_reg_t src_reg_a; + ir_reg_t src_reg_b; + ir_reg_t src_reg_c; uint32_t imm_data; void *p; + ir_host_reg_t dest_reg_a_real; } uop_t; #define UOP_NR_MAX 4096 @@ -98,20 +66,38 @@ static inline uop_t *uop_alloc(ir_data_t *ir) uop = &ir->uops[ir->wr_pos++]; - uop->dest_reg_a = UOP_REG_UNUSED; - uop->src_reg_a = UOP_REG_UNUSED; - uop->src_reg_b = UOP_REG_UNUSED; - uop->src_reg_c = UOP_REG_UNUSED; + uop->dest_reg_a = invalid_ir_reg; + uop->src_reg_a = invalid_ir_reg; + uop->src_reg_b = invalid_ir_reg; + uop->src_reg_c = invalid_ir_reg; return uop; } -static inline void uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int arg, uint16_t src_reg_a) +static inline void uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a) { uop_t *uop = uop_alloc(ir); uop->type = uop_type; - uop->src_reg_a = src_reg_a; + uop->src_reg_a = codegen_reg_read(src_reg_a); +} + +static inline void uop_gen_reg_dst_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int dest_reg, void *p) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->p = p; } static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) @@ -146,7 +132,14 @@ static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p #define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p) #define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p) +#define uop_MOV_IMM(ir, reg, imm) uop_gen_reg_dst_imm(UOP_MOV_IMM, ir, reg, imm) +#define uop_MOV_PTR(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOV_PTR, ir, reg, p) + #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) +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg); + #endif diff --git a/src/codegen_reg.c b/src/codegen_reg.c new file mode 100644 index 0000000..f9e3e36 --- /dev/null +++ b/src/codegen_reg.c @@ -0,0 +1,139 @@ +#include "ibm.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_ir_defs.h" +#include "codegen_reg.h" + +uint8_t reg_last_version[IREG_COUNT]; +uint8_t reg_version_refcount[IREG_COUNT][256]; + +ir_reg_t invalid_ir_reg = {IREG_INVALID}; + +ir_reg_t host_regs[CODEGEN_HOST_REGS]; + +enum +{ + REG_BYTE, + REG_WORD, + REG_DWORD, + REG_QWORD, + REG_POINTER +}; + +struct +{ + int native_size; + void *p; +} ireg_data[IREG_COUNT] = +{ + [IREG_EAX] = {REG_DWORD, &EAX}, + [IREG_ECX] = {REG_DWORD, &ECX}, + [IREG_EDX] = {REG_DWORD, &EDX}, + [IREG_EBX] = {REG_DWORD, &EBX}, + [IREG_ESP] = {REG_DWORD, &ESP}, + [IREG_EBP] = {REG_DWORD, &EBP}, + [IREG_ESI] = {REG_DWORD, &ESI}, + [IREG_EDI] = {REG_DWORD, &EDI}, + + [IREG_flags_op] = {REG_DWORD, &cpu_state.flags_op}, + [IREG_flags_res] = {REG_DWORD, &cpu_state.flags_res}, + [IREG_flags_op1] = {REG_DWORD, &cpu_state.flags_op1}, + [IREG_flags_op2] = {REG_DWORD, &cpu_state.flags_op2}, + + [IREG_pc] = {REG_DWORD, &cpu_state.pc}, + [IREG_oldpc] = {REG_DWORD, &cpu_state.oldpc}, + + [IREG_eaaddr] = {REG_DWORD, &cpu_state.eaaddr}, + [IREG_ea_seg] = {REG_POINTER, &cpu_state.ea_seg}, + + [IREG_op32] = {REG_DWORD, &cpu_state.op32}, + [IREG_ssegs] = {REG_BYTE, &cpu_state.ssegs}, + + /*Temporary registers are stored on the stack, and are not guaranteed to + be preserved across uOPs. They will not be written back if they will + not be read again.*/ + [IREG_temp0] = {REG_DWORD, NULL}, + [IREG_temp1] = {REG_DWORD, NULL}, + [IREG_temp2] = {REG_DWORD, NULL}, + [IREG_temp3] = {REG_DWORD, NULL} +}; + +void codegen_reg_reset() +{ + int c; + + for (c = 0; c < IREG_COUNT; c++) + { + reg_last_version[c] = 0; + reg_version_refcount[c][0] = 0; + } + for (c = 0; c < CODEGEN_HOST_REGS; c++) + host_regs[c] = invalid_ir_reg; +} + +static inline int ir_reg_is_invalid(ir_reg_t ir_reg) +{ + return (ir_reg.reg == IREG_INVALID); +} + +static void codegen_reg_writeback(codeblock_t *block, int c) +{ + int ir_reg = host_regs[c].reg; + + switch (ireg_data[ir_reg].native_size) + { + case REG_BYTE: + codegen_direct_write_8(block, ireg_data[ir_reg].p, codegen_host_reg_list[c]); + break; + + case REG_DWORD: + codegen_direct_write_32(block, ireg_data[ir_reg].p, codegen_host_reg_list[c]); + break; + + case REG_POINTER: + codegen_direct_write_ptr(block, ireg_data[ir_reg].p, codegen_host_reg_list[c]); + break; + + default: + fatal("codegen_reg_flush - native_size=%i\n", ireg_data[ir_reg].native_size); + } + + host_regs[c] = invalid_ir_reg; +} + +ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) +{ + int c; + + /*Search for unused registers*/ + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + if (ir_reg_is_invalid(host_regs[c])) + break; + } + + if (c == CODEGEN_HOST_REGS) + { + c = 0; + codegen_reg_writeback(block, c); +// fatal("codegen_reg_alloc_write_reg - out of registers\n"); + } + + host_regs[c].reg = ir_reg.reg; + host_regs[c].version = ir_reg.version; + + return codegen_host_reg_list[c]; +} + +void codegen_reg_flush(ir_data_t *ir, codeblock_t *block) +{ + int c; + + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + if (!ir_reg_is_invalid(host_regs[c])) + { + codegen_reg_writeback(block, c); + } + } +} diff --git a/src/codegen_reg.h b/src/codegen_reg.h new file mode 100644 index 0000000..1b8bd06 --- /dev/null +++ b/src/codegen_reg.h @@ -0,0 +1,99 @@ +#ifndef _CODEGEN_REG_H_ +#define _CODEGEN_REG_H_ + +#define IREG_SIZE_L (0 << 6) +#define IREG_SIZE_W (1 << 6) +#define IREG_SIZE_B (2 << 6) +#define IREG_SIZE_BH (3 << 6) + +enum +{ + IREG_EAX = 0, + IREG_ECX = 1, + IREG_EDX = 2, + IREG_EBX = 3, + IREG_ESP = 4, + IREG_EBP = 5, + IREG_ESI = 6, + IREG_EDI = 7, + + IREG_flags_op = 8, + IREG_flags_res = 9, + IREG_flags_op1 = 10, + IREG_flags_op2 = 11, + + IREG_pc = 12, + IREG_oldpc = 13, + + IREG_eaaddr = 14, + IREG_ea_seg = 15, + IREG_op32 = 16, + IREG_ssegs = 17, + + /*Temporary registers are stored on the stack, and are not guaranteed to + be preserved across uOPs. They will not be written back if they will + not be read again.*/ + IREG_temp0 = 20, + IREG_temp1 = 21, + IREG_temp2 = 22, + IREG_temp3 = 23, + + IREG_COUNT, + + IREG_INVALID = 255 +}; + +extern uint8_t reg_last_version[IREG_COUNT]; +extern uint8_t reg_version_refcount[IREG_COUNT][256]; + +typedef struct +{ + uint8_t reg; + uint8_t version; +} ir_reg_t; + +extern ir_reg_t invalid_ir_reg; + +typedef uint8_t ir_host_reg_t; + +static inline ir_reg_t codegen_reg_read(int reg) +{ + ir_reg_t ireg; + + if (reg == IREG_INVALID) + fatal("codegen_reg_read - IREG_INVALID\n"); + + ireg.reg = reg; + ireg.version = reg_last_version[reg]; + reg_version_refcount[ireg.reg][ireg.version]++; + if (!reg_version_refcount[ireg.reg][ireg.version]) + fatal("codegen_reg_read - refcount overflow\n"); + + return ireg; +} + +static inline ir_reg_t codegen_reg_write(int reg) +{ + ir_reg_t ireg; + + if (reg == IREG_INVALID) + fatal("codegen_reg_write - IREG_INVALID\n"); + + ireg.reg = reg; + ireg.version = reg_last_version[reg] + 1; + reg_last_version[reg]++; + if (!reg_last_version[reg]) + fatal("codegen_reg_write - version overflow\n"); + reg_version_refcount[reg][ireg.version] = 0; + + return ireg; +} + +struct ir_data_t; + +void codegen_reg_reset(); +void codegen_reg_flush(struct ir_data_t *ir, codeblock_t *block); + +ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg); + +#endif