From dd2a608707ead03bc84d117eac115f7c4f4117ad Mon Sep 17 00:00:00 2001 From: SarahW Date: Sun, 18 Sep 2016 14:57:10 +0100 Subject: [PATCH] x86-32 recompiler performs float->integer rounding by loading FPU control word instead of calling helper function - speedup on some stuff. --- src/codegen_ops_fpu.h | 1 + src/codegen_ops_x86-64.h | 4 + src/codegen_ops_x86.h | 251 +++++++++++---------------------------- src/codegen_x86.c | 5 + src/ibm.h | 2 + src/x87_ops_misc.h | 7 ++ 6 files changed, 88 insertions(+), 182 deletions(-) diff --git a/src/codegen_ops_fpu.h b/src/codegen_ops_fpu.h index 2349a0c..eca1587 100644 --- a/src/codegen_ops_fpu.h +++ b/src/codegen_ops_fpu.h @@ -580,6 +580,7 @@ static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint MEM_LOAD_ADDR_EA_W(target_seg); STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.npxc, 0); + UPDATE_NPXC(0); return op_pc + 1; } diff --git a/src/codegen_ops_x86-64.h b/src/codegen_ops_x86-64.h index 1557171..33dd6a2 100644 --- a/src/codegen_ops_x86-64.h +++ b/src/codegen_ops_x86-64.h @@ -4556,6 +4556,10 @@ static void FP_COMPARE_IL() FP_COMPARE_MEM(); } +static void UPDATE_NPXC(int reg) +{ +} + static void SET_BITS(uintptr_t addr, uint32_t val) { if (IS_32_ADDR(addr)) diff --git a/src/codegen_ops_x86.h b/src/codegen_ops_x86.h index fc4d60f..0013546 100644 --- a/src/codegen_ops_x86.h +++ b/src/codegen_ops_x86.h @@ -2173,82 +2173,6 @@ static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) *host_reg2 = REG_ECX; } - -static double _fp_half = 0.5; - -static void FP_LOAD_ROUNDING() -{ - pclog("cpu_state.npxc %04x\n", cpu_state.npxc); - addbyte(0x8b); /*MOV EDX, npxc*/ - addbyte(0x15); - addlong((uintptr_t)&cpu_state.npxc); - addbyte(0xd9); /*FSTCW [ESP+8]*/ - addbyte(0x7c); - addbyte(0x24); - addbyte(0x08); - addbyte(0x89); /*MOV [ESP+12],EDX*/ - addbyte(0x54); - addbyte(0x24); - addbyte(0x0c); - addbyte(0xd9); /*FLDCW [ESP+12]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x0c); -} -static void FP_RESTORE_ROUNDING() -{ - addbyte(0xd9); /*FLDCW [ESP+8]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x08); -} - -static int32_t x87_fround32(double b) -{ - int64_t a, c; - - switch ((cpu_state.npxc >> 10) & 3) - { - case 0: /*Nearest*/ - a = (int64_t)floor(b); - c = (int64_t)floor(b + 1.0); - if ((b - a) < (c - b)) - return a; - else if ((b - a) > (c - b)) - return c; - else - return (a & 1) ? c : a; - case 1: /*Down*/ - return (int32_t)floor(b); - case 2: /*Up*/ - return (int32_t)ceil(b); - case 3: /*Chop*/ - return (int32_t)b; - } -} -static int64_t x87_fround64(double b) -{ - int64_t a, c; - - switch ((cpu_state.npxc >> 10) & 3) - { - case 0: /*Nearest*/ - a = (int64_t)floor(b); - c = (int64_t)floor(b + 1.0); - if ((b - a) < (c - b)) - return a; - else if ((b - a) > (c - b)) - return c; - else - return (a & 1) ? c : a; - case 1: /*Down*/ - return (int64_t)floor(b); - case 2: /*Up*/ - return (int64_t)ceil(b); - case 3: /*Chop*/ - return (int64_t)b; - } -} static int FP_LOAD_REG_INT_W(int reg) { addbyte(0x8b); /*MOV EBX, TOP*/ @@ -2268,25 +2192,19 @@ static int FP_LOAD_REG_INT_W(int reg) addbyte(0xdd); addbyte(cpu_state_offset(ST)); - addbyte(0x89); /*MOV [ESP+8], EAX*/ - addbyte(0x44); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); + addbyte(0xdb); /*FISTP [ESP]*/ + addbyte(0x1c); addbyte(0x24); - addbyte(0x08); - - addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); - CALL_FUNC(x87_fround32); - - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x8b); /*MOV EAX, [ESP+8]*/ - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - return REG_EBX; } static int FP_LOAD_REG_INT(int reg) @@ -2308,25 +2226,19 @@ static int FP_LOAD_REG_INT(int reg) addbyte(0xdd); addbyte(cpu_state_offset(ST)); - addbyte(0x89); /*MOV [ESP+8], EAX*/ - addbyte(0x44); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); + addbyte(0xdb); /*FISTP [ESP]*/ + addbyte(0x1c); addbyte(0x24); - addbyte(0x08); - - addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); - CALL_FUNC(x87_fround32); - - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x8b); /*MOV EAX, [ESP+8]*/ - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - return REG_EBX; } static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) @@ -2378,34 +2290,29 @@ static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) addbyte(cpu_state_offset(MM)); addbyte(0xeb); /*JMP done*/ - addbyte(4+4+3+5+2+2+4); + addbyte(4+3+3+3+3+4); addbyte(0xdd); /*FLD ST[EBX*8]*/ addbyte(0x44); addbyte(0xdd); addbyte(cpu_state_offset(ST)); - addbyte(0x89); /*MOV [ESP+8], EAX*/ - addbyte(0x44); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); + addbyte(0xdf); /*FISTPQ [ESP]*/ + addbyte(0x3c); addbyte(0x24); - addbyte(0x08); - - addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ addbyte(0x1c); addbyte(0x24); - - CALL_FUNC(x87_fround64); - - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x89); /*MOV ECX, EDX*/ - addbyte(0xd1); - - addbyte(0x8b); /*MOV EAX, [ESP+8]*/ - addbyte(0x44); + addbyte(0x8b); /*MOV ECX, 4[ESP]*/ + addbyte(0x4c); addbyte(0x24); - addbyte(0x08); + addbyte(4); *host_reg1 = REG_EBX; *host_reg2 = REG_ECX; @@ -2511,31 +2418,9 @@ static void FP_OP_D(int op) addbyte(0x04); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0x9b); /*FSTCW [ESP+8]*/ - addbyte(0xd9); - addbyte(0x7c); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*MOV AX, [ESP+8]*/ - addbyte(0x8b); - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*AND AX, ~(3 << 10)*/ - addbyte(0x25); - addword(~(3 << 10)); - addbyte(0x66); /*OR AX, npxc & (3 << 10)*/ - addbyte(0x0d); - addword(cpu_state.npxc & (3 << 10)); - addbyte(0x66); /*MOV [ESP+12], AX*/ - addbyte(0x89); - addbyte(0x44); - addbyte(0x24); - addbyte(0x0c); - addbyte(0xd9); /*FLDCW [ESP+12]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x0c); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); } addbyte(0xdd); /*FLD ST[dst][EBP]*/ addbyte(0x45); @@ -2552,10 +2437,9 @@ static void FP_OP_D(int op) addbyte(cpu_state_offset(ST[cpu_state.TOP])); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0xd9); /*FLDCW [ESP+8]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x08); + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); } } else @@ -2568,31 +2452,9 @@ static void FP_OP_D(int op) addbyte(0x24); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0x9b); /*FSTCW [ESP+8]*/ - addbyte(0xd9); - addbyte(0x7c); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*MOV AX, [ESP+8]*/ - addbyte(0x8b); - addbyte(0x44); - addbyte(0x24); - addbyte(0x08); - addbyte(0x66); /*AND AX, ~(3 << 10)*/ - addbyte(0x25); - addword(~(3 << 10)); - addbyte(0x66); /*OR AX, npxc & (3 << 10)*/ - addbyte(0x0d); - addword(cpu_state.npxc & (3 << 10)); - addbyte(0x66); /*MOV [ESP+12], AX*/ - addbyte(0x89); - addbyte(0x44); - addbyte(0x24); - addbyte(0x0c); - addbyte(0xd9); /*FLDCW [ESP+12]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x0c); + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(new_npxc)); } addbyte(0x89); /*MOV [ESP+4], EDX*/ addbyte(0x54); @@ -2616,10 +2478,9 @@ static void FP_OP_D(int op) addbyte(cpu_state_offset(ST)); if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) { - addbyte(0xd9); /*FLDCW [ESP+8]*/ - addbyte(0x6c); - addbyte(0x24); - addbyte(0x08); + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte(cpu_state_offset(old_npxc)); } } } @@ -3226,6 +3087,32 @@ static void FP_COMPARE_REG(int dst, int src) } } +static void UPDATE_NPXC(int reg) +{ + addbyte(0x66); /*AND cpu_state.new_npxc, ~0xc00*/ + addbyte(0x81); + addbyte(0x65); + addbyte(cpu_state_offset(new_npxc)); + addword(~0xc00); + if (reg) + { + addbyte(0x66); /*AND reg, 0xc00*/ + addbyte(0x81); + addbyte(0xe0 | reg); + addword(0xc00); + } + else + { + addbyte(0x66); /*AND AX, 0xc00*/ + addbyte(0x25); + addword(0xc00); + } + addbyte(0x66); /*OR cpu_state.new_npxc, reg*/ + addbyte(0x09); + addbyte(0x45 | (reg << 3)); + addbyte(cpu_state_offset(new_npxc)); +} + static int ZERO_EXTEND_W_B(int reg) { addbyte(0x0f); /*MOVZX regl, regb*/ diff --git a/src/codegen_x86.c b/src/codegen_x86.c index 736cb7e..d4ca3db 100644 --- a/src/codegen_x86.c +++ b/src/codegen_x86.c @@ -563,6 +563,11 @@ void codegen_init() mem_store_addr_ea_b = gen_MEM_STORE_ADDR_EA_B(); block_pos = 1024; mem_store_addr_ea_q = gen_MEM_STORE_ADDR_EA_Q(); + + asm( + "fstcw %0\n" + : "=m" (cpu_state.old_npxc) + ); } void codegen_reset() diff --git a/src/ibm.h b/src/ibm.h index 62f9379..9c85b02 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -163,6 +163,8 @@ struct uint16_t MM_w4[8]; MMX_REG MM[8]; + + uint16_t old_npxc, new_npxc; } cpu_state; #define cycles cpu_state._cycles diff --git a/src/x87_ops_misc.h b/src/x87_ops_misc.h index afdf136..f40b932 100644 --- a/src/x87_ops_misc.h +++ b/src/x87_ops_misc.h @@ -32,6 +32,7 @@ static int opFINIT(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); cpu_state.npxs = 0; *(uint64_t *)cpu_state.tag = 0x0303030303030303ll; cpu_state.TOP = 0; @@ -85,6 +86,7 @@ static int FSTOR() case 0x000: /*16-bit real mode*/ case 0x001: /*16-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -93,6 +95,7 @@ static int FSTOR() case 0x100: /*32-bit real mode*/ case 0x101: /*32-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -665,6 +668,7 @@ static int FLDENV() case 0x000: /*16-bit real mode*/ case 0x001: /*16-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -672,6 +676,7 @@ static int FLDENV() case 0x100: /*32-bit real mode*/ case 0x101: /*32-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -705,6 +710,7 @@ static int opFLDCW_a16(uint32_t fetchdat) tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); CLOCK_CYCLES(4); return 0; } @@ -717,6 +723,7 @@ static int opFLDCW_a32(uint32_t fetchdat) tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); CLOCK_CYCLES(4); return 0; }