Skip to content

Commit

Permalink
Merge pull request #4101 from Sonicadvance1/fprem_fixes
Browse files Browse the repository at this point in the history
Fixes fprem
  • Loading branch information
Sonicadvance1 authored Oct 3, 2024
2 parents 5e9c211 + 16869d8 commit b89f5b8
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 8 deletions.
26 changes: 25 additions & 1 deletion FEXCore/Source/Common/SoftFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,31 @@ struct FEX_PACKED X80SoftFloat {

return Result;
#else
return extF80_rem(state, lhs, rhs);
/*
* FPREM is not an IEEE-754 remainder. From the spec:
*
* Computes the remainder obtained from dividing the value in the ST(0)
* register (the dividend) by the value in the ST(1) register (the divisor
* or modulus), and stores the result in ST(0). The remainder represents the
* following value:
*
* Remainder := ST(0) − (Q * ST(1))
*
* Here, Q is an integer value that is obtained by truncating the
* floating-point number quotient of [ST(0) / ST(1)] toward zero.
*
* We implement this sequence literally. softfloat_round_minMag means
* "truncate towards zero".
*/
extFloat80_t quotient = extF80_div(state, lhs, rhs);
extFloat80_t Q = extF80_roundToInt(state, quotient, softfloat_round_minMag, true);
bool Q_zero = Q.signif == 0 && (Q.signExp & ~(1 << 15)) == 0;

if (Q_zero) {
return lhs;
} else {
return extF80_sub(state, lhs, extF80_mul(state, Q, rhs));
}
#endif
}

Expand Down
86 changes: 86 additions & 0 deletions unittests/ASM/FEX_bugs/x87_fprem.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "0x41582d3bc0000000",
"RBX": "0x41582d3bc0000000",
"RCX": "0xc1582d3bc0000000",
"RDX": "0xc1582d3bc0000000",
"RDI": "0x42d2f6b36dfc3bc0",
"RSI": "0x42d2f6b36dfc3bc0",
"RBP": "0xc2d2f6b36dfc3bc0",
"RSP": "0xc2d2f6b36dfc3bc0"
}
}
%endif

; FEX-Emu had a bug in the fprem implementation where it was behaving like fprem1
; Do a handful of large fprem operations to ensure it works correctly.

; 64-bit float memory locations
; doremainder <result>, <src1>, <src2>
%macro doremainder 3
; Load big number and divisor
fld qword %3
fld qword %2

; For large remainders, x86 fprem computes partial remainders and needs to run multiple times.
%%again:
; Get the remainder
fprem
; Check if we need to run again
fnstsw ax
test ah, 0x4
jne %%again

; Pop one value
fstp st1

; Store the result
fstp qword %1
%endmacro

; Do a handful of remainder checks with different sign combinations.
doremainder [rel .data_result + (8 * 0)], [rel .data_big], [rel .data_divisor]
doremainder [rel .data_result + (8 * 1)], [rel .data_big], [rel .data_divisor_negative]
doremainder [rel .data_result + (8 * 2)], [rel .data_big_negative], [rel .data_divisor]
doremainder [rel .data_result + (8 * 3)], [rel .data_big_negative], [rel .data_divisor_negative]

; Test infinities as well
doremainder [rel .data_result + (8 * 4)], [rel .data_big], [rel .data_inf]
doremainder [rel .data_result + (8 * 5)], [rel .data_big], [rel .data_inf_negative]
doremainder [rel .data_result + (8 * 6)], [rel .data_big_negative], [rel .data_inf]
doremainder [rel .data_result + (8 * 7)], [rel .data_big_negative], [rel .data_inf_negative]

; Load the results in to registers
mov rax, qword [rel .data_result + (8 * 0)]
mov rbx, qword [rel .data_result + (8 * 1)]
mov rcx, qword [rel .data_result + (8 * 2)]
mov rdx, qword [rel .data_result + (8 * 3)]
mov rdi, qword [rel .data_result + (8 * 4)]
mov rsi, qword [rel .data_result + (8 * 5)]
mov rbp, qword [rel .data_result + (8 * 6)]
mov rsp, qword [rel .data_result + (8 * 7)]

hlt

.data_big:
dq 83403126337775.0

.data_big_negative:
dq -83403126337775.0

.data_divisor:
dq 10000000.0

.data_divisor_negative:
dq -10000000.0

%define Inf __?Infinity?__
.data_inf:
dq Inf

.data_inf_negative:
dq -Inf

.data_result:
dq 0, 0, 0, 0, 0, 0, 0, 0
3 changes: 0 additions & 3 deletions unittests/ASM/Known_Failures_int

This file was deleted.

4 changes: 0 additions & 4 deletions unittests/ASM/Known_Failures_jit
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
# FPREM is incorrect
Test_X87/D9_F5_2.asm
Test_X87/D9_F5_3.asm

Test_FEX_bugs/32bit_syscall.asm

0 comments on commit b89f5b8

Please sign in to comment.