From 78996b3e5c0175a48c51398552d0151eeedefea2 Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 7 Oct 2018 22:02:31 +0100 Subject: [PATCH] Added recompiled register versions of FADD, FDIV, FDIVR, FMUL, FSUB and FSUBR. --- src/codegen.c | 4 +- src/codegen_backend.h | 7 +- src/codegen_backend_arm.c | 25 +- src/codegen_backend_arm64.c | 26 ++- src/codegen_backend_arm64_defs.h | 37 ++- src/codegen_backend_arm64_ops.c | 67 ++++++ src/codegen_backend_arm64_ops.h | 13 ++ src/codegen_backend_arm64_uops.c | 127 +++++++++++ src/codegen_backend_arm_defs.h | 18 ++ src/codegen_backend_arm_ops.c | 35 +++ src/codegen_backend_arm_ops.h | 7 + src/codegen_backend_arm_uops.c | 121 ++++++++++ src/codegen_backend_x86-64.c | 24 +- src/codegen_backend_x86-64.h | 2 + src/codegen_backend_x86-64_defs.h | 22 ++ src/codegen_backend_x86-64_ops.c | 115 ++++++++++ src/codegen_backend_x86-64_ops.h | 17 ++ src/codegen_backend_x86-64_uops.c | 134 +++++++++++ src/codegen_backend_x86.c | 34 ++- src/codegen_backend_x86_defs.h | 12 + src/codegen_backend_x86_ops.c | 95 ++++++++ src/codegen_backend_x86_ops.h | 17 ++ src/codegen_backend_x86_uops.c | 130 +++++++++++ src/codegen_ir_defs.h | 36 ++- src/codegen_ops.c | 95 ++++++++ src/codegen_ops.h | 8 +- src/codegen_ops_fpu_arith.c | 134 +++++++++++ src/codegen_ops_fpu_arith.h | 12 + src/codegen_reg.c | 364 ++++++++++++++++++++---------- src/codegen_reg.h | 46 +++- src/ibm.h | 16 +- 31 files changed, 1638 insertions(+), 162 deletions(-) create mode 100644 src/codegen_ops_fpu_arith.c create mode 100644 src/codegen_ops_fpu_arith.h diff --git a/src/codegen.c b/src/codegen.c index ee782d1..409221f 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -360,7 +360,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t case 0xd8: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; - recomp_op_table = NULL;//recomp_opcodes_d8; + recomp_op_table = recomp_opcodes_d8; opcode_shift = 3; opcode_mask = 0x1f; over = 1; @@ -397,7 +397,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0xdc: op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; - recomp_op_table = NULL;//recomp_opcodes_dc; + recomp_op_table = recomp_opcodes_dc; opcode_shift = 3; opcode_mask = 0x1f; over = 1; diff --git a/src/codegen_backend.h b/src/codegen_backend.h index 0f73290..df6fcea 100644 --- a/src/codegen_backend.h +++ b/src/codegen_backend.h @@ -1,9 +1,9 @@ //#ifdef __amd64__ //#include "codegen_x86-64.h" -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 -#include "codegen_backend_x86.h" -#elif defined __amd64__ +#if defined __amd64__ #include "codegen_backend_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 +#include "codegen_backend_x86.h" #elif defined __ARM_EABI__ #include "codegen_backend_arm.h" #elif defined __aarch64__ @@ -65,3 +65,4 @@ typedef int (*uOpFn)(codeblock_t *codeblock, struct uop_t *uop); extern const uOpFn uop_handlers[]; extern int codegen_host_reg_list[CODEGEN_HOST_REGS]; +extern int codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS]; diff --git a/src/codegen_backend_arm.c b/src/codegen_backend_arm.c index fb2d6f2..3b9c5fe 100644 --- a/src/codegen_backend_arm.c +++ b/src/codegen_backend_arm.c @@ -6,6 +6,7 @@ #include "codegen_backend.h" #include "codegen_backend_arm_defs.h" #include "codegen_backend_arm_ops.h" +#include "codegen_reg.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -35,6 +36,18 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = REG_R11, }; +int codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + REG_D8, + REG_D9, + REG_D10, + REG_D11, + REG_D12, + REG_D13, + REG_D14, + REG_D15 +}; + static void build_load_routine(codeblock_t *block, int size) { uint32_t *branch_offset; @@ -220,7 +233,7 @@ void codegen_backend_prologue(codeblock_t *block) host_arm_nop(block); block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ - host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x20); + host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); host_arm_LDMIA_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_PC); while (block_pos != BLOCK_START) host_arm_nop(block); @@ -228,13 +241,19 @@ void codegen_backend_prologue(codeblock_t *block) /*Entry code*/ host_arm_STMDB_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_LR); - host_arm_SUB_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x20); + host_arm_SUB_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); host_arm_MOV_IMM(block, REG_CPUSTATE, (uint32_t)&cpu_state); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm_SUB_IMM(block, REG_TEMP, REG_TEMP, block->TOP); + host_arm_STR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + } } void codegen_backend_epilogue(codeblock_t *block) { - host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x20); + host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); host_arm_LDMIA_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_PC); if (block_pos > ARM_LITERAL_POOL_OFFSET) diff --git a/src/codegen_backend_arm64.c b/src/codegen_backend_arm64.c index 4ae98f0..57eb10b 100644 --- a/src/codegen_backend_arm64.c +++ b/src/codegen_backend_arm64.c @@ -6,6 +6,7 @@ #include "codegen_backend.h" #include "codegen_backend_arm64_defs.h" #include "codegen_backend_arm64_ops.h" +#include "codegen_reg.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -38,6 +39,18 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = REG_X28 }; +int codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + REG_V8, + REG_V9, + REG_V10, + REG_V11, + REG_V12, + REG_V13, + REG_V14, + REG_V15 +}; + static void build_load_routine(codeblock_t *block, int size) { uint32_t *branch_offset; @@ -237,7 +250,7 @@ void codegen_backend_prologue(codeblock_t *block) host_arm64_NOP(block); block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ - host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_SP, 48); + host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_SP, 64); host_arm64_LDP_POSTIDX_X(block, REG_X21, REG_X22, REG_SP, 16); host_arm64_LDP_POSTIDX_X(block, REG_X23, REG_X24, REG_SP, 16); host_arm64_LDP_POSTIDX_X(block, REG_X25, REG_X26, REG_SP, 16); @@ -255,15 +268,22 @@ void codegen_backend_prologue(codeblock_t *block) host_arm64_STP_PREIDX_X(block, REG_X25, REG_X26, REG_SP, -16); host_arm64_STP_PREIDX_X(block, REG_X23, REG_X24, REG_SP, -16); host_arm64_STP_PREIDX_X(block, REG_X21, REG_X22, REG_SP, -16); - host_arm64_STP_PREIDX_X(block, REG_X19, REG_X20, REG_SP, -48); + host_arm64_STP_PREIDX_X(block, REG_X19, REG_X20, REG_SP, -64); offset = add_literal_q(block, (uintptr_t)&cpu_state); host_arm64_LDR_LITERAL_X(block, REG_CPUSTATE, offset); + + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm64_SUB_IMM(block, REG_TEMP, REG_TEMP, block->TOP); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_SP, IREG_TOP_diff_stack_offset); + } } void codegen_backend_epilogue(codeblock_t *block) { - host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_SP, 48); + host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_SP, 64); host_arm64_LDP_POSTIDX_X(block, REG_X21, REG_X22, REG_SP, 16); host_arm64_LDP_POSTIDX_X(block, REG_X23, REG_X24, REG_SP, 16); host_arm64_LDP_POSTIDX_X(block, REG_X25, REG_X26, REG_SP, 16); diff --git a/src/codegen_backend_arm64_defs.h b/src/codegen_backend_arm64_defs.h index c818d89..207fd80 100644 --- a/src/codegen_backend_arm64_defs.h +++ b/src/codegen_backend_arm64_defs.h @@ -64,6 +64,39 @@ #define REG_X30 30 #define REG_XZR 31 +#define REG_V0 0 +#define REG_V1 1 +#define REG_V2 2 +#define REG_V3 3 +#define REG_V4 4 +#define REG_V5 5 +#define REG_V6 6 +#define REG_V7 7 +#define REG_V8 8 +#define REG_V9 9 +#define REG_V10 10 +#define REG_V11 11 +#define REG_V12 12 +#define REG_V13 13 +#define REG_V14 14 +#define REG_V15 15 +#define REG_V16 16 +#define REG_V17 17 +#define REG_V18 18 +#define REG_V19 19 +#define REG_V20 20 +#define REG_V21 21 +#define REG_V22 22 +#define REG_V23 23 +#define REG_V24 24 +#define REG_V25 25 +#define REG_V26 26 +#define REG_V27 27 +#define REG_V28 28 +#define REG_V29 29 +#define REG_V30 30 +#define REG_V31 31 + #define REG_SP 31 #define REG_ARG0 REG_X0 @@ -73,9 +106,11 @@ #define REG_CPUSTATE REG_X29 -#define REG_TEMP REG_X7 +#define REG_TEMP REG_X7 +#define REG_TEMP2 REG_X6 #define CODEGEN_HOST_REGS 10 +#define CODEGEN_HOST_FP_REGS 8 extern void *codegen_mem_load_byte; extern void *codegen_mem_load_word; diff --git a/src/codegen_backend_arm64_ops.c b/src/codegen_backend_arm64_ops.c index cab45ac..a7a3cd6 100644 --- a/src/codegen_backend_arm64_ops.c +++ b/src/codegen_backend_arm64_ops.c @@ -48,6 +48,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_SHIFT 24 #define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT) #define OPCODE_ADDX_IMM (0x91 << OPCODE_SHIFT) +#define OPCODE_B (0x14 << OPCODE_SHIFT) #define OPCODE_BCOND (0x54 << OPCODE_SHIFT) #define OPCODE_CBNZ (0xb5 << OPCODE_SHIFT) #define OPCODE_CMN_IMM (0x31 << OPCODE_SHIFT) @@ -68,6 +69,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_BFI (0x0cc << 22) #define OPCODE_LDR_IMM_W (0x2e5 << 22) +#define OPCODE_LDR_IMM_F64 (0x3f5 << 22) #define OPCODE_LDRB_IMM_W (0x0e5 << 22) #define OPCODE_LDRH_IMM (0x1e5 << 22) #define OPCODE_LDP_POSTIDX_X (0x2a3 << 22) @@ -75,6 +77,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_STP_PREIDX_X (0x2a6 << 22) #define OPCODE_STR_IMM_W (0x2e4 << 22) #define OPCODE_STR_IMM_Q (0x3e4 << 22) +#define OPCODE_STR_IMM_F64 (0x3f4 << 22) #define OPCODE_STRB_IMM (0x0e4 << 22) #define OPCODE_STRH_IMM (0x1e4 << 22) #define OPCODE_UBFX (0x14c << 22) @@ -99,10 +102,15 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_ASR (0x1ac02800) #define OPCODE_BLR (0xd63f0000) #define OPCODE_BR (0xd61f0000) +#define OPCODE_FADD_D (0x1e602800) +#define OPCODE_FDIV_D (0x1e601800) +#define OPCODE_FMUL_D (0x1e600800) +#define OPCODE_FSUB_D (0x1e603800) #define OPCODE_LDR_REG (0xb8606800) #define OPCODE_LDRB_REG (0x38606800) #define OPCODE_LDRH_REG (0x78606800) #define OPCODE_LDRX_REG_LSL3 (0xf8607800) +#define OPCODE_LDR_REG_F64_S (0xfc607800) #define OPCODE_LSL (0x1ac02000) #define OPCODE_LSR (0x1ac02400) #define OPCODE_NOP (0xd503201f) @@ -110,6 +118,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_STR_REG (0xb8206800) #define OPCODE_STRB_REG (0x38206800) #define OPCODE_STRH_REG (0x78206800) +#define OPCODE_STR_REG_F64_S (0xfc207800) #define DATPROC_SHIFT(sh) (sh << 10) #define DATPROC_IMM_SHIFT(sh) (sh << 22) @@ -124,6 +133,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define IMMS(imms) ((imms) << 10) #define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) +#define OFFSET26(offset) ((offset >> 2) & 0x03ffffff) #define OFFSET12_B(offset) (offset << 10) #define OFFSET12_H(offset) ((offset >> 1) << 10) @@ -146,6 +156,16 @@ static int offset_is_19bit(int offset) return 1; } +/*Returns true if offset fits into 26 bits*/ +static int offset_is_26bit(int offset) +{ + if (offset >= (1 << (25+2))) + return 0; + if (offset < -(1 << (25+2))) + return 0; + return 1; +} + int add_literal(codeblock_t *block, uint32_t data) { if (literal_offset >= 4096) @@ -296,6 +316,15 @@ void host_arm64_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_re codegen_addlong(block, OPCODE_ASR | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); } +void host_arm64_B(codeblock_t *block, void *dest) +{ + int offset = (uintptr_t)dest - (uintptr_t)&block->data[block_pos]; + + if (!offset_is_26bit(offset)) + fatal("host_arm64_B - offset out of range %x\n", offset); + codegen_addlong(block, OPCODE_B | OFFSET26(offset)); +} + void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) { codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR((32 - lsb) & 31) | IMMS((width-1) & 31)); @@ -461,6 +490,26 @@ void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, in codegen_addlong(block, OPCODE_CMP_LSL | Rd(0x1f) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); } +void host_arm64_FADD_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FADD_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FDIV_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FDIV_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FMUL_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMUL_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FSUB_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FSUB_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) { if (imm_data == 0xffff) /*Quick hack until proper immediate generation is written */ @@ -515,6 +564,15 @@ void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offs codegen_addlong(block, OPCODE_LDR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); } +void host_arm64_LDR_IMM_F64(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + codegen_addlong(block, OPCODE_LDR_IMM_F64 | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_REG_F64_S(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG_F64_S | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) { if (!in_range12_b(offset)) @@ -670,6 +728,15 @@ void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offse codegen_addlong(block, OPCODE_STR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); } +void host_arm64_STR_IMM_F64(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + codegen_addlong(block, OPCODE_STR_IMM_F64 | OFFSET12_Q(offset) | Rn(base_reg) | Rt(src_reg)); +} +void host_arm64_STR_REG_F64_S(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG_F64_S | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) { if (!in_range12_b(offset)) diff --git a/src/codegen_backend_arm64_ops.h b/src/codegen_backend_arm64_ops.h index 2c47509..da83275 100644 --- a/src/codegen_backend_arm64_ops.h +++ b/src/codegen_backend_arm64_ops.h @@ -11,6 +11,8 @@ void host_arm64_ANDS_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_ void host_arm64_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); +void host_arm64_B(codeblock_t *block, void *dest); + void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); void host_arm64_BLR(codeblock_t *block, int addr_reg); @@ -49,6 +51,11 @@ void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, in void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_FADD_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FDIV_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMUL_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FSUB_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); @@ -56,6 +63,9 @@ void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offs void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offset); void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); +void host_arm64_LDR_IMM_F64(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_REG_F64_S(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); void host_arm64_LDRB_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); @@ -91,6 +101,9 @@ void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int of void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset); void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); +void host_arm64_STR_IMM_F64(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm64_STR_REG_F64_S(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); void host_arm64_STRB_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); diff --git a/src/codegen_backend_arm64_uops.c b/src/codegen_backend_arm64_uops.c index 1e8ffb3..cb8e7cc 100644 --- a/src/codegen_backend_arm64_uops.c +++ b/src/codegen_backend_arm64_uops.c @@ -1,6 +1,8 @@ #ifdef __aarch64__ #include "ibm.h" +#include "x86.h" +#include "386_common.h" #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_arm64_defs.h" @@ -15,6 +17,7 @@ #define REG_IS_W(size) (size == IREG_SIZE_W) #define REG_IS_B(size) (size == IREG_SIZE_B) #define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) static int codegen_ADD(codeblock_t *block, uop_t *uop) { @@ -595,6 +598,85 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FADD_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FDIV_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FMUL_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FSUB_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range12_w((uintptr_t)&cr0 - (uintptr_t)&cpu_state)) + fatal("codegen_FP_ENTER - out of range\n"); + + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm64_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm64_BEQ_(block); + + host_arm64_mov_imm(block, REG_TEMP, uop->imm_data); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm64_mov_imm(block, REG_ARG0, 7); + host_arm64_call(block, x86_int); + host_arm64_B(block, &block->data[BLOCK_EXIT_OFFSET]); + + host_arm64_branch_set_offset(branch_ptr, &block->data[block_pos]); + + return 0; +} + static int codegen_JMP(codeblock_t *block, uop_t *uop) { host_arm64_jump(block, (uintptr_t)uop->p); @@ -1561,6 +1643,13 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB }; void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) @@ -1584,6 +1673,21 @@ void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) else fatal("codegen_direct_read_32 - not in range\n"); } +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_double - not in range\n"); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_SP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADD_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_LDR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { @@ -1606,6 +1710,29 @@ void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) else fatal("codegen_direct_write_32 - not in range\n"); } +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_SP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADD_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STRB_REG(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_double - not in range\n"); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_SP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADD_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) { diff --git a/src/codegen_backend_arm_defs.h b/src/codegen_backend_arm_defs.h index e094838..0a246fa 100644 --- a/src/codegen_backend_arm_defs.h +++ b/src/codegen_backend_arm_defs.h @@ -24,6 +24,23 @@ #define REG_TEMP REG_R3 +#define REG_D0 0 +#define REG_D1 1 +#define REG_D2 2 +#define REG_D3 3 +#define REG_D4 4 +#define REG_D5 5 +#define REG_D6 6 +#define REG_D7 7 +#define REG_D8 8 +#define REG_D9 9 +#define REG_D10 10 +#define REG_D11 11 +#define REG_D12 12 +#define REG_D13 13 +#define REG_D14 14 +#define REG_D15 15 + #define REG_MASK_R0 (1 << REG_R0) #define REG_MASK_R1 (1 << REG_R1) #define REG_MASK_R2 (1 << REG_R2) @@ -45,6 +62,7 @@ REG_MASK_R8 | REG_MASK_R9 | REG_MASK_R10 | REG_MASK_R11) #define CODEGEN_HOST_REGS 7 +#define CODEGEN_HOST_FP_REGS 8 extern void *codegen_mem_load_byte; extern void *codegen_mem_load_word; diff --git a/src/codegen_backend_arm_ops.c b/src/codegen_backend_arm_ops.c index 110ddd5..2146efe 100644 --- a/src/codegen_backend_arm_ops.c +++ b/src/codegen_backend_arm_ops.c @@ -97,6 +97,12 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_USUB16 0xe6500f70 #define OPCODE_UXTB 0xe6ef0070 #define OPCODE_UXTH 0xe6ff0070 +#define OPCODE_VADD 0xee300b00 +#define OPCODE_VDIV 0xee800b00 +#define OPCODE_VLDR 0xed900b00 +#define OPCODE_VMUL 0xee200b00 +#define OPCODE_VSTR 0xed800b00 +#define OPCODE_VSUB 0xee300b40 #define B_OFFSET(x) (((x) >> 2) & 0xffffff) @@ -724,4 +730,33 @@ void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate) codegen_addlong(block, OPCODE_UXTH | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); } +void host_arm_VADD_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VADD | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VDIV_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VDIV | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VLDR_D(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VLDR bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VLDR | Rd(dest_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VMUL_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VMUL | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSTR_D(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VSTR bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VSTR | Rd(src_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VSUB_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VSUB | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + #endif \ No newline at end of file diff --git a/src/codegen_backend_arm_ops.h b/src/codegen_backend_arm_ops.h index 7df158b..a446bf1 100644 --- a/src/codegen_backend_arm_ops.h +++ b/src/codegen_backend_arm_ops.h @@ -113,3 +113,10 @@ void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate); void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate); + +void host_arm_VADD_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VDIV_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VLDR_D(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm_VMUL_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSTR_D(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm_VSUB_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); diff --git a/src/codegen_backend_arm_uops.c b/src/codegen_backend_arm_uops.c index 9b21d04..d09f0e3 100644 --- a/src/codegen_backend_arm_uops.c +++ b/src/codegen_backend_arm_uops.c @@ -1,6 +1,8 @@ #ifdef __ARM_EABI__ #include "ibm.h" +#include "x86.h" +#include "386_common.h" #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_arm_defs.h" @@ -73,6 +75,7 @@ void host_arm_nop(codeblock_t *block) #define REG_IS_W(size) (size == IREG_SIZE_W) #define REG_IS_B(size) (size == IREG_SIZE_B) #define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) static int codegen_ADD(codeblock_t *block, uop_t *uop) { @@ -669,6 +672,85 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VADD_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VDIV_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VMUL_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VSUB_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range(&cr0, &cpu_state)) + fatal("codegen_FP_ENTER - out of range\n"); + + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm_BEQ_(block); + + host_arm_MOV_IMM(block, REG_TEMP, uop->imm_data); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm_MOV_IMM(block, REG_ARG0, 7); + host_arm_call(block, x86_int); + host_arm_B(block, (uintptr_t)&block->data[BLOCK_EXIT_OFFSET]); + + *branch_ptr |= ((((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_ptr) - 8) & 0x3fffffc) >> 2; + + return 0; +} + static int codegen_JMP(codeblock_t *block, uop_t *uop) { host_arm_B(block, (uintptr_t)uop->p); @@ -1641,6 +1723,13 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB }; void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) @@ -1660,6 +1749,18 @@ void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) else fatal("codegen_direct_read_32 - not in range\n"); } +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_arm_VLDR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VLDR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { @@ -1685,6 +1786,26 @@ void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) else fatal("codegen_direct_write_32 - not in range\n"); } +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_STRB_IMM(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VSTR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) { diff --git a/src/codegen_backend_x86-64.c b/src/codegen_backend_x86-64.c index deda8ef..4fb6fe0 100644 --- a/src/codegen_backend_x86-64.c +++ b/src/codegen_backend_x86-64.c @@ -5,6 +5,7 @@ #include "codegen_backend.h" #include "codegen_backend_x86-64_defs.h" #include "codegen_backend_x86-64_ops.h" +#include "codegen_reg.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -30,6 +31,17 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = REG_EDX }; +int codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + REG_XMM0, + REG_XMM1, + REG_XMM2, + REG_XMM3, + REG_XMM4, + REG_XMM5, + REG_XMM6 +}; + static void *mem_abrt_rout; static void build_load_routine(codeblock_t *block, int size) @@ -286,10 +298,16 @@ void codegen_backend_prologue(codeblock_t *block) addbyte(0x48); /*SUBL $40,%rsp*/ addbyte(0x83); addbyte(0xEC); - addbyte(0x28); + addbyte(0x38); addbyte(0x48); /*MOVL RBP, &cpu_state*/ addbyte(0xBD); addquad(((uintptr_t)&cpu_state) + 128); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_x86_MOV32_REG_ABS(block, REG_EAX, &cpu_state.TOP); + host_x86_SUB32_REG_IMM(block, REG_EAX, REG_EAX, block->TOP); + host_x86_MOV32_BASE_OFFSET_REG(block, REG_ESP, IREG_TOP_diff_stack_offset, REG_EAX); + } } void codegen_backend_epilogue(codeblock_t *block) @@ -297,7 +315,7 @@ void codegen_backend_epilogue(codeblock_t *block) addbyte(0x48); /*ADDL $40,%rsp*/ addbyte(0x83); addbyte(0xC4); - addbyte(0x28); + addbyte(0x38); addbyte(0x41); /*POP R15*/ addbyte(0x5f); addbyte(0x41); /*POP R14*/ @@ -336,7 +354,7 @@ void codegen_backend_epilogue(codeblock_t *block) addbyte(0x48); /*ADDL $40,%rsp*/ addbyte(0x83); addbyte(0xC4); - addbyte(0x28); + addbyte(0x38); addbyte(0x41); /*POP R15*/ addbyte(0x5f); addbyte(0x41); /*POP R14*/ diff --git a/src/codegen_backend_x86-64.h b/src/codegen_backend_x86-64.h index 6c0cfca..50797ef 100644 --- a/src/codegen_backend_x86-64.h +++ b/src/codegen_backend_x86-64.h @@ -1,3 +1,5 @@ +#include "codegen_backend_x86-64_defs.h" + #define BLOCK_SIZE 0x4000 #define BLOCK_MASK 0x3fff #define BLOCK_START 0 diff --git a/src/codegen_backend_x86-64_defs.h b/src/codegen_backend_x86-64_defs.h index ee6df65..8334b74 100644 --- a/src/codegen_backend_x86-64_defs.h +++ b/src/codegen_backend_x86-64_defs.h @@ -32,3 +32,25 @@ #define REG_R13 13 #define REG_R14 14 #define REG_R15 15 + +#define REG_XMM0 0 +#define REG_XMM1 1 +#define REG_XMM2 2 +#define REG_XMM3 3 +#define REG_XMM4 4 +#define REG_XMM5 5 +#define REG_XMM6 6 +#define REG_XMM7 7 + +#define REG_XMM_TEMP REG_XMM7 + +#define CODEGEN_HOST_REGS 3 +#define CODEGEN_HOST_FP_REGS 7 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; diff --git a/src/codegen_backend_x86-64_ops.c b/src/codegen_backend_x86-64_ops.c index 45fde94..1fe0e58 100644 --- a/src/codegen_backend_x86-64_ops.c +++ b/src/codegen_backend_x86-64_ops.c @@ -212,6 +212,11 @@ void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int codegen_addbyte2(block, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*ADD dst_reg, src_reg_b*/ } +void host_x86_ADDSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); +} + void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) { if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) @@ -336,6 +341,11 @@ void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ } +void host_x86_DIVSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); +} + void host_x86_JMP(codeblock_t *block, void *p) { jmp(block, (uintptr_t)p); @@ -599,6 +609,21 @@ void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) } } +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int index_reg, int shift, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_addbyte4(block, 0x88, 0x44 | (src_reg << 3), base_reg | (index_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_addbyte3(block, 0x88, 0x84 | (src_reg << 3), base_reg | (index_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) { if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) @@ -812,6 +837,86 @@ void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_d } } +void host_x86_MOVQ_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_MOVQ_ABS_REG reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x45 | (src_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOVQ_ABS_REG - out of range %p\n", p); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addbyte(block, 0x25); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOVQ_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg) +{ + if ((src_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_MOVQ_ABS_REG_REG_SHIFT_REG - bad reg\n"); + + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_addbyte3(block, 0x44 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_addbyte2(block, 0x84 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} + +void host_x86_MOVQ_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_MOVQ_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x45 | (dst_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOVQ_REG_ABS - out of range %p\n", p); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x04 | (dst_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addbyte(block, 0x25); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOVQ_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, 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_MOVQ_REG_ABS_REG_REG_SHIFT - bad reg\n"); + + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_addbyte3(block, 0x44 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_addbyte2(block, 0x84 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0xc0 | src_reg | (dst_reg << 3)); /*MOVQ dst_reg, src_reg*/ +} + void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) { codegen_addbyte4(block, 0x66, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ @@ -874,6 +979,11 @@ void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) fatal("host_x86_MOVZX_REG_ABS_32_8 - bad offset %i\n", offset); } +void host_x86_MULSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); +} + void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) { if (dst_reg != src_reg || (dst_reg & 8) || (src_reg & 8)) @@ -1153,6 +1263,11 @@ void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int codegen_addbyte2(block, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg_b & 7) << 3)); /*SUB dst_reg, src_reg_b*/ } +void host_x86_SUBSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); +} + #define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) diff --git a/src/codegen_backend_x86-64_ops.h b/src/codegen_backend_x86-64_ops.h index 85ec419..5b16a0e 100644 --- a/src/codegen_backend_x86-64_ops.h +++ b/src/codegen_backend_x86-64_ops.h @@ -7,6 +7,8 @@ void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int s void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_ADDSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); @@ -25,6 +27,8 @@ void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_DIVSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_JMP(codeblock_t *block, void *p); void host_x86_JNZ(codeblock_t *block, void *p); @@ -60,6 +64,8 @@ void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg); void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int index_reg, int shift, int src_reg); + void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); @@ -86,6 +92,13 @@ void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); +void host_x86_MOVQ_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVQ_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVQ_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift); +void host_x86_MOVQ_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOVQ_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg); + void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); @@ -101,6 +114,8 @@ void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MULSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); @@ -148,6 +163,8 @@ void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int s void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_SUBSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg); diff --git a/src/codegen_backend_x86-64_uops.c b/src/codegen_backend_x86-64_uops.c index bef4bcb..534bb91 100644 --- a/src/codegen_backend_x86-64_uops.c +++ b/src/codegen_backend_x86-64_uops.c @@ -1,6 +1,8 @@ #ifdef __amd64__ #include "ibm.h" +#include "x86.h" +#include "386_common.h" #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_x86-64_defs.h" @@ -18,6 +20,7 @@ #define REG_IS_W(size) (size == IREG_SIZE_W) #define REG_IS_B(size) (size == IREG_SIZE_B || size == IREG_SIZE_BH) #define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) static int codegen_ADD(codeblock_t *block, uop_t *uop) { @@ -524,6 +527,95 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_ADDSD_REG_REG(block, dest_reg, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_DIVSD_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_REG_REG(block, REG_XMM_TEMP, src_reg_a); + host_x86_DIVSD_REG_REG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_REG_REG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_MULSD_REG_REG(block, dest_reg, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_SUBSD_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_REG_REG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBSD_REG_REG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_REG_REG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint8_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_short(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_ECX, 7); +#else + host_x86_MOV32_REG_IMM(block, REG_EDI, 7); +#endif + host_x86_CALL(block, x86_int); + host_x86_JMP(block, &block->data[BLOCK_EXIT_OFFSET]); + *branch_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 1; + + return 0; +} + static int codegen_JMP(codeblock_t *block, uop_t *uop) { host_x86_JMP(block, uop->p); @@ -1346,6 +1438,13 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB }; void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) @@ -1356,6 +1455,19 @@ 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_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, REG_ECX, 7); + host_x86_MOVQ_REG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_RBP, REG_ECX, 3); +} void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { @@ -1369,6 +1481,28 @@ 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_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, REG_ECX, 7); + host_x86_MOV8_ABS_REG_REG_SHIFT_REG(block, offset, REG_RBP, REG_ECX, 0, host_reg); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_REG(block, offset, REG_RBP, REG_ECX, 3, host_reg); +} void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) { diff --git a/src/codegen_backend_x86.c b/src/codegen_backend_x86.c index 17f588f..d09bb21 100644 --- a/src/codegen_backend_x86.c +++ b/src/codegen_backend_x86.c @@ -5,6 +5,7 @@ #include "codegen_backend.h" #include "codegen_backend_x86_defs.h" #include "codegen_backend_x86_ops.h" +#include "codegen_reg.h" #include "x86.h" #if defined(__linux__) || defined(__APPLE__) @@ -30,12 +31,23 @@ int codegen_host_reg_list[CODEGEN_HOST_REGS] = REG_EDX }; +int codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + REG_XMM0, + REG_XMM1, + REG_XMM2, + REG_XMM3, + REG_XMM4, + REG_XMM5, + REG_XMM6 +}; + static void *mem_abrt_rout; static void build_load_routine(codeblock_t *block, int size) { uint8_t *branch_offset; - uint8_t *misaligned_offset; + uint8_t *misaligned_offset = NULL; /*In - ESI = address Out - ECX = data, ESI = abrt*/ @@ -107,7 +119,7 @@ static void build_load_routine(codeblock_t *block, int size) static void build_store_routine(codeblock_t *block, int size) { uint8_t *branch_offset; - uint8_t *misaligned_offset; + uint8_t *misaligned_offset = NULL; /*In - ECX = data, ESI = address Out - ESI = abrt @@ -253,18 +265,24 @@ void codegen_backend_prologue(codeblock_t *block) addbyte(0x55); /*PUSH EBP*/ addbyte(0x56); /*PUSH ESI*/ addbyte(0x57); /*PUSH EDI*/ - addbyte(0x83); /*SUBL $32,%esp*/ + addbyte(0x83); /*SUBL $64,%esp*/ addbyte(0xEC); - addbyte(0x20); + addbyte(0x40); addbyte(0xBD); /*MOVL EBP, &cpu_state*/ addlong(((uintptr_t)&cpu_state) + 128); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_x86_MOV32_REG_ABS(block, REG_EAX, &cpu_state.TOP); + host_x86_SUB32_REG_IMM(block, REG_EAX, REG_EAX, block->TOP); + host_x86_MOV32_BASE_OFFSET_REG(block, REG_ESP, IREG_TOP_diff_stack_offset, REG_EAX); + } } void codegen_backend_epilogue(codeblock_t *block) { - addbyte(0x83); /*ADDL $32,%esp*/ + addbyte(0x83); /*ADDL $64,%esp*/ addbyte(0xC4); - addbyte(0x20); + addbyte(0x40); addbyte(0x5f); /*POP EDI*/ addbyte(0x5e); /*POP ESI*/ addbyte(0x5d); /*POP EBP*/ @@ -287,9 +305,9 @@ void codegen_backend_epilogue(codeblock_t *block) addbyte(0xe8); /*CALL x86gpf*/ addlong((uint32_t)x86gpf - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ - addbyte(0x83); /*ADDL $32,%esp*/ + addbyte(0x83); /*ADDL $64,%esp*/ addbyte(0xC4); - addbyte(0x20); + addbyte(0x40); addbyte(0x5f); /*POP EDI*/ addbyte(0x5e); /*POP ESI*/ addbyte(0x5d); /*POP EBP*/ diff --git a/src/codegen_backend_x86_defs.h b/src/codegen_backend_x86_defs.h index 37e4160..93d6569 100644 --- a/src/codegen_backend_x86_defs.h +++ b/src/codegen_backend_x86_defs.h @@ -10,7 +10,19 @@ #define REG_ESI 6 #define REG_EDI 7 +#define REG_XMM0 0 +#define REG_XMM1 1 +#define REG_XMM2 2 +#define REG_XMM3 3 +#define REG_XMM4 4 +#define REG_XMM5 5 +#define REG_XMM6 6 +#define REG_XMM7 7 + +#define REG_XMM_TEMP REG_XMM7 + #define CODEGEN_HOST_REGS 3 +#define CODEGEN_HOST_FP_REGS 7 extern void *codegen_mem_load_byte; extern void *codegen_mem_load_word; diff --git a/src/codegen_backend_x86_ops.c b/src/codegen_backend_x86_ops.c index 355b8f8..3dad4db 100644 --- a/src/codegen_backend_x86_ops.c +++ b/src/codegen_backend_x86_ops.c @@ -185,6 +185,11 @@ void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int codegen_addbyte2(block, 0x01, 0xc0 | dst_reg | (src_reg_b << 3)); /*ADD dst_reg, src_reg_b*/ } +void host_x86_ADDSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); +} + void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) { if (dst_reg != src_reg) @@ -304,6 +309,11 @@ void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ } +void host_x86_DIVSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); +} + void host_x86_JMP(codeblock_t *block, void *p) { codegen_addbyte(block, 0xe9); /*JMP*/ @@ -515,6 +525,19 @@ void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) } } +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int idx_reg, int shift, int src_reg) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_addbyte4(block, 0x88, 0x44 | (src_reg << 3), base_reg | (idx_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_addbyte3(block, 0x88, 0x84 | (src_reg << 3), base_reg | (idx_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) { codegen_addbyte3(block, 0x88, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV B[base_reg + idx_reg], src_reg*/ @@ -691,6 +714,68 @@ void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_d } } +void host_x86_MOVQ_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, 0x66, 0x0f, 0xd6, 0x45 | (src_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x05 | (src_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVQ_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg) +{ + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_addbyte3(block, 0x44 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_addbyte2(block, 0x84 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} + +void host_x86_MOVQ_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_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x45 | (dst_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x05 | (dst_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVQ_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift) +{ + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_addbyte3(block, 0x44 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_addbyte2(block, 0x84 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0xc0 | src_reg | (dst_reg << 3)); /*MOVQ dst_reg, src_reg*/ +} + void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) { codegen_addbyte4(block, 0x66, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ @@ -755,6 +840,11 @@ void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_r codegen_addbyte4(block, 0x0f, 0xb7, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOVZX dst_reg, W[base_reg + idx_reg]*/ } +void host_x86_MULSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); +} + void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) { if (dst_reg != src_reg_a) @@ -988,6 +1078,11 @@ void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int codegen_addbyte2(block, 0x29, 0xc0 | dst_reg | (src_reg_b << 3)); /*SUB dst_reg, src_reg_b*/ } +void host_x86_SUBSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); +} + void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) { codegen_addbyte2(block, 0x84, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ diff --git a/src/codegen_backend_x86_ops.h b/src/codegen_backend_x86_ops.h index 7bf81ed..d6ff697 100644 --- a/src/codegen_backend_x86_ops.h +++ b/src/codegen_backend_x86_ops.h @@ -8,6 +8,8 @@ void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int s void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_ADDSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); @@ -25,6 +27,8 @@ void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_DIVSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_JMP(codeblock_t *block, void *p); void host_x86_JNZ(codeblock_t *block, void *p); @@ -59,6 +63,8 @@ void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg); void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int idx_reg, int shift, int src_reg); + void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); @@ -88,6 +94,13 @@ void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); +void host_x86_MOVQ_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVQ_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVQ_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift); +void host_x86_MOVQ_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOVQ_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg); + void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); @@ -101,6 +114,8 @@ void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MULSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); @@ -147,6 +162,8 @@ void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int s void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_SUBSD_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); diff --git a/src/codegen_backend_x86_uops.c b/src/codegen_backend_x86_uops.c index 235176d..b153804 100644 --- a/src/codegen_backend_x86_uops.c +++ b/src/codegen_backend_x86_uops.c @@ -1,6 +1,8 @@ #if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 #include "ibm.h" +#include "x86.h" +#include "386_common.h" #include "codegen.h" #include "codegen_backend.h" #include "codegen_backend_x86_defs.h" @@ -28,6 +30,7 @@ #define REG_IS_W(size) (size == IREG_SIZE_W) #define REG_IS_B(size) (size == IREG_SIZE_B || size == IREG_SIZE_BH) #define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) static int codegen_ADD(codeblock_t *block, uop_t *uop) { @@ -535,6 +538,91 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_ADDSD_REG_REG(block, dest_reg, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_DIVSD_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_REG_REG(block, REG_XMM_TEMP, src_reg_a); + host_x86_DIVSD_REG_REG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_REG_REG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_MULSD_REG_REG(block, dest_reg, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_SUBSD_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_REG_REG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBSD_REG_REG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_REG_REG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint8_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_short(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 7); + host_x86_CALL(block, x86_int); + host_x86_JMP(block, &block->data[BLOCK_EXIT_OFFSET]); + *branch_offset = (uint8_t)((uintptr_t)&block->data[block_pos] - (uintptr_t)branch_offset) - 1; + + return 0; +} + static int codegen_JMP(codeblock_t *block, uop_t *uop) { host_x86_JMP(block, uop->p); @@ -1335,6 +1423,13 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB }; void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) @@ -1345,6 +1440,19 @@ 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_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, REG_ECX, 7); + host_x86_MOVQ_REG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_EBP, REG_ECX, 3); +} void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) { @@ -1358,6 +1466,28 @@ 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_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, REG_ECX, 7); + host_x86_MOV8_ABS_REG_REG_SHIFT_REG(block, offset, REG_EBP, REG_ECX, 0, host_reg); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_REG(block, offset, REG_EBP, REG_ECX, 3, host_reg); +} void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) { diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h index c0b23c2..e949bdf 100644 --- a/src/codegen_ir_defs.h +++ b/src/codegen_ir_defs.h @@ -78,7 +78,7 @@ /*UOP_OR_IMM - dest_reg = src_reg_a | immediate*/ #define UOP_OR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x36) /*UOP_SUB - dest_reg = src_reg_a - src_reg_b*/ -#define UOP_SUB (UOP_TYPE_PARAMS_REGS | 0x37) +#define UOP_SUB (UOP_TYPE_PARAMS_REGS | 0x37) /*UOP_SUB_IMM - dest_reg = src_reg_a - immediate*/ #define UOP_SUB_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x38) /*UOP_XOR - dest_reg = src_reg_a ^ src_reg_b*/ @@ -151,7 +151,18 @@ /*UOP_TEST_JS_DEST - if (src_reg_a positive) then jump to ptr*/ #define UOP_TEST_JS_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x71 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) -#define UOP_MAX 0x72 +/*UOP_FP_ENTER - */ +#define UOP_FP_ENTER (UOP_TYPE_PARAMS_IMM | 0x80 | UOP_TYPE_BARRIER) +/*UOP_FADD - (floating point) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_FADD (UOP_TYPE_PARAMS_REGS | 0x81) +/*UOP_FSUB - (floating point) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_FSUB (UOP_TYPE_PARAMS_REGS | 0x82) +/*UOP_FMUL - (floating point) dest_reg = src_reg_a * src_reg_b*/ +#define UOP_FMUL (UOP_TYPE_PARAMS_REGS | 0x83) +/*UOP_FDIV - (floating point) dest_reg = src_reg_a / src_reg_b*/ +#define UOP_FDIV (UOP_TYPE_PARAMS_REGS | 0x84) + +#define UOP_MAX 0x85 #define UOP_MASK 0xffff @@ -205,6 +216,15 @@ static inline void uop_set_jump_dest(ir_data_t *ir, int jump_uop) uop->jump_dest_uop = ir->wr_pos; } +static inline int uop_gen(uint32_t uop_type, ir_data_t *ir) +{ + uop_t *uop = uop_alloc(ir); + + uop->type = uop_type; + + return ir->wr_pos-1; +} + static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a) { uop_t *uop = uop_alloc(ir); @@ -433,6 +453,13 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, #define uop_CMP_JO_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JO_DEST, ir, src_reg_a, src_reg_b) #define uop_CMP_JZ_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JZ_DEST, ir, src_reg_a, src_reg_b) +#define uop_FADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FDIV(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FDIV, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FMUL(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FMUL, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FSUB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FSUB, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_FP_ENTER(ir) do { if (!codegen_fpu_entered) uop_gen_imm(UOP_FP_ENTER, ir, cpu_state.oldpc); codegen_fpu_entered = 1; } while (0) + #define uop_JMP(ir, p) uop_gen_pointer(UOP_JMP, ir, p) #define uop_LOAD_SEG(ir, p, src_reg) uop_gen_reg_src_pointer(UOP_LOAD_SEG, ir, src_reg, p) @@ -461,11 +488,16 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p); void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx); void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg); void codegen_direct_write_16(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); +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg); +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg); void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset); void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset); diff --git a/src/codegen_ops.c b/src/codegen_ops.c index 188e284..55916ee 100644 --- a/src/codegen_ops.c +++ b/src/codegen_ops.c @@ -4,6 +4,7 @@ #include "codegen_ops.h" #include "codegen_ops_arith.h" #include "codegen_ops_branch.h" +#include "codegen_ops_fpu_arith.h" #include "codegen_ops_jump.h" #include "codegen_ops_logic.h" #include "codegen_ops_misc.h" @@ -105,3 +106,97 @@ RecompOpFn recomp_opcodes_0f[512] = /*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; + +RecompOpFn recomp_opcodes_d8[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, +}; + +RecompOpFn recomp_opcodes_dc[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, +}; diff --git a/src/codegen_ops.h b/src/codegen_ops.h index 1534a38..fbbaed4 100644 --- a/src/codegen_ops.h +++ b/src/codegen_ops.h @@ -9,12 +9,12 @@ typedef uint32_t (*RecompOpFn)(codeblock_t *block, struct ir_data_t *ir, uint8_t extern RecompOpFn recomp_opcodes[512]; extern RecompOpFn recomp_opcodes_0f[512]; -/*extern RecompOpFn recomp_opcodes_d8[512]; -extern RecompOpFn recomp_opcodes_d9[512]; +extern RecompOpFn recomp_opcodes_d8[512]; +/*extern RecompOpFn recomp_opcodes_d9[512]; extern RecompOpFn recomp_opcodes_da[512]; -extern RecompOpFn recomp_opcodes_db[512]; +extern RecompOpFn recomp_opcodes_db[512];*/ extern RecompOpFn recomp_opcodes_dc[512]; -extern RecompOpFn recomp_opcodes_dd[512]; +/*extern RecompOpFn recomp_opcodes_dd[512]; extern RecompOpFn recomp_opcodes_de[512]; extern RecompOpFn recomp_opcodes_df[512]; extern RecompOpFn recomp_opcodes_REPE[512]; diff --git a/src/codegen_ops_fpu_arith.c b/src/codegen_ops_fpu_arith.c new file mode 100644 index 0000000..4d2237b --- /dev/null +++ b/src/codegen_ops_fpu_arith.c @@ -0,0 +1,134 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_arith.h" + +uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} + +uint32_t ropFDIV(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} + +uint32_t ropFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFMULr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} + +uint32_t ropFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} diff --git a/src/codegen_ops_fpu_arith.h b/src/codegen_ops_fpu_arith.h new file mode 100644 index 0000000..063f614 --- /dev/null +++ b/src/codegen_ops_fpu_arith.h @@ -0,0 +1,12 @@ +uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIV(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_reg.c b/src/codegen_reg.c index 36b5ad8..556dbbf 100644 --- a/src/codegen_reg.c +++ b/src/codegen_reg.c @@ -9,10 +9,22 @@ 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]; +ir_reg_t _host_regs[CODEGEN_HOST_REGS]; +static uint8_t _host_reg_dirty[CODEGEN_HOST_REGS]; -static uint8_t host_regs_locked; +ir_reg_t host_fp_regs[CODEGEN_HOST_FP_REGS]; +static uint8_t host_fp_reg_dirty[CODEGEN_HOST_FP_REGS]; + +typedef struct host_reg_set_t +{ + ir_reg_t *regs; + uint8_t *dirty; + int *reg_list; + uint16_t locked; + int nr_regs; +} host_reg_set_t; + +static host_reg_set_t host_reg_set, host_fp_reg_set; enum { @@ -20,70 +32,110 @@ enum REG_WORD, REG_DWORD, REG_QWORD, - REG_POINTER + REG_POINTER, + REG_FPU_ST_BYTE, + REG_FPU_ST_DOUBLE +}; + +enum +{ + REG_INTEGER, + REG_FP }; struct { int native_size; void *p; + int type; } 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_EAX] = {REG_DWORD, &EAX, REG_INTEGER}, + [IREG_ECX] = {REG_DWORD, &ECX, REG_INTEGER}, + [IREG_EDX] = {REG_DWORD, &EDX, REG_INTEGER}, + [IREG_EBX] = {REG_DWORD, &EBX, REG_INTEGER}, + [IREG_ESP] = {REG_DWORD, &ESP, REG_INTEGER}, + [IREG_EBP] = {REG_DWORD, &EBP, REG_INTEGER}, + [IREG_ESI] = {REG_DWORD, &ESI, REG_INTEGER}, + [IREG_EDI] = {REG_DWORD, &EDI, REG_INTEGER}, - [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_flags_op] = {REG_DWORD, &cpu_state.flags_op, REG_INTEGER}, + [IREG_flags_res] = {REG_DWORD, &cpu_state.flags_res, REG_INTEGER}, + [IREG_flags_op1] = {REG_DWORD, &cpu_state.flags_op1, REG_INTEGER}, + [IREG_flags_op2] = {REG_DWORD, &cpu_state.flags_op2, REG_INTEGER}, - [IREG_pc] = {REG_DWORD, &cpu_state.pc}, - [IREG_oldpc] = {REG_DWORD, &cpu_state.oldpc}, + [IREG_pc] = {REG_DWORD, &cpu_state.pc, REG_INTEGER}, + [IREG_oldpc] = {REG_DWORD, &cpu_state.oldpc, REG_INTEGER}, - [IREG_eaaddr] = {REG_DWORD, &cpu_state.eaaddr}, - [IREG_ea_seg] = {REG_POINTER, &cpu_state.ea_seg}, + [IREG_eaaddr] = {REG_DWORD, &cpu_state.eaaddr, REG_INTEGER}, + [IREG_ea_seg] = {REG_POINTER, &cpu_state.ea_seg, REG_INTEGER}, - [IREG_op32] = {REG_DWORD, &cpu_state.op32}, - [IREG_ssegs] = {REG_BYTE, &cpu_state.ssegs}, + [IREG_op32] = {REG_DWORD, &cpu_state.op32, REG_INTEGER}, + [IREG_ssegs] = {REG_BYTE, &cpu_state.ssegs, REG_INTEGER}, - [IREG_rm_mod_reg] = {REG_DWORD, &cpu_state.rm_data.rm_mod_reg_data}, + [IREG_rm_mod_reg] = {REG_DWORD, &cpu_state.rm_data.rm_mod_reg_data, REG_INTEGER}, - [IREG_ins] = {REG_DWORD, &cpu_state.cpu_recomp_ins}, - [IREG_cycles] = {REG_DWORD, &cpu_state._cycles}, + [IREG_ins] = {REG_DWORD, &cpu_state.cpu_recomp_ins, REG_INTEGER}, + [IREG_cycles] = {REG_DWORD, &cpu_state._cycles, REG_INTEGER}, - [IREG_CS_base] = {REG_DWORD, &cpu_state.seg_cs.base}, - [IREG_DS_base] = {REG_DWORD, &cpu_state.seg_ds.base}, - [IREG_ES_base] = {REG_DWORD, &cpu_state.seg_es.base}, - [IREG_FS_base] = {REG_DWORD, &cpu_state.seg_fs.base}, - [IREG_GS_base] = {REG_DWORD, &cpu_state.seg_gs.base}, - [IREG_SS_base] = {REG_DWORD, &cpu_state.seg_ss.base}, + [IREG_CS_base] = {REG_DWORD, &cpu_state.seg_cs.base, REG_INTEGER}, + [IREG_DS_base] = {REG_DWORD, &cpu_state.seg_ds.base, REG_INTEGER}, + [IREG_ES_base] = {REG_DWORD, &cpu_state.seg_es.base, REG_INTEGER}, + [IREG_FS_base] = {REG_DWORD, &cpu_state.seg_fs.base, REG_INTEGER}, + [IREG_GS_base] = {REG_DWORD, &cpu_state.seg_gs.base, REG_INTEGER}, + [IREG_SS_base] = {REG_DWORD, &cpu_state.seg_ss.base, REG_INTEGER}, - [IREG_CS_seg] = {REG_WORD, &cpu_state.seg_cs.seg}, - [IREG_DS_seg] = {REG_WORD, &cpu_state.seg_ds.seg}, - [IREG_ES_seg] = {REG_WORD, &cpu_state.seg_es.seg}, - [IREG_FS_seg] = {REG_WORD, &cpu_state.seg_fs.seg}, - [IREG_GS_seg] = {REG_WORD, &cpu_state.seg_gs.seg}, - [IREG_SS_seg] = {REG_WORD, &cpu_state.seg_ss.seg}, + [IREG_CS_seg] = {REG_WORD, &cpu_state.seg_cs.seg, REG_INTEGER}, + [IREG_DS_seg] = {REG_WORD, &cpu_state.seg_ds.seg, REG_INTEGER}, + [IREG_ES_seg] = {REG_WORD, &cpu_state.seg_es.seg, REG_INTEGER}, + [IREG_FS_seg] = {REG_WORD, &cpu_state.seg_fs.seg, REG_INTEGER}, + [IREG_GS_seg] = {REG_WORD, &cpu_state.seg_gs.seg, REG_INTEGER}, + [IREG_SS_seg] = {REG_WORD, &cpu_state.seg_ss.seg, REG_INTEGER}, + + [IREG_FPU_TOP] = {REG_DWORD, &cpu_state.TOP, REG_INTEGER}, + + [IREG_ST0] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + [IREG_ST1] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + [IREG_ST2] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + [IREG_ST3] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + [IREG_ST4] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + [IREG_ST5] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + [IREG_ST6] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + [IREG_ST7] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP}, + + [IREG_tag0] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, + [IREG_tag1] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, + [IREG_tag2] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, + [IREG_tag3] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, + [IREG_tag4] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, + [IREG_tag5] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, + [IREG_tag6] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, + [IREG_tag7] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER}, /*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, (void *)16}, - [IREG_temp1] = {REG_DWORD, (void *)20}, - [IREG_temp2] = {REG_DWORD, (void *)24}, - [IREG_temp3] = {REG_DWORD, (void *)28}, + [IREG_temp0] = {REG_DWORD, (void *)16, REG_INTEGER}, + [IREG_temp1] = {REG_DWORD, (void *)20, REG_INTEGER}, + [IREG_temp2] = {REG_DWORD, (void *)24, REG_INTEGER}, + [IREG_temp3] = {REG_DWORD, (void *)28, REG_INTEGER}, }; void codegen_reg_reset() { int c; - + + host_reg_set.regs = _host_regs; + host_reg_set.dirty = _host_reg_dirty; + host_reg_set.reg_list = codegen_host_reg_list; + host_reg_set.locked = 0; + host_reg_set.nr_regs = CODEGEN_HOST_REGS; + host_fp_reg_set.regs = host_fp_regs; + host_fp_reg_set.dirty = host_fp_reg_dirty; + host_fp_reg_set.reg_list = codegen_host_fp_reg_list; + host_fp_reg_set.locked = 0; + host_fp_reg_set.nr_regs = CODEGEN_HOST_FP_REGS; + for (c = 0; c < IREG_COUNT; c++) { reg_last_version[c] = 0; @@ -91,8 +143,13 @@ void codegen_reg_reset() } for (c = 0; c < CODEGEN_HOST_REGS; c++) { - host_regs[c] = invalid_ir_reg; - host_reg_dirty[c] = 0; + host_reg_set.regs[c] = invalid_ir_reg; + host_reg_set.dirty[c] = 0; + } + for (c = 0; c < CODEGEN_HOST_FP_REGS; c++) + { + host_fp_reg_set.regs[c] = invalid_ir_reg; + host_fp_reg_set.dirty[c] = 0; } } @@ -101,62 +158,104 @@ static inline int ir_reg_is_invalid(ir_reg_t ir_reg) return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID); } -static void codegen_reg_load(codeblock_t *block, int c, ir_reg_t ir_reg) +static inline host_reg_set_t *get_reg_set(ir_reg_t ir_reg) +{ + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type == REG_INTEGER) + return &host_reg_set; + else + return &host_fp_reg_set; +} + +static void codegen_reg_load(host_reg_set_t *reg_set, codeblock_t *block, int c, ir_reg_t ir_reg) { switch (ireg_data[IREG_GET_REG(ir_reg.reg)].native_size) { case REG_WORD: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_WORD !REG_INTEGER\n"); if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) - codegen_direct_read_16_stack(block, codegen_host_reg_list[c], (int)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + codegen_direct_read_16_stack(block, reg_set->reg_list[c], (int)ireg_data[IREG_GET_REG(ir_reg.reg)].p); else - codegen_direct_read_16(block, codegen_host_reg_list[c], ireg_data[IREG_GET_REG(ir_reg.reg)].p); + codegen_direct_read_16(block, reg_set->reg_list[c], ireg_data[IREG_GET_REG(ir_reg.reg)].p); break; case REG_DWORD: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_DWORD !REG_INTEGER\n"); if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) - codegen_direct_read_32_stack(block, codegen_host_reg_list[c], (int)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + codegen_direct_read_32_stack(block, reg_set->reg_list[c], (int)ireg_data[IREG_GET_REG(ir_reg.reg)].p); else - codegen_direct_read_32(block, codegen_host_reg_list[c], ireg_data[IREG_GET_REG(ir_reg.reg)].p); + codegen_direct_read_32(block, reg_set->reg_list[c], ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_FPU_ST_DOUBLE: + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_read_double(block, reg_set->reg_list[c], &cpu_state.ST[ir_reg.reg & 7]); + else + codegen_direct_read_st_double(block, reg_set->reg_list[c], &cpu_state.ST[0], ir_reg.reg & 7); break; default: fatal("codegen_reg_load - native_size=%i\n", ireg_data[IREG_GET_REG(ir_reg.reg)].native_size); } - host_regs[c] = ir_reg; + reg_set->regs[c] = ir_reg; + //pclog(" codegen_reg_load: c=%i reg=%02x.%i\n", c, host_regs[c].reg,host_regs[c].version); } -static void codegen_reg_writeback(codeblock_t *block, int c, int invalidate) +static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, int c, int invalidate) { - int ir_reg = IREG_GET_REG(host_regs[c].reg); + int ir_reg = IREG_GET_REG(reg_set->regs[c].reg); void *p = ireg_data[ir_reg].p; switch (ireg_data[ir_reg].native_size) { case REG_BYTE: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_BYTE !REG_INTEGER\n"); if ((uintptr_t)p < 256) fatal("codegen_reg_writeback - REG_BYTE %p\n", p); - codegen_direct_write_8(block, p, codegen_host_reg_list[c]); + codegen_direct_write_8(block, p, reg_set->reg_list[c]); break; case REG_WORD: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_WORD !REG_INTEGER\n"); if ((uintptr_t)p < 256) fatal("codegen_reg_writeback - REG_WORD %p\n", p); - codegen_direct_write_16(block, p, codegen_host_reg_list[c]); + codegen_direct_write_16(block, p, reg_set->reg_list[c]); break; case REG_DWORD: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_DWORD !REG_INTEGER\n"); if ((uintptr_t)p < 256) - codegen_direct_write_32_stack(block, (int)p, codegen_host_reg_list[c]); + codegen_direct_write_32_stack(block, (int)p, reg_set->reg_list[c]); else - codegen_direct_write_32(block, p, codegen_host_reg_list[c]); + codegen_direct_write_32(block, p, reg_set->reg_list[c]); break; case REG_POINTER: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_POINTER !REG_INTEGER\n"); if ((uintptr_t)p < 256) fatal("codegen_reg_writeback - REG_POINTER %p\n", p); - codegen_direct_write_ptr(block, p, codegen_host_reg_list[c]); + codegen_direct_write_ptr(block, p, reg_set->reg_list[c]); + break; + + case REG_FPU_ST_BYTE: + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_8(block, &cpu_state.tag[reg_set->regs[c].reg & 7], reg_set->reg_list[c]); + else + codegen_direct_write_st_8(block, &cpu_state.tag[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c]); + break; + + case REG_FPU_ST_DOUBLE: + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_double(block, &cpu_state.ST[reg_set->regs[c].reg & 7], reg_set->reg_list[c]); + else + codegen_direct_write_st_double(block, &cpu_state.ST[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c]); break; default: @@ -164,8 +263,8 @@ static void codegen_reg_writeback(codeblock_t *block, int c, int invalidate) } if (invalidate) - host_regs[c] = invalid_ir_reg; - host_reg_dirty[c] = 0; + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; } void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c) @@ -173,7 +272,8 @@ void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_ int c; int dest_reference = 0; - host_regs_locked = 0; + host_reg_set.locked = 0; + host_fp_reg_set.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, @@ -190,82 +290,88 @@ void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_ } for (c = 0; c < CODEGEN_HOST_REGS; c++) { - if (!ir_reg_is_invalid(src_reg_a) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(src_reg_a.reg)) + host_reg_set_t *reg_set = get_reg_set(src_reg_a); + if (!ir_reg_is_invalid(src_reg_a) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(src_reg_a.reg)) { - if (host_regs[c].version != src_reg_a.version) + if (reg_set->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); + reg_set->locked |= (1 << c); } - if (!ir_reg_is_invalid(src_reg_b) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(src_reg_b.reg)) + reg_set = get_reg_set(src_reg_b); + if (!ir_reg_is_invalid(src_reg_b) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(src_reg_b.reg)) { - if (host_regs[c].version != src_reg_b.version) + if (reg_set->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); + reg_set->locked |= (1 << c); } - if (!ir_reg_is_invalid(src_reg_c) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(src_reg_c.reg)) + reg_set = get_reg_set(src_reg_c); + if (!ir_reg_is_invalid(src_reg_c) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(src_reg_c.reg)) { - if (host_regs[c].version != src_reg_c.version) + if (reg_set->regs[c].version != src_reg_c.version) fatal("codegen_reg_alloc_register - host_regs[c].version != src_reg_c.version\n"); - host_regs_locked |= (1 << c); + reg_set->locked |= (1 << c); } - if (!ir_reg_is_invalid(dest_reg_a) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(dest_reg_a.reg)) + reg_set = get_reg_set(dest_reg_a); + if (!ir_reg_is_invalid(dest_reg_a) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_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[IREG_GET_REG(host_regs[c].reg)][host_regs[c].version] == dest_reference)) - host_regs_locked |= (1 << c); + if (reg_set->regs[c].version == dest_reg_a.version || (reg_set->regs[c].version == (dest_reg_a.version-1) && reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] == dest_reference)) + reg_set->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); + fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", reg_set->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 *host_reg_idx) { + host_reg_set_t *reg_set = get_reg_set(ir_reg); int c; /*Search for required register*/ - for (c = 0; c < CODEGEN_HOST_REGS; c++) + for (c = 0; c < reg_set->nr_regs; c++) { - if (!ir_reg_is_invalid(host_regs[c]) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(ir_reg.reg) && host_regs[c].version == ir_reg.version) + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version == ir_reg.version) break; - if (!ir_reg_is_invalid(host_regs[c]) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version_refcount[IREG_GET_REG(host_regs[c].reg)][host_regs[c].version]) + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version]) fatal("codegen_reg_alloc_read_reg - version mismatch!\n"); } - if (c == CODEGEN_HOST_REGS) + if (c == reg_set->nr_regs) { /*No unused registers. Search for an unlocked register*/ - for (c = 0; c < CODEGEN_HOST_REGS; c++) + for (c = 0; c < reg_set->nr_regs; c++) { - if (!(host_regs_locked & (1 << c))) + if (!(reg_set->locked & (1 << c))) break; } - if (c == CODEGEN_HOST_REGS) + if (c == reg_set->nr_regs) fatal("codegen_reg_alloc_read_reg - out of registers\n"); - if (host_reg_dirty[c]) - codegen_reg_writeback(block, c, 1); + if (reg_set->dirty[c]) + codegen_reg_writeback(reg_set, block, c, 1); // pclog(" load %i\n", c); - codegen_reg_load(block, c, ir_reg); - host_regs_locked |= (1 << c); + codegen_reg_load(reg_set, block, c, ir_reg); + reg_set->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); - host_reg_dirty[c] = 0; + reg_set->dirty[c] = 0; } // else // pclog(" already loaded %i\n", c); - reg_version_refcount[IREG_GET_REG(host_regs[c].reg)][host_regs[c].version]--; - if (reg_version_refcount[IREG_GET_REG(host_regs[c].reg)][host_regs[c].version] < 0) + reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version]--; + if (reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] < 0) fatal("codegen_reg_alloc_read_reg - refcount < 0\n"); if (host_reg_idx) *host_reg_idx = c; // pclog(" codegen_reg_alloc_read_reg: %i.%i %i %02x.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c], host_regs[c].reg,host_regs[c].version, c); - return codegen_host_reg_list[c] | IREG_GET_SIZE(ir_reg.reg); + return reg_set->reg_list[c] | IREG_GET_SIZE(ir_reg.reg); } ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) { + host_reg_set_t *reg_set = get_reg_set(ir_reg); int c; if (IREG_GET_SIZE(ir_reg.reg) != IREG_SIZE_L) @@ -278,85 +384,107 @@ ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) codegen_reg_alloc_read_reg(block, parent_reg, &c); - if (IREG_GET_REG(host_regs[c].reg) != IREG_GET_REG(ir_reg.reg) || host_regs[c].version != ir_reg.version-1) + if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version != ir_reg.version-1) fatal("codegen_reg_alloc_write_reg sub_reg - doesn't match %i %02x.%i %02x.%i\n", c, - host_regs[c].reg,host_regs[c].version, + reg_set->regs[c].reg,reg_set->regs[c].version, ir_reg.reg,ir_reg.version); - host_regs[c].reg = ir_reg.reg; - host_regs[c].version = ir_reg.version; - host_reg_dirty[c] = 1; + reg_set->regs[c].reg = ir_reg.reg; + reg_set->regs[c].version = ir_reg.version; + reg_set->dirty[c] = 1; // pclog(" codegen_reg_alloc_write_reg: partial %i.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c]); - return codegen_host_reg_list[c] | IREG_GET_SIZE(ir_reg.reg); + return reg_set->reg_list[c] | IREG_GET_SIZE(ir_reg.reg); } /*Search for previous version in host register*/ - for (c = 0; c < CODEGEN_HOST_REGS; c++) + for (c = 0; c < reg_set->nr_regs; c++) { - if (!ir_reg_is_invalid(host_regs[c]) && IREG_GET_REG(host_regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) { - if (host_regs[c].version == ir_reg.version-1) + if (reg_set->regs[c].version == ir_reg.version-1) { - if (reg_version_refcount[IREG_GET_REG(host_regs[c].reg)][host_regs[c].version] != 0) + if (reg_version_refcount[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version] != 0) fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); break; } } } - if (c == CODEGEN_HOST_REGS) + if (c == reg_set->nr_regs) { /*Search for unused registers*/ - for (c = 0; c < CODEGEN_HOST_REGS; c++) + for (c = 0; c < reg_set->nr_regs; c++) { - if (ir_reg_is_invalid(host_regs[c])) + if (ir_reg_is_invalid(reg_set->regs[c])) break; } - if (c == CODEGEN_HOST_REGS) + if (c == reg_set->nr_regs) { /*No unused registers. Search for an unlocked register*/ - for (c = 0; c < CODEGEN_HOST_REGS; c++) + for (c = 0; c < reg_set->nr_regs; c++) { - if (!(host_regs_locked & (1 << c))) + if (!(reg_set->locked & (1 << c))) break; } - if (c == CODEGEN_HOST_REGS) + if (c == reg_set->nr_regs) fatal("codegen_reg_alloc_write_reg - out of registers\n"); - if (host_reg_dirty[c]) - codegen_reg_writeback(block, c, 1); + if (reg_set->dirty[c]) + codegen_reg_writeback(reg_set, block, c, 1); } } - host_regs[c].reg = ir_reg.reg; - host_regs[c].version = ir_reg.version; - host_reg_dirty[c] = 1; + reg_set->regs[c].reg = ir_reg.reg; + reg_set->regs[c].version = ir_reg.version; + reg_set->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] | IREG_GET_SIZE(ir_reg.reg); + return reg_set->reg_list[c] | IREG_GET_SIZE(ir_reg.reg); } void codegen_reg_flush(ir_data_t *ir, codeblock_t *block) { + host_reg_set_t *reg_set; int c; - - for (c = 0; c < CODEGEN_HOST_REGS; c++) + + reg_set = &host_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) { - if (!ir_reg_is_invalid(host_regs[c]) && host_reg_dirty[c]) + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) { - codegen_reg_writeback(block, c, 0); + codegen_reg_writeback(reg_set, block, c, 0); + } + } + + reg_set = &host_fp_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 0); } } } void codegen_reg_flush_invalidate(ir_data_t *ir, codeblock_t *block) { + host_reg_set_t *reg_set; int c; - for (c = 0; c < CODEGEN_HOST_REGS; c++) + reg_set = &host_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) { - if (!ir_reg_is_invalid(host_regs[c])) + if (!ir_reg_is_invalid(reg_set->regs[c])) { - codegen_reg_writeback(block, c, 1); + codegen_reg_writeback(reg_set, block, c, 1); + } + } + + reg_set = &host_fp_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c])) + { + codegen_reg_writeback(reg_set, block, c, 1); } } } diff --git a/src/codegen_reg.h b/src/codegen_reg.h index 26422d8..986f0aa 100644 --- a/src/codegen_reg.h +++ b/src/codegen_reg.h @@ -1,9 +1,9 @@ #ifndef _CODEGEN_REG_H_ #define _CODEGEN_REG_H_ -#define IREG_REG_MASK 0x3f -#define IREG_SIZE_SHIFT 6 -#define IREG_SIZE_MASK (3 << IREG_SIZE_SHIFT) +#define IREG_REG_MASK 0xff +#define IREG_SIZE_SHIFT 8 +#define IREG_SIZE_MASK (7 << IREG_SIZE_SHIFT) #define IREG_GET_REG(reg) ((reg) & IREG_REG_MASK) #define IREG_GET_SIZE(reg) ((reg) & IREG_SIZE_MASK) @@ -12,6 +12,7 @@ #define IREG_SIZE_W (1 << IREG_SIZE_SHIFT) #define IREG_SIZE_B (2 << IREG_SIZE_SHIFT) #define IREG_SIZE_BH (3 << IREG_SIZE_SHIFT) +#define IREG_SIZE_D (4 << IREG_SIZE_SHIFT) enum { @@ -64,7 +65,33 @@ enum IREG_temp2 = 35, IREG_temp3 = 36, - IREG_COUNT, + IREG_FPU_TOP = 37, + + /*FPU stack registers are physical registers. Use IREG_ST() / IREG_tag() + to access. + When CODEBLOCK_STATIC_TOP is set, the physical register number will be + used directly to index the stack. When it is clear, the difference + between the current value of TOP and the value when the block was + first compiled will be added to adjust for any changes in TOP.*/ + IREG_ST0 = 40, + IREG_ST1 = 41, + IREG_ST2 = 42, + IREG_ST3 = 43, + IREG_ST4 = 44, + IREG_ST5 = 45, + IREG_ST6 = 46, + IREG_ST7 = 47, + + IREG_tag0 = 48, + IREG_tag1 = 49, + IREG_tag2 = 50, + IREG_tag3 = 51, + IREG_tag4 = 52, + IREG_tag5 = 53, + IREG_tag6 = 54, + IREG_tag7 = 55, + + IREG_COUNT = 56, IREG_INVALID = 63, @@ -116,6 +143,11 @@ enum #define IREG_16(reg) ((reg) + IREG_AX) #define IREG_32(reg) ((reg) + IREG_EAX) +#define IREG_ST(r) (IREG_ST0 + ((cpu_state.TOP + (r)) & 7) + IREG_SIZE_D) +#define IREG_tag(r) (IREG_tag0 + ((cpu_state.TOP + (r)) & 7)) + +#define IREG_TOP_diff_stack_offset 32 + static inline int ireg_seg_base(x86seg *seg) { if (seg == &cpu_state.seg_cs) @@ -139,13 +171,13 @@ extern uint8_t reg_version_refcount[IREG_COUNT][256]; typedef struct { - uint8_t reg; - uint8_t version; + uint16_t reg; + uint16_t version; } ir_reg_t; extern ir_reg_t invalid_ir_reg; -typedef uint8_t ir_host_reg_t; +typedef uint16_t ir_host_reg_t; #define REG_VERSION_MAX 250 diff --git a/src/ibm.h b/src/ibm.h index de79af6..6503b67 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -180,6 +180,12 @@ struct uint16_t old_npxc, new_npxc; x86seg seg_cs,seg_ds,seg_es,seg_ss,seg_fs,seg_gs; + + union + { + uint32_t l; + uint16_t w; + } CR0; } cpu_state; #define cycles cpu_state._cycles @@ -239,14 +245,8 @@ uint8_t *pccache2; int loadseg(uint16_t seg, x86seg *s); void loadcs(uint16_t seg); -union -{ - uint32_t l; - uint16_t w; -} CR0; - -#define cr0 CR0.l -#define msw CR0.w +#define cr0 cpu_state.CR0.l +#define msw cpu_state.CR0.w uint32_t cr2, cr3, cr4; uint32_t dr[8];