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:
parent
03fe25d818
commit
ee3f9210dc
23 changed files with 776 additions and 76 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
105
src/codegen.c
105
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -325,4 +325,5 @@ extern int codegen_reg_loaded[8];
|
|||
|
||||
extern int codegen_in_recompile;
|
||||
|
||||
void codegen_generate_reset();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include "codegen_backend_arm_defs.h"
|
||||
|
||||
#define BLOCK_SIZE 0x1000
|
||||
#define BLOCK_MASK 0x0fff
|
||||
#define BLOCK_START 32
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include "codegen_backend_arm64_defs.h"
|
||||
|
||||
#define BLOCK_SIZE 0x1000
|
||||
#define BLOCK_MASK 0x0fff
|
||||
#define BLOCK_START 64
|
||||
|
|
|
|||
|
|
@ -70,3 +70,5 @@
|
|||
#define REG_ARG3 REG_X3
|
||||
|
||||
#define REG_CPUSTATE REG_X29
|
||||
|
||||
#define CODEGEN_HOST_REGS 5
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include "codegen_backend_x86_defs.h"
|
||||
|
||||
#define BLOCK_SIZE 0x4000
|
||||
#define BLOCK_MASK 0x3fff
|
||||
#define BLOCK_START 0
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
139
src/codegen_reg.c
Normal 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
99
src/codegen_reg.h
Normal 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
|
||||
Loading…
Reference in a new issue