diff --git a/src/386_dynarec_ops.c b/src/386_dynarec_ops.c index 23c8036..5377a27 100644 --- a/src/386_dynarec_ops.c +++ b/src/386_dynarec_ops.c @@ -23,64 +23,6 @@ static inline void fetch_ea_32_long(uint32_t rmdat) eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; ea_rseg = cpu_state.ea_seg->seg; - if (cpu_rm == 4) - { - uint8_t sib = rmdat >> 8; - - switch (cpu_mod) - { - case 0: - cpu_state.eaaddr = cpu_state.regs[sib & 7].l; - cpu_state.pc++; - break; - case 1: - cpu_state.pc++; - cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; -// cpu_state.pc++; - break; - case 2: - cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; - cpu_state.pc += 5; - break; - } - /*SIB byte present*/ - if ((sib & 7) == 5 && !cpu_mod) - cpu_state.eaaddr = getlong(); - else if ((sib & 6) == 4 && !cpu_state.ssegs) - { - easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; - } - if (((sib >> 3) & 7) != 4) - cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); - } - else - { - cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; - if (cpu_mod) - { - if (cpu_rm == 5 && !cpu_state.ssegs) - { - easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; - } - if (cpu_mod == 1) - { - cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); - cpu_state.pc++; - } - else - { - cpu_state.eaaddr += getlong(); - } - } - else if (cpu_rm == 5) - { - cpu_state.eaaddr = getlong(); - } - } if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; @@ -96,33 +38,6 @@ static inline void fetch_ea_16_long(uint32_t rmdat) eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; ea_rseg = cpu_state.ea_seg->seg; - if (!cpu_mod && cpu_rm == 6) - { - cpu_state.eaaddr = getword(); - } - else - { - switch (cpu_mod) - { - case 0: - cpu_state.eaaddr = 0; - break; - case 1: - cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; - break; - case 2: - cpu_state.eaaddr = getword(); - break; - } - cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); - if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) - { - easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; - } - cpu_state.eaaddr &= 0xFFFF; - } if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; @@ -133,8 +48,8 @@ static inline void fetch_ea_16_long(uint32_t rmdat) } } -#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 1; } -#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 1 +#define fetch_ea_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat); +#define fetch_ea_32(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_32_long(rmdat); #define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, read_ls, writes, write_ls, ea32) diff --git a/src/codegen.c b/src/codegen.c index 238f4f6..db29524 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -9,6 +9,8 @@ #include "codegen_backend.h" #include "codegen_ir.h" +int has_ea; + codeblock_t *codeblock; codeblock_t **codeblock_hash; @@ -38,8 +40,211 @@ void codegen_generate_reset() last_op_ssegs = -1; last_op_ea_seg = NULL; last_op_32 = -1; + has_ea = 0; } +static x86seg *codegen_generate_ea_16_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ +// pclog("codegen - mod=%i rm=%i reg=%i fetchdat=%08x\n", cpu_mod, cpu_rm, cpu_reg, fetchdat); + if (!cpu_mod && cpu_rm == 6) + { + uint16_t addr = (fetchdat >> 8) & 0xffff; + uop_MOV_IMM(ir, IREG_eaaddr, addr); + (*op_pc) += 2; + } + else + { + int base_reg, index_reg, offset; + + switch (cpu_rm) + { + case 0: case 1: case 7: + base_reg = IREG_EBX; + break; + case 2: case 3: case 6: + base_reg = IREG_EBP; + break; + case 4: + base_reg = IREG_ESI; + break; + case 5: + base_reg = IREG_EDI; + break; + } + uop_MOV(ir, IREG_eaaddr, base_reg); + + if (!(cpu_rm & 4)) + { + if (!(cpu_rm & 1)) + index_reg = IREG_ESI; + else + index_reg = IREG_EDI; + + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, index_reg); + } + + switch (cpu_mod) + { + case 1: + offset = (int)(int8_t)((fetchdat >> 8) & 0xff); + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset); + (*op_pc)++; + break; + case 2: + offset = (fetchdat >> 8) & 0xffff; + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset); + (*op_pc) += 2; + break; + } + + uop_AND_IMM(ir, IREG_eaaddr, IREG_eaaddr, 0xffff); + + if (mod1seg[cpu_rm] == &ss && !op_ssegs) + { + op_ea_seg = &_ss; + } + } + + return op_ea_seg; +} + +static x86seg *codegen_generate_ea_32_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + uint32_t new_eaaddr; + + if (cpu_rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (cpu_mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + (*op_pc) += 4; + } + else + { + uop_MOV(ir, IREG_eaaddr, sib & 7); + } + break; + case 1: + new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7); + (*op_pc) += 4; + break; + } +// if (stack_offset && (sib & 7) == 4 && (cpu_mod || (sib & 7) != 5)) /*ESP*/ +// { +// addbyte(0x05); +// addlong(stack_offset); +// } + if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7); + break; + case 1: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 1); + break; + case 2: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 2); + break; + case 3: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 3); + break; + } + } + } + else + { + if (!cpu_mod && cpu_rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + uop_MOV(ir, IREG_eaaddr, cpu_rm); + if (cpu_mod) + { + if (cpu_rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (cpu_mod == 1) + { + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, (uint32_t)(int8_t)(fetchdat >> 8)); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, new_eaaddr); + (*op_pc) += 4; + } + } + } + return op_ea_seg; +} + +static uint8_t opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +static uint8_t opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) { codeblock_t *block = &codeblock[block_current]; @@ -52,6 +257,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t x86seg *op_ea_seg = &_ds; int op_ssegs = 0; int over = 0; + int test_modrm = 1; op_ea_seg = &_ds; @@ -127,14 +333,44 @@ generate_call: //pclog("%04x:%08x : %02x\n", CS, new_pc, opcode); op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + if (!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode])) + { + //int stack_offset = 0; + +// if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ +// stack_offset = (op_32 & 0x100) ? 4 : 2; + + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + uop_MOV_IMM(ir, IREG_rm_mod_reg, cpu_rm | (cpu_mod << 8) | (cpu_reg << 16)); + +// op_pc += pc_off; + if (cpu_mod != 3 && !(op_32 & 0x200)) + { + op_ea_seg = codegen_generate_ea_16_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc); +// has_ea = 1; + } + if (cpu_mod != 3 && (op_32 & 0x200)) + { + op_ea_seg = codegen_generate_ea_32_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc); +// has_ea = 1; + } +// op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); +// op_pc -= pc_off; + } + + 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) + 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) + 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); @@ -150,4 +386,7 @@ generate_call: CPU_BLOCK_END(); codegen_endpc = (cs + cpu_state.pc) + 8; + +// if (has_ea) +// fatal("Has EA\n"); } diff --git a/src/codegen_backend_arm.c b/src/codegen_backend_arm.c index fa0b57c..41aeb71 100644 --- a/src/codegen_backend_arm.c +++ b/src/codegen_backend_arm.c @@ -20,8 +20,6 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = REG_R4, REG_R5, REG_R6, -// REG_X22, -// REG_X23 }; void codegen_backend_init() diff --git a/src/codegen_backend_arm64_defs.h b/src/codegen_backend_arm64_defs.h index 56deb25..1c4de84 100644 --- a/src/codegen_backend_arm64_defs.h +++ b/src/codegen_backend_arm64_defs.h @@ -29,6 +29,7 @@ #define REG_W28 28 #define REG_W29 29 #define REG_W30 30 +#define REG_WZR 31 #define REG_X0 0 #define REG_X1 1 @@ -61,6 +62,7 @@ #define REG_X28 28 #define REG_X29 29 #define REG_X30 30 +#define REG_XZR 31 #define REG_SP 31 diff --git a/src/codegen_backend_arm64_uops.c b/src/codegen_backend_arm64_uops.c index 2da9964..0845743 100644 --- a/src/codegen_backend_arm64_uops.c +++ b/src/codegen_backend_arm64_uops.c @@ -8,7 +8,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) { - *(uint32_t *)&block->data[block_pos] = val; + *(uint32_t *)&block->data[block_pos] = val; block_pos += 4; if (block_pos >= BLOCK_MAX) { @@ -21,6 +21,9 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define Rd(x) (x) #define Rn(x) ((x) << 5) #define Rt2(x) ((x) << 10) +#define Rm(x) ((x) << 16) + +#define shift_imm6(x) ((x) << 10) #define DATA_OFFSET_UP (1 << 23) #define DATA_OFFSET_DOWN (0 << 23) @@ -30,6 +33,8 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define COND_AL (0xe << COND_SHIFT) #define OPCODE_SHIFT 24 +#define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT) +#define OPCODE_AND_IMM (0x11 << OPCODE_SHIFT) #define OPCODE_CBNZ (0xb5 << OPCODE_SHIFT) #define OPCODE_LDR_LITERAL_W (0x18 << OPCODE_SHIFT) #define OPCODE_LDR_LITERAL_X (0x58 << OPCODE_SHIFT) @@ -37,20 +42,28 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_MOVK_W (0x0e5 << 23) #define OPCODE_MOVZ_W (0x0a5 << 23) +#define OPCODE_LDR_IMM_W (0x2e5 << 22) #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_ADD_LSL (0x058 << 21) +#define OPCODE_AND_LSL (0x050 << 21) +#define OPCODE_ORR_LSL (0x150 << 21) + #define OPCODE_BLR (0xd63f0000) #define OPCODE_NOP (0xd503201f) #define OPCODE_RET (0xd65f0000) +#define DATPROC_SHIFT(sh) (sh << 10) +#define DATPROC_IMM_SHIFT(sh) (sh << 22) #define MOV_WIDE_HW(hw) (hw << 21) #define IMM7_X(imm_data) (((imm_data >> 3) & 0x7f) << 15) -#define IMM16(imm_data) (imm_data << 5) +#define IMM12(imm_data) ((imm_data) << 10) +#define IMM16(imm_data) ((imm_data) << 5) #define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) @@ -112,7 +125,39 @@ static inline int imm_is_imm16(uint32_t imm_data) return 1; return 0; } +static inline int imm_is_imm12(uint32_t imm_data) +{ + if (!(imm_data & 0xfffff000) || !(imm_data & 0xff000fff)) + return 1; + return 0; +} +void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (!(imm_data & 0xff000000)) + { + if (imm_data & 0xfff) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + { + host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); +} void host_arm64_BLR(codeblock_t *block, int addr_reg) { @@ -134,6 +179,13 @@ void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, in codegen_addlong(block, OPCODE_LDP_POSTIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); } +void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_w(offset)) + fatal("host_arm64_LDR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); +} + void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offset) { int offset = (ARM_LITERAL_POOL_OFFSET + literal_offset) - block_pos; @@ -153,6 +205,11 @@ void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offs codegen_addlong(block, OPCODE_LDR_LITERAL_X | OFFSET19(offset) | Rt(dest_reg)); } +void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data) { int hw; @@ -237,6 +294,30 @@ void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data) } +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + host_arm64_ADD_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, 0); + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_ADD_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + host_arm64_ADD_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_AND_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; +} + static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) { host_arm64_call(block, uop->p); @@ -270,6 +351,12 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + host_arm64_MOV_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, 0); + + 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); @@ -319,10 +406,24 @@ 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_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, - [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM }; +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_32 - not in range\n"); +} + void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) diff --git a/src/codegen_backend_arm_defs.h b/src/codegen_backend_arm_defs.h index f6fe556..1fadfa1 100644 --- a/src/codegen_backend_arm_defs.h +++ b/src/codegen_backend_arm_defs.h @@ -23,6 +23,8 @@ #define REG_CPUSTATE REG_R10 #define REG_LITERAL REG_R11 +#define REG_TEMP REG_R3 + #define REG_MASK_R0 (1 << REG_R0) #define REG_MASK_R1 (1 << REG_R1) #define REG_MASK_R2 (1 << REG_R2) diff --git a/src/codegen_backend_arm_uops.c b/src/codegen_backend_arm_uops.c index 40d1409..a63e17a 100644 --- a/src/codegen_backend_arm_uops.c +++ b/src/codegen_backend_arm_uops.c @@ -30,6 +30,9 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_SHIFT 20 #define OPCODE_ADD_IMM (0x28 << OPCODE_SHIFT) +#define OPCODE_ADD_REG (0x08 << OPCODE_SHIFT) +#define OPCODE_AND_IMM (0x20 << OPCODE_SHIFT) +#define OPCODE_AND_REG (0x00 << OPCODE_SHIFT) #define OPCODE_B (0xa0 << OPCODE_SHIFT) #define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT) #define OPCODE_LDR_IMM (0x51 << OPCODE_SHIFT) @@ -45,6 +48,18 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define B_OFFSET(x) (((x) >> 2) & 0xffffff) +#define SHIFT_TYPE_SHIFT 5 +#define SHIFT_TYPE_LSL (0 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_LSR (1 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ASR (2 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ROR (3 << SHIFT_TYPE_SHIFT) + +#define SHIFT_TYPE_IMM (0 << 4) +#define SHIFT_TYPE_REG (1 << 4) + +#define SHIFT_IMM_SHIFT 7 +#define SHIFT_LSL_IMM(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) + static int literal_offset = 0; void codegen_reset_literal_pool(codeblock_t *block) { @@ -114,14 +129,49 @@ static inline int in_range(void *addr, void *base) return 1; } +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) { uint32_t arm_imm; - if (!get_arm_imm(imm, &arm_imm)) - fatal("host_arm_ADD_IMM !check_arm_imm %08x\n", imm); + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_ADD_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} - codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, REG_TEMP, REG_LITERAL, offset); + host_arm_AND_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); } void host_arm_BLX(codeblock_t *block, int addr_reg) @@ -153,15 +203,20 @@ void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm) { uint32_t arm_imm; - if (!get_arm_imm(imm, &arm_imm)) - fatal("host_arm_MOV_IMM !check_arm_imm %08x\n", imm); - - codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm); + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm); + } + else + { + int offset = add_literal(block, imm); + host_arm_LDR_IMM(block, dst_reg, REG_LITERAL, offset); + } } -void host_arm_MOV_REG(codeblock_t *block, int dst_reg, int src_reg) +void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) { - codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg)); + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); } void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) @@ -204,7 +259,31 @@ void host_arm_call(codeblock_t *block, void *dst_addr) void host_arm_nop(codeblock_t *block) { - host_arm_MOV_REG(block, REG_R0, REG_R0); + host_arm_MOV_REG_LSL(block, REG_R0, REG_R0, 0); +} + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + host_arm_ADD_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, 0); + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_ADD_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + host_arm_ADD_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_AND_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; } static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) @@ -269,6 +348,13 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, 0); + + return 0; +} + static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) { uint32_t arm_imm; @@ -332,10 +418,24 @@ 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_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, - [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM }; +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + if (in_range(p, &cpu_state)) + host_arm_LDR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_32 - not in range\n"); +} + void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { if (in_range(p, &cpu_state)) diff --git a/src/codegen_backend_x86-64_uops.c b/src/codegen_backend_x86-64_uops.c index e5c231a..d0b3e00 100644 --- a/src/codegen_backend_x86-64_uops.c +++ b/src/codegen_backend_x86-64_uops.c @@ -87,6 +87,13 @@ static inline void codegen_addquad(codeblock_t *block, uint64_t val) } } +static int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} + static inline void call(codeblock_t *block, uintptr_t func) { uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; @@ -104,6 +111,62 @@ static inline void call(codeblock_t *block, uintptr_t func) } } +static void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + { + codegen_addbyte3(block, 0x83, 0xc0 | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else + { + if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } + } +} + +static void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + { + codegen_addbyte3(block, 0x83, 0xe0 | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else + { + if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xe0 | (dst_reg & 7)); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } + } +} + +static void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a || (dst_reg & 8) || (src_reg_b & 8)) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x01, 0xc0 | (dst_reg & 7) | (src_reg_b & 7)); /*ADD dst_reg, src_reg_b*/ +} + static void host_x86_CALL(codeblock_t *block, void *p) { call(block, (uintptr_t)p); @@ -115,13 +178,22 @@ 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_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_LEA_REG_REG_SHIFT - bad reg\n"); + + codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b * (1 << shift)]*/ + (shift << 6) | ((src_reg_b & 7) << 3) | (src_reg_a & 7)); +} + static void host_x86_MOV8_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, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/ + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/ codegen_addbyte(block, imm_data); } else @@ -139,7 +211,7 @@ static void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_dat if (offset >= -128 && offset < 127) { - codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ codegen_addlong(block, imm_data); } else @@ -156,16 +228,19 @@ 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 (src_reg & 8) + fatal("host_x86_MOV8_ABS_REG - bad reg\n"); + if (offset >= -128 && offset < 127) { - codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/ + codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], 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_addbyte(block, 0x05 | ((src_reg & 7) << 3)); codegen_addlong(block, (uint32_t)(uintptr_t)p); } } @@ -173,16 +248,19 @@ 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 (src_reg & 8) + fatal("host_x86_MOV32_ABS_REG - bad reg\n"); + if (offset >= -128 && offset < 127) { - codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + codegen_addbyte3(block, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], 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_addbyte(block, 0x05 | ((src_reg & 7) << 3)); codegen_addlong(block, (uint32_t)(uintptr_t)p); } } @@ -190,26 +268,47 @@ 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 (src_reg & 8) + fatal("host_x86_MOV64_ABS_REG - bad reg\n"); + if (offset >= -128 && offset < 127) { - codegen_addbyte4(block, 0x48, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], 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_addbyte4(block, 0x48, 0x89, 0x04 | ((src_reg & 7) << 3), 0x25); /*MOV [p], src_reg*/ codegen_addlong(block, (uint32_t)(uintptr_t)p); } } +static void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + if (dst_reg & 8) + fatal("host_x86_MOV32_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else + { + fatal("host_x86_MOV32_REG_ABS - out of range\n"); + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((dst_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} static void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data) { if (reg & 8) fatal("host_x86_MOV32_REG_IMM reg & 8\n"); - codegen_addbyte(block, 0xb8 | reg); /*MOV reg, imm_data*/ + codegen_addbyte(block, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ codegen_addlong(block, imm_data); } @@ -217,10 +316,17 @@ static void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_dat { if (reg & 8) fatal("host_x86_MOV64_REG_IMM reg & 8\n"); - codegen_addbyte2(block, 0x48, 0xb8 | reg); /*MOVQ reg, imm_data*/ + codegen_addbyte2(block, 0x48, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ codegen_addquad(block, imm_data); } +static void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV32_REG_REG - bad reg\n"); + + codegen_addbyte2(block, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) { @@ -244,9 +350,42 @@ static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_ #define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) -static void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +static void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg) { - codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_TEST32_REG - bad reg\n"); + codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_reg, src_reg)); /*TEST dst_host_reg, src_host_reg*/ +} + + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_ADD32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + if (!uop->imm_data) + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + else if (uop->imm_data < 4) + host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + else + fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data); + + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_AND32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; } static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) @@ -287,6 +426,11 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real); + 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); @@ -325,10 +469,21 @@ 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_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, - [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM }; +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV32_REG_ABS(block, host_reg, p); +} + void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { host_x86_MOV8_ABS_REG(block, p, host_reg); diff --git a/src/codegen_backend_x86_uops.c b/src/codegen_backend_x86_uops.c index c19df3e..b437185 100644 --- a/src/codegen_backend_x86_uops.c +++ b/src/codegen_backend_x86_uops.c @@ -86,6 +86,70 @@ static inline void codegen_addquad(codeblock_t *block, uint64_t val) CPU_BLOCK_END(); } } + +static int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} + +static void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + { + codegen_addbyte3(block, 0x83, 0xc0 | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else + { + if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xc0 | dst_reg); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } + } +} + +static void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data) +{ + if (dst_reg != src_reg) + fatal("host_x86_AND32_REG_IMM - dst_reg != src_reg\n"); + + if (is_imm8(imm_data)) + { + codegen_addbyte3(block, 0x83, 0xe0 | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else + { + if (dst_reg == REG_EAX) + { + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_addbyte2(block, 0x81, 0xe0 | dst_reg); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } + } +} + +static void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if (dst_reg != src_reg_a) + fatal("host_x86_ADD32_REG_IMM - dst_reg != src_reg_a\n"); + + codegen_addbyte2(block, 0x01, 0xc0 | dst_reg | src_reg_b); /*ADD dst_reg, src_reg_b*/ +} + static void host_x86_CALL(codeblock_t *block, void *p) { codegen_addbyte(block, 0xe8); /*CALL*/ @@ -98,6 +162,11 @@ 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_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (shift << 6) | (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b * (1 << shift)]*/ +} + static void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); @@ -162,6 +231,21 @@ static void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) } } +static void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte3(block, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_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) @@ -175,6 +259,11 @@ static void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm } } +static void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte2(block, 0x89, 0xc0 | dst_reg | (src_reg << 3)); +} + static void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) { if (!offset) @@ -207,6 +296,36 @@ static void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_ho pclog(" %04x:%04x : %08x %08x %08x %08x\n", CS, cpu_state.pc, AX, BX, CX, DX); }*/ +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_ADD32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + if (!uop->imm_data) + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + else if (uop->imm_data < 4) + host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + else + fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data); + + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_AND32_REG_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); + return 0; +} + static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) { host_x86_CALL(block, uop->p); @@ -238,6 +357,11 @@ static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real); + 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); @@ -272,10 +396,21 @@ 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_MOV & UOP_MASK] = codegen_MOV, [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, - [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM }; +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV32_REG_ABS(block, host_reg, p); +} + void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { host_x86_MOV8_ABS_REG(block, p, host_reg); diff --git a/src/codegen_ir.c b/src/codegen_ir.c index 692b9b4..9099aea 100644 --- a/src/codegen_ir.c +++ b/src/codegen_ir.c @@ -4,12 +4,13 @@ #include "codegen_ir.h" #include "codegen_reg.h" +extern int has_ea; static ir_data_t ir_block; ir_data_t *codegen_ir_init() { ir_block.wr_pos = 0; - //pclog("codegen_ir_init\n"); +// pclog("codegen_ir_init %04x:%04x\n", CS,cpu_state.pc); return &ir_block; } @@ -24,10 +25,19 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) { uop_t *uop = &ir->uops[c]; - //pclog("uOP %i : %08x\n", c, uop->type); +// pclog("uOP %i : %08x\n", c, uop->type); if (uop->type & UOP_TYPE_PARAMS_REGS) { + codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b); + if (uop->src_reg_a.reg != IREG_INVALID) + { + uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a); + } + if (uop->src_reg_b.reg != IREG_INVALID) + { + uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b); + } if (uop->dest_reg_a.reg != IREG_INVALID) { uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a); @@ -42,5 +52,6 @@ void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) codegen_backend_epilogue(block); - //fatal("IR compilation complete\n"); +// if (has_ea) +// fatal("IR compilation complete\n"); } diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h index 5bb310a..d64e926 100644 --- a/src/codegen_ir_defs.h +++ b/src/codegen_ir_defs.h @@ -32,8 +32,13 @@ #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_MOV (UOP_TYPE_PARAMS_REGS | 0x22) +#define UOP_ADD (UOP_TYPE_PARAMS_REGS | 0x30) +#define UOP_ADD_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x31) +#define UOP_AND_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x32) +#define UOP_ADD_LSHIFT (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x33) -#define UOP_MAX 0x22 +#define UOP_MAX 0x34 #define UOP_MASK 0xffff @@ -43,10 +48,10 @@ typedef struct uop_t 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; + ir_host_reg_t src_reg_a_real, src_reg_b_real; } uop_t; #define UOP_NR_MAX 4096 @@ -69,7 +74,7 @@ static inline uop_t *uop_alloc(ir_data_t *ir) 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; +// uop->src_reg_c = invalid_ir_reg; return uop; } @@ -100,6 +105,46 @@ static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int uop->p = p; } +static inline void uop_gen_reg_dst_src1(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg); +} + +static inline void uop_gen_reg_dst_src2(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->dest_reg_a = codegen_reg_write(dest_reg); +} + +static inline void uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg); + uop->imm_data = imm; +} + static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) { uop_t *uop = uop_alloc(ir); @@ -129,15 +174,23 @@ static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p #define uop_LOAD_FUNC_ARG_IMM(ir, arg, imm) uop_gen_imm(UOP_LOAD_FUNC_ARG_0_IMM + arg, ir, imm) +#define uop_ADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_ADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_ADD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ADD_IMM, ir, dst_reg, src_reg, imm) +#define uop_ADD_LSHIFT(ir, dst_reg, src_reg_a, src_reg_b, shift) uop_gen_reg_dst_src2_imm(UOP_ADD_LSHIFT, ir, dst_reg, src_reg_a, src_reg_b, shift) +#define uop_AND_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_AND_IMM, ir, dst_reg, src_reg, imm) + #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(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOV, ir, dst_reg, src_reg) #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_read_32(codeblock_t *block, int host_reg, void *p); + 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); diff --git a/src/codegen_reg.c b/src/codegen_reg.c index f9e3e36..c2ca44d 100644 --- a/src/codegen_reg.c +++ b/src/codegen_reg.c @@ -10,6 +10,9 @@ uint8_t reg_version_refcount[IREG_COUNT][256]; ir_reg_t invalid_ir_reg = {IREG_INVALID}; ir_reg_t host_regs[CODEGEN_HOST_REGS]; +static uint8_t host_reg_dirty[CODEGEN_HOST_REGS]; + +static uint8_t host_regs_locked; enum { @@ -48,6 +51,8 @@ struct [IREG_op32] = {REG_DWORD, &cpu_state.op32}, [IREG_ssegs] = {REG_BYTE, &cpu_state.ssegs}, + + [IREG_rm_mod_reg] = {REG_DWORD, &cpu_state.rm_data.rm_mod_reg_data}, /*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 @@ -76,6 +81,21 @@ static inline int ir_reg_is_invalid(ir_reg_t ir_reg) return (ir_reg.reg == IREG_INVALID); } +static void codegen_reg_load(codeblock_t *block, int c, ir_reg_t ir_reg) +{ + switch (ireg_data[ir_reg.reg].native_size) + { + case REG_DWORD: + codegen_direct_read_32(block, codegen_host_reg_list[c], ireg_data[ir_reg.reg].p); + break; + + default: + fatal("codegen_reg_load - native_size=%i\n", ireg_data[ir_reg.reg].native_size); + } + + host_regs[c] = ir_reg; +} + static void codegen_reg_writeback(codeblock_t *block, int c) { int ir_reg = host_regs[c].reg; @@ -101,27 +121,135 @@ static void codegen_reg_writeback(codeblock_t *block, int c) host_regs[c] = invalid_ir_reg; } +void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b) +{ + int c; + int dest_reference = 0; + + host_regs_locked = 0; + +/* pclog("alloc_register: dst=%i.%i src_a=%i.%i src_b=%i.%i\n", dest_reg_a.reg, dest_reg_a.version, + src_reg_a.reg, src_reg_a.version, + src_reg_b.reg, src_reg_b.version);*/ + + if (!ir_reg_is_invalid(dest_reg_a)) + { + if (!ir_reg_is_invalid(src_reg_a) && src_reg_a.reg == dest_reg_a.reg && src_reg_a.version == dest_reg_a.version-1) + dest_reference++; + if (!ir_reg_is_invalid(src_reg_b) && src_reg_b.reg == dest_reg_a.reg && src_reg_b.version == dest_reg_a.version-1) + dest_reference++; + } + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + if (!ir_reg_is_invalid(src_reg_a) && host_regs[c].reg == src_reg_a.reg) + { + if (host_regs[c].version != src_reg_a.version) + fatal("codegen_reg_alloc_register - host_regs[c].version != src_reg_a.version\n"); + host_regs_locked |= (1 << c); + } + if (!ir_reg_is_invalid(src_reg_b) && host_regs[c].reg == src_reg_b.reg) + { + if (host_regs[c].version != src_reg_b.version) + fatal("codegen_reg_alloc_register - host_regs[c].version != src_reg_b.version\n"); + host_regs_locked |= (1 << c); + } + if (!ir_reg_is_invalid(dest_reg_a) && host_regs[c].reg == dest_reg_a.reg) + { + if (host_regs[c].version == dest_reg_a.version || (host_regs[c].version == (dest_reg_a.version-1) && reg_version_refcount[host_regs[c].reg][host_regs[c].version] == dest_reference)) + host_regs_locked |= (1 << c); + else + fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", host_regs[c].version, dest_reg_a.version, dest_reference); + } + } +} + +ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg) +{ + int c; + + /*Search for required register*/ + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + if (!ir_reg_is_invalid(host_regs[c]) && host_regs[c].reg == ir_reg.reg && host_regs[c].version == ir_reg.version) + break; + + if (!ir_reg_is_invalid(host_regs[c]) && host_regs[c].reg == ir_reg.reg && reg_version_refcount[host_regs[c].reg][host_regs[c].version]) + fatal("codegen_reg_alloc_read_reg - version mismatch!\n"); + } + + if (c == CODEGEN_HOST_REGS) + { + /*No unused registers. Search for an unlocked register*/ + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + if (!(host_regs_locked & (1 << c))) + break; + } + if (c == CODEGEN_HOST_REGS) + fatal("codegen_reg_alloc_read_reg - out of registers\n"); + if (host_reg_dirty[c]) + codegen_reg_writeback(block, c); + codegen_reg_load(block, c, ir_reg); + host_regs_locked |= (1 << c); +// fatal("codegen_reg_alloc_read_reg - read %i.%i to %i\n", ir_reg.reg,ir_reg.version, c); +// codegen_reg_writeback(block, c); + } + + reg_version_refcount[host_regs[c].reg][host_regs[c].version]--; + if (reg_version_refcount[host_regs[c].reg][host_regs[c].version] < 0) + fatal("codegen_reg_alloc_read_reg - refcount < 0\n"); + + host_reg_dirty[c] = 0; +// pclog(" codegen_reg_alloc_read_reg: %i.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c]); + return codegen_host_reg_list[c]; +} + ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) { int c; - /*Search for unused registers*/ + /*Search for previous version in host register*/ for (c = 0; c < CODEGEN_HOST_REGS; c++) { - if (ir_reg_is_invalid(host_regs[c])) - break; + if (!ir_reg_is_invalid(host_regs[c]) && host_regs[c].reg == ir_reg.reg) + { + if (host_regs[c].version == ir_reg.version-1) + { + if (reg_version_refcount[host_regs[c].reg][host_regs[c].version] != 0) + fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); + break; + } + } } if (c == CODEGEN_HOST_REGS) { - c = 0; - codegen_reg_writeback(block, c); -// fatal("codegen_reg_alloc_write_reg - out of registers\n"); + /*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) + { + /*No unused registers. Search for an unlocked register*/ + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + if (!(host_regs_locked & (1 << c))) + break; + } + if (c == CODEGEN_HOST_REGS) + fatal("codegen_reg_alloc_write_reg - out of registers\n"); + if (host_reg_dirty[c]) + codegen_reg_writeback(block, c); + } } host_regs[c].reg = ir_reg.reg; host_regs[c].version = ir_reg.version; - + host_reg_dirty[c] = 1; +// pclog(" codegen_reg_alloc_write_reg: %i.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c]); return codegen_host_reg_list[c]; } diff --git a/src/codegen_reg.h b/src/codegen_reg.h index 1b8bd06..d1d81a2 100644 --- a/src/codegen_reg.h +++ b/src/codegen_reg.h @@ -29,6 +29,8 @@ enum IREG_ea_seg = 15, IREG_op32 = 16, IREG_ssegs = 17, + + IREG_rm_mod_reg = 18, /*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 @@ -94,6 +96,10 @@ struct ir_data_t; void codegen_reg_reset(); void codegen_reg_flush(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_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg); ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg); #endif