From 07035c97c850cce90e8e75cee7e929b25fa2498b Mon Sep 17 00:00:00 2001 From: SarahW Date: Mon, 26 Nov 2018 17:00:00 +0000 Subject: [PATCH] Added recompiled versions of FABS, FCHS, FSQRT and FTST. --- src/codegen_backend_arm64_ops.c | 18 ++++++++ src/codegen_backend_arm64_ops.h | 4 ++ src/codegen_backend_arm64_uops.c | 70 ++++++++++++++++++++++++++++ src/codegen_backend_arm_ops.c | 18 ++++++++ src/codegen_backend_arm_ops.h | 6 +++ src/codegen_backend_arm_uops.c | 68 +++++++++++++++++++++++++++ src/codegen_backend_x86-64_ops.c | 10 ++++ src/codegen_backend_x86-64_ops.h | 4 ++ src/codegen_backend_x86-64_uops.c | 77 +++++++++++++++++++++++++++++++ src/codegen_backend_x86_ops.c | 10 ++++ src/codegen_backend_x86_ops.h | 4 ++ src/codegen_backend_x86_uops.c | 77 +++++++++++++++++++++++++++++++ src/codegen_ir_defs.h | 13 ++++++ src/codegen_ops.c | 8 ++-- src/codegen_ops_fpu_arith.c | 36 +++++++++++++++ src/codegen_ops_fpu_arith.h | 5 ++ 16 files changed, 424 insertions(+), 4 deletions(-) diff --git a/src/codegen_backend_arm64_ops.c b/src/codegen_backend_arm64_ops.c index 9dabfe4..ee2c0b6 100644 --- a/src/codegen_backend_arm64_ops.c +++ b/src/codegen_backend_arm64_ops.c @@ -120,6 +120,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_CMGT_V4H (0x0e603400) #define OPCODE_CMGT_V2S (0x0ea03400) #define OPCODE_EOR_V (0x2e201c00) +#define OPCODE_FABS_D (0x1e60c000) #define OPCODE_FADD_D (0x1e602800) #define OPCODE_FCMP_D (0x1e602000) #define OPCODE_FCVT_D_S (0x1e22c000) @@ -139,7 +140,9 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_FMOV_S_W (0x1e270000) #define OPCODE_FMOV_W_S (0x1e260000) #define OPCODE_FMUL_D (0x1e600800) +#define OPCODE_FNEG_D (0x1e614000) #define OPCODE_FRINTX_D (0x1e674000) +#define OPCODE_FSQRT_D (0x1e61c000) #define OPCODE_FSUB_D (0x1e603800) #define OPCODE_LDR_REG (0xb8606800) #define OPCODE_LDRX_REG (0xf8606800) @@ -680,6 +683,11 @@ void host_arm64_EOR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int sr codegen_addlong(block, OPCODE_EOR_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); } +void host_arm64_FABS_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FABS_D | Rd(dst_reg) | Rn(src_reg)); +} + 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)); @@ -768,11 +776,21 @@ void host_arm64_FMOV_W_S(codeblock_t *block, int dst_reg, int src_reg) codegen_addlong(block, OPCODE_FMOV_W_S | Rd(dst_reg) | Rn(src_reg)); } +void host_arm64_FNEG_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FNEG_D | Rd(dst_reg) | Rn(src_reg)); +} + void host_arm64_FRINTX_D(codeblock_t *block, int dst_reg, int src_reg) { codegen_addlong(block, OPCODE_FRINTX_D | Rd(dst_reg) | Rn(src_reg)); } +void host_arm64_FSQRT_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FSQRT_D | Rd(dst_reg) | Rn(src_reg)); +} + void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) { if (!in_range7_x(offset)) diff --git a/src/codegen_backend_arm64_ops.h b/src/codegen_backend_arm64_ops.h index 179c5af..048c354 100644 --- a/src/codegen_backend_arm64_ops.h +++ b/src/codegen_backend_arm64_ops.h @@ -75,6 +75,8 @@ void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); void host_arm64_EOR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FABS_D(codeblock_t *block, int dst_reg, int src_reg); + void host_arm64_FADD_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); void host_arm64_FCMP_D(codeblock_t *block, 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); @@ -101,6 +103,8 @@ void host_arm64_FMOV_W_S(codeblock_t *block, int dst_reg, int src_reg); void host_arm64_FRINTX_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FSQRT_D(codeblock_t *block, int dst_reg, int src_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); diff --git a/src/codegen_backend_arm64_uops.c b/src/codegen_backend_arm64_uops.c index 4f34ea3..0ee74dc 100644 --- a/src/codegen_backend_arm64_uops.c +++ b/src/codegen_backend_arm64_uops.c @@ -619,6 +619,71 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FABS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FABS_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FNEG_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FSQRT_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FSUB_D(block, REG_V_TEMP, REG_V_TEMP, REG_V_TEMP); + host_arm64_MOVZ_IMM(block, dest_reg, 0); + host_arm64_FCMP_D(block, src_reg_a, REG_V_TEMP); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C3); + host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, C0); + host_arm64_CSEL_EQ(block, dest_reg, REG_TEMP, dest_reg); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C0|C2|C3); + host_arm64_CSEL_CC(block, dest_reg, REG_TEMP2, dest_reg); + host_arm64_CSEL_VS(block, dest_reg, REG_TEMP, dest_reg); + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + 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); @@ -2540,6 +2605,11 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_FMUL & UOP_MASK] = codegen_FMUL, [UOP_FSUB & UOP_MASK] = codegen_FSUB, + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, diff --git a/src/codegen_backend_arm_ops.c b/src/codegen_backend_arm_ops.c index b6692a7..12e9c68 100644 --- a/src/codegen_backend_arm_ops.c +++ b/src/codegen_backend_arm_ops.c @@ -86,6 +86,7 @@ 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_VABS_D 0xeeb00bc0 #define OPCODE_VADD 0xee300b00 #define OPCODE_VADD_I8 0xf2000800 #define OPCODE_VADD_I16 0xf2100800 @@ -120,6 +121,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_VMUL 0xee200b00 #define OPCODE_VMUL_S16 0xf2100910 #define OPCODE_VMULL_S16 0xf2900c00 +#define OPCODE_VNEG_D 0xeeb10b40 #define OPCODE_VORR_D 0xf2200110 #define OPCODE_VPADDL_S16 0xf3b40200 #define OPCODE_VPADDL_S32 0xf3b80200 @@ -145,6 +147,7 @@ static inline void codegen_addlong(codeblock_t *block, uint32_t val) #define OPCODE_VSHR_D_U32 0xf3a00010 #define OPCODE_VSHR_D_U64 0xf3800090 #define OPCODE_VSHRN 0xf2800810 +#define OPCODE_VSQRT_D 0xeeb10bc0 #define OPCODE_VSTR_D 0xed800b00 #define OPCODE_VSTR_S 0xed800a00 #define OPCODE_VSUB 0xee300b40 @@ -796,6 +799,11 @@ 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_VABS_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VABS_D | Vd(dest_reg) | Vm(src_reg)); +} + 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)); @@ -940,6 +948,11 @@ void host_arm_VMULL_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_ codegen_addlong(block, OPCODE_VMULL_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); } +void host_arm_VNEG_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VNEG_D | Vd(dest_reg) | Vm(src_reg)); +} + void host_arm_VORR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) { codegen_addlong(block, OPCODE_VORR_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); @@ -1065,6 +1078,11 @@ void host_arm_VSHRN_32(codeblock_t *block, int dst_reg, int src_reg, int shift) codegen_addlong(block, OPCODE_VSHRN | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM_32(16-shift)); } +void host_arm_VSQRT_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VSQRT_D | Vd(dest_reg) | Vm(src_reg)); +} + void host_arm_VSTR_D(codeblock_t *block, int src_reg, int base_reg, int offset) { if ((offset > 1020) || (offset & 3)) diff --git a/src/codegen_backend_arm_ops.h b/src/codegen_backend_arm_ops.h index edfbbc1..542dc2a 100644 --- a/src/codegen_backend_arm_ops.h +++ b/src/codegen_backend_arm_ops.h @@ -139,6 +139,8 @@ 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_VABS_D(codeblock_t *block, int dest_reg, int src_reg); + void host_arm_VADD_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); void host_arm_VADD_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); void host_arm_VADD_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); @@ -154,6 +156,8 @@ void host_arm_VCGT_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_re void host_arm_VCGT_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); void host_arm_VCGT_S32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCHS_D(codeblock_t *block, int dest_reg, int src_reg); + void host_arm_VCVT_D_IS(codeblock_t *block, int dest_reg, int src_reg); void host_arm_VCVT_D_S(codeblock_t *block, int dest_reg, int src_reg); void host_arm_VCVT_IS_D(codeblock_t *block, int dest_reg, int src_reg); @@ -179,6 +183,8 @@ void host_arm_VMUL_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg void host_arm_VMUL_S16(codeblock_t *block, int dest_reg, int src_reg_n, int src_reg_m); void host_arm_VMULL_S16(codeblock_t *block, int dest_reg, int src_reg_n, int src_reg_m); +void host_arm_VNEG_D(codeblock_t *block, int dest_reg, int src_reg); + void host_arm_VORR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); void host_arm_VPADDL_S16(codeblock_t *block, int dst_reg, int src_reg); diff --git a/src/codegen_backend_arm_uops.c b/src/codegen_backend_arm_uops.c index c63a370..a9ce03e 100644 --- a/src/codegen_backend_arm_uops.c +++ b/src/codegen_backend_arm_uops.c @@ -693,6 +693,69 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FABS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VABS_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VNEG_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VSQRT_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VSUB_D(block, REG_D_TEMP, REG_D_TEMP, REG_D_TEMP); + host_arm_VCMP_D(block, src_reg_a, REG_D_TEMP); + host_arm_MOV_IMM(block, dest_reg, 0); + host_arm_VMRS_APSR(block); + host_arm_ORREQ_IMM(block, dest_reg, dest_reg, C3); + host_arm_ORRCC_IMM(block, dest_reg, dest_reg, C0); + host_arm_ORRVS_IMM(block, dest_reg, dest_reg, C0|C2|C3); + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + 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); @@ -2688,6 +2751,11 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_FMUL & UOP_MASK] = codegen_FMUL, [UOP_FSUB & UOP_MASK] = codegen_FSUB, + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, diff --git a/src/codegen_backend_x86-64_ops.c b/src/codegen_backend_x86-64_ops.c index ed57f2a..4ec3fd4 100644 --- a/src/codegen_backend_x86-64_ops.c +++ b/src/codegen_backend_x86-64_ops.c @@ -548,6 +548,11 @@ void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, (shift << 6) | ((src_reg_b & 7) << 3) | (src_reg_a & 7)); } +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXSD dst_reg, src_reg*/ +} + void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); @@ -1571,6 +1576,11 @@ void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ } +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSD dst_reg, src_reg*/ +} + void host_x86_SUB8_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)) diff --git a/src/codegen_backend_x86-64_ops.h b/src/codegen_backend_x86-64_ops.h index 35510d0..10fe26a 100644 --- a/src/codegen_backend_x86-64_ops.h +++ b/src/codegen_backend_x86-64_ops.h @@ -71,6 +71,8 @@ void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); @@ -236,6 +238,8 @@ void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift); void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift); void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); diff --git a/src/codegen_backend_x86-64_uops.c b/src/codegen_backend_x86-64_uops.c index faf5c33..dc87d53 100644 --- a/src/codegen_backend_x86-64_uops.c +++ b/src/codegen_backend_x86-64_uops.c @@ -548,6 +548,78 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FABS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && dest_reg == src_reg_a) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, dest_reg); + host_x86_MAXSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_PXOR_XREG_XREG(block, dest_reg, dest_reg); + host_x86_SUBSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_SQRTSD_XREG_XREG(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + 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); @@ -2288,6 +2360,11 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_FMUL & UOP_MASK] = codegen_FMUL, [UOP_FSUB & UOP_MASK] = codegen_FSUB, + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, diff --git a/src/codegen_backend_x86_ops.c b/src/codegen_backend_x86_ops.c index 33dc124..a861d14 100644 --- a/src/codegen_backend_x86_ops.c +++ b/src/codegen_backend_x86_ops.c @@ -513,6 +513,11 @@ void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (shift << 6) | (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b * (1 << shift)]*/ } +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXSD dst_reg, src_reg*/ +} + void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) { int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); @@ -1397,6 +1402,11 @@ void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ } +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addbyte4(block, 0xf2, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSD dst_reg, src_reg*/ +} + void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data) { if (dst_reg != src_reg) diff --git a/src/codegen_backend_x86_ops.h b/src/codegen_backend_x86_ops.h index 5084c5e..d07b0d9 100644 --- a/src/codegen_backend_x86_ops.h +++ b/src/codegen_backend_x86_ops.h @@ -75,6 +75,8 @@ void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg_a, uint32 void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); @@ -239,6 +241,8 @@ void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift); void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift); void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t imm_data); void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint16_t imm_data); void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm_data); diff --git a/src/codegen_backend_x86_uops.c b/src/codegen_backend_x86_uops.c index a5ff9d9..20f39a7 100644 --- a/src/codegen_backend_x86_uops.c +++ b/src/codegen_backend_x86_uops.c @@ -559,6 +559,78 @@ static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) return 0; } +static int codegen_FABS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && dest_reg == src_reg_a) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, dest_reg); + host_x86_MAXSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_PXOR_XREG_XREG(block, dest_reg, dest_reg); + host_x86_SUBSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_SQRTSD_XREG_XREG(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(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); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + 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); @@ -2297,6 +2369,11 @@ const uOpFn uop_handlers[UOP_MAX] = [UOP_FMUL & UOP_MASK] = codegen_FMUL, [UOP_FSUB & UOP_MASK] = codegen_FSUB, [UOP_FCOM & UOP_MASK] = codegen_FCOM, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h index 4a32aa7..15b3014 100644 --- a/src/codegen_ir_defs.h +++ b/src/codegen_ir_defs.h @@ -187,6 +187,14 @@ #define UOP_FDIV (UOP_TYPE_PARAMS_REGS | 0x84) /*UOP_FCOM - dest_reg = flags from compare(src_reg_a, src_reg_b)*/ #define UOP_FCOM (UOP_TYPE_PARAMS_REGS | 0x85) +/*UOP_FABS - dest_reg = fabs(src_reg_a)*/ +#define UOP_FABS (UOP_TYPE_PARAMS_REGS | 0x86) +/*UOP_FCHS - dest_reg = fabs(src_reg_a)*/ +#define UOP_FCHS (UOP_TYPE_PARAMS_REGS | 0x87) +/*UOP_FTST - dest_reg = flags from compare(src_reg_a, 0)*/ +#define UOP_FTST (UOP_TYPE_PARAMS_REGS | 0x88) +/*UOP_FSQRT - dest_reg = fsqrt(src_reg_a)*/ +#define UOP_FSQRT (UOP_TYPE_PARAMS_REGS | 0x89) /*UOP_MMX_ENTER - must be called before any MMX registers accessed*/ #define UOP_MMX_ENTER (UOP_TYPE_PARAMS_IMM | 0x90 | UOP_TYPE_BARRIER) @@ -582,6 +590,11 @@ static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, #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_FABS(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FABS, ir, dst_reg, src_reg) +#define uop_FCHS(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FCHS, ir, dst_reg, src_reg) +#define uop_FSQRT(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FSQRT, ir, dst_reg, src_reg) +#define uop_FTST(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FTST, ir, dst_reg, src_reg) + #define uop_FP_ENTER(ir) do { if (!codegen_fpu_entered) uop_gen_imm(UOP_FP_ENTER, ir, cpu_state.oldpc); codegen_fpu_entered = 1; codegen_mmx_entered = 0; } while (0) #define uop_MMX_ENTER(ir) do { if (!codegen_mmx_entered) uop_gen_imm(UOP_MMX_ENTER, ir, cpu_state.oldpc); codegen_mmx_entered = 1; codegen_fpu_entered = 0; } while (0) diff --git a/src/codegen_ops.c b/src/codegen_ops.c index 00e4018..8dc433a 100644 --- a/src/codegen_ops.c +++ b/src/codegen_ops.c @@ -184,8 +184,8 @@ RecompOpFn recomp_opcodes_d9[512] = /*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, /*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, -/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, -/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFCHS, ropFABS, NULL, NULL, ropFTST, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSQRT, NULL, NULL, NULL, NULL, NULL, /*32-bit data*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -206,8 +206,8 @@ RecompOpFn recomp_opcodes_d9[512] = /*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, /*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, -/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, -/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFCHS, ropFABS, NULL, NULL, ropFTST, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSQRT, NULL, NULL, NULL, NULL, NULL, }; RecompOpFn recomp_opcodes_da[512] = diff --git a/src/codegen_ops_fpu_arith.c b/src/codegen_ops_fpu_arith.c index d903959..9d4259c 100644 --- a/src/codegen_ops_fpu_arith.c +++ b/src/codegen_ops_fpu_arith.c @@ -534,3 +534,39 @@ uint32_t ropFISUBR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, ui ropFI_arith_mem(l, IREG_temp0) ropFI_arith_mem(w, IREG_temp0_W) + + +uint32_t ropFABS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FABS(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} + +uint32_t ropFCHS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FCHS(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FSQRT(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFTST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FTST(ir, IREG_temp0_W, IREG_ST(0)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + + return op_pc; +} diff --git a/src/codegen_ops_fpu_arith.h b/src/codegen_ops_fpu_arith.h index e61d4ae..60ae273 100644 --- a/src/codegen_ops_fpu_arith.h +++ b/src/codegen_ops_fpu_arith.h @@ -56,3 +56,8 @@ uint32_t ropFISUBl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t f uint32_t ropFISUBw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropFISUBRl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); uint32_t ropFISUBRw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFABS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCHS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFTST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc);