Implemented basic register allocation.

Mainly handles 'virtual' registers at the moment (eg current and last PC values, segment override status, etc).
This commit is contained in:
SarahW 2018-06-23 19:04:36 +01:00
commit ee3f9210dc
23 changed files with 776 additions and 76 deletions

View file

@ -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 \

View file

@ -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;
}

View file

@ -325,4 +325,5 @@ extern int codegen_reg_loaded[8];
extern int codegen_in_recompile;
void codegen_generate_reset();
#endif

View file

@ -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();
}

View file

@ -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];

View file

@ -15,6 +15,15 @@
#include <windows.h>
#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;

View file

@ -1,3 +1,5 @@
#include "codegen_backend_arm_defs.h"
#define BLOCK_SIZE 0x1000
#define BLOCK_MASK 0x0fff
#define BLOCK_START 32

View file

@ -15,6 +15,15 @@
#include <windows.h>
#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;

View file

@ -1,3 +1,5 @@
#include "codegen_backend_arm64_defs.h"
#define BLOCK_SIZE 0x1000
#define BLOCK_MASK 0x0fff
#define BLOCK_START 64

View file

@ -70,3 +70,5 @@
#define REG_ARG3 REG_X3
#define REG_CPUSTATE REG_X29
#define CODEGEN_HOST_REGS 5

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -13,6 +13,13 @@
#include <windows.h>
#endif
int codegen_host_reg_list[CODEGEN_HOST_REGS] =
{
REG_EAX,
REG_EBX,
REG_EDX
};
static void *mem_abrt_rout;
void codegen_backend_init()

View file

@ -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

View file

@ -13,6 +13,13 @@
#include <windows.h>
#endif
int codegen_host_reg_list[CODEGEN_HOST_REGS] =
{
REG_EAX,
REG_EBX,
REG_EDX
};
static void *mem_abrt_rout;
void codegen_backend_init()

View file

@ -1,3 +1,5 @@
#include "codegen_backend_x86_defs.h"
#define BLOCK_SIZE 0x4000
#define BLOCK_MASK 0x3fff
#define BLOCK_START 0

View file

@ -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

View file

@ -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

View file

@ -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");
}

View file

@ -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

139
src/codegen_reg.c Normal file
View file

@ -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);
}
}
}

99
src/codegen_reg.h Normal file
View file

@ -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