x86-32 recompiler performs float->integer rounding by loading FPU control word instead of calling helper function - speedup on some stuff.

This commit is contained in:
SarahW 2016-09-18 14:57:10 +01:00
commit dd2a608707
6 changed files with 88 additions and 182 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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