mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 13:00:15 +02:00
Merge pull request #4811 from pmatos/fix/SPEC_GCC-C-execute-ieee-fp-cmp-8l
Fix IEEE 754 unordered comparison detection in x87 floating-point operations
This commit is contained in:
8 files changed
+531
-222
No files matched your search
@@ -294,7 +294,11 @@ struct FEX_PACKED X80SoftFloat {
|
||||
FCMP(softfloat_state* state, const X80SoftFloat& lhs, const X80SoftFloat& rhs, bool* eq, bool* lt, bool* nan) {
|
||||
*eq = extF80_eq(state, lhs, rhs);
|
||||
*lt = extF80_lt(state, lhs, rhs);
|
||||
*nan = IsNan(lhs) || IsNan(rhs);
|
||||
|
||||
// Use IEEE 754 semantics: unordered if neither <, =, nor > is true
|
||||
// This is more reliable than custom NaN detection
|
||||
bool gt = !(*eq) && !(*lt) && extF80_le(state, rhs, lhs);
|
||||
*nan = !(*eq) && !(*lt) && !gt;
|
||||
}
|
||||
|
||||
FEXCORE_PRESERVE_ALL_ATTR static X80SoftFloat FSCALE(softfloat_state* state, const X80SoftFloat& lhs, const X80SoftFloat& rhs) {
|
||||
|
||||
@@ -680,6 +680,9 @@ void OpDispatchBuilder::FCOMI(OpcodeArgs, IR::OpSize Width, bool Integer, OpDisp
|
||||
SetRFLAG<FEXCore::X86State::RFLAG_PF_RAW_LOC>(PF);
|
||||
}
|
||||
|
||||
// Set Invalid Operation flag when unordered (NaN comparison)
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_IE_LOC>(HostFlag_Unordered);
|
||||
|
||||
if (PopTwice) {
|
||||
_PopStackDestroy();
|
||||
_PopStackDestroy();
|
||||
@@ -701,6 +704,9 @@ void OpDispatchBuilder::FTST(OpcodeArgs) {
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C1_LOC>(Constant(0));
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C2_LOC>(HostFlag_Unordered);
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_C3_LOC>(HostFlag_ZF);
|
||||
|
||||
// Set Invalid Operation flag when unordered (NaN comparison)
|
||||
SetRFLAG<FEXCore::X86State::X87FLAG_IE_LOC>(HostFlag_Unordered);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::X87OpHelper(OpcodeArgs, FEXCore::IR::IROps IROp, bool ZeroC2) {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0xcafecafe"
|
||||
},
|
||||
"Mode": "32BIT"
|
||||
}
|
||||
%endif
|
||||
|
||||
; IsNan() couldn't detect negative NaNs (sign bit set in exponent field).
|
||||
; This caused __builtin_isunordered() to return wrong values.
|
||||
|
||||
mov esp, 0xe000_1000
|
||||
|
||||
; Test 1: __builtin_isunordered(1.0, 2.0) should return 0
|
||||
; Pattern: fucomip + setp + test for 0
|
||||
fld1
|
||||
lea edx, [two]
|
||||
fld tword [edx]
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jnz test_failed ; If not 0, test failed (should be ordered)
|
||||
|
||||
; Test 2: __builtin_isunordered(1.0, NaN) should return 1
|
||||
fld1
|
||||
lea edx, [qnan]
|
||||
fld tword [edx]
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jz test_failed ; If 0, test failed (should be unordered)
|
||||
|
||||
; Test 3: __builtin_isunordered(NaN, 1.0) should return 1
|
||||
lea edx, [qnan]
|
||||
fld tword [edx]
|
||||
fld1
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jz test_failed ; If 0, test failed (should be unordered)
|
||||
|
||||
; Test 4: __builtin_isunordered(2.0, 2.0) should return 0 (equal case)
|
||||
lea edx, [two]
|
||||
fld tword [edx]
|
||||
lea edx, [two]
|
||||
fld tword [edx]
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jnz test_failed ; If not 0, test failed (should be ordered)
|
||||
|
||||
; All tests passed
|
||||
mov eax, 0xcafecafe
|
||||
hlt
|
||||
|
||||
test_failed:
|
||||
; Test failed
|
||||
mov eax, 0xdeadbeef
|
||||
hlt
|
||||
|
||||
align 8
|
||||
two:
|
||||
dt 2.0
|
||||
|
||||
align 8
|
||||
qnan:
|
||||
dq 0xC000000000000000 ; Quiet NaN with only quiet bit set (no bottom 62 bits) - this breaks IsNan
|
||||
dw 0x7FFF ; Standard NaN exponent (0x7FFF)
|
||||
@@ -0,0 +1,72 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0x0000000cafecafe"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
; IsNan() couldn't detect negative NaNs (sign bit set in exponent field).
|
||||
; This caused __builtin_isunordered() to return wrong values.
|
||||
|
||||
mov rsp, 0xe000_1000
|
||||
|
||||
; Test 1: __builtin_isunordered(1.0, 2.0) should return 0
|
||||
; Pattern: fucomip + setp + test for 0
|
||||
fld1
|
||||
lea rdx, [rel two]
|
||||
fld tword [rdx]
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jnz test_failed ; If not 0, test failed (should be ordered)
|
||||
|
||||
; Test 2: __builtin_isunordered(1.0, NaN) should return 1
|
||||
fld1
|
||||
lea rdx, [rel qnan]
|
||||
fld tword [rdx]
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jz test_failed ; If 0, test failed (should be unordered)
|
||||
|
||||
; Test 3: __builtin_isunordered(NaN, 1.0) should return 1
|
||||
lea rdx, [rel qnan]
|
||||
fld tword [rdx]
|
||||
fld1
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jz test_failed ; If 0, test failed (should be unordered)
|
||||
|
||||
; Test 4: __builtin_isunordered(2.0, 2.0) should return 0 (equal case)
|
||||
lea rdx, [rel two]
|
||||
fld tword [rdx]
|
||||
lea rdx, [rel two]
|
||||
fld tword [rdx]
|
||||
fucomip st1
|
||||
setp al
|
||||
movzx eax, al
|
||||
test eax, eax
|
||||
jnz test_failed ; If not 0, test failed (should be ordered)
|
||||
|
||||
; All tests passed
|
||||
mov rax, 0xcafecafe
|
||||
hlt
|
||||
|
||||
test_failed:
|
||||
; Test failed
|
||||
mov rax, 0xdeadbeef
|
||||
hlt
|
||||
|
||||
align 8
|
||||
two:
|
||||
dt 2.0
|
||||
|
||||
align 8
|
||||
qnan:
|
||||
dq 0xC000000000000000 ; Quiet NaN with only quiet bit set (no bottom 62 bits) - this breaks IsNan
|
||||
dw 0x7FFF ; Standard NaN exponent (0x7FFF)
|
||||
@@ -14,7 +14,7 @@
|
||||
"Instructions": {
|
||||
"Block1": {
|
||||
"x86InstructionCount": 70,
|
||||
"ExpectedInstructionCount": 415,
|
||||
"ExpectedInstructionCount": 416,
|
||||
"x86Insts": [
|
||||
"sub esp,0x2c",
|
||||
"mov ecx,dword [esp + 0x34]",
|
||||
@@ -475,6 +475,7 @@
|
||||
"rmif x21, #63, #nzCv",
|
||||
"rmif x22, #62, #nZcv",
|
||||
"eor w26, w20, #0x1",
|
||||
"strb w20, [x28, #1008]",
|
||||
"ldrb w20, [x28, #1019]",
|
||||
"sub w20, w20, #0x3 (3)",
|
||||
"and w20, w20, #0x7",
|
||||
@@ -507,7 +508,7 @@
|
||||
},
|
||||
"Block2": {
|
||||
"x86InstructionCount": 37,
|
||||
"ExpectedInstructionCount": 213,
|
||||
"ExpectedInstructionCount": 217,
|
||||
"x86Insts": [
|
||||
"sub esp,0x1c",
|
||||
"mov edx,dword [esp + 0x20]",
|
||||
@@ -585,10 +586,11 @@
|
||||
"ubfx x22, x20, #0, #1",
|
||||
"ubfx x20, x20, #2, #1",
|
||||
"orr w21, w21, w20",
|
||||
"orr w20, w22, w20",
|
||||
"orr w22, w22, w20",
|
||||
"eor x21, x21, #0x1",
|
||||
"rmif x21, #63, #nzCv",
|
||||
"rmif x20, #62, #nZcv",
|
||||
"rmif x22, #62, #nZcv",
|
||||
"strb w20, [x28, #1008]",
|
||||
"csetm x20, ls",
|
||||
"dup v4.2d, x20",
|
||||
"bsl v4.16b, v3.16b, v2.16b",
|
||||
@@ -625,10 +627,11 @@
|
||||
"ubfx x22, x20, #0, #1",
|
||||
"ubfx x20, x20, #2, #1",
|
||||
"orr w21, w21, w20",
|
||||
"orr w20, w22, w20",
|
||||
"orr w22, w22, w20",
|
||||
"eor x21, x21, #0x1",
|
||||
"rmif x21, #63, #nzCv",
|
||||
"rmif x20, #62, #nZcv",
|
||||
"rmif x22, #62, #nZcv",
|
||||
"strb w20, [x28, #1008]",
|
||||
"csetm x20, ls",
|
||||
"dup v5.2d, x20",
|
||||
"bsl v5.16b, v3.16b, v2.16b",
|
||||
@@ -665,10 +668,11 @@
|
||||
"ubfx x22, x20, #0, #1",
|
||||
"ubfx x20, x20, #2, #1",
|
||||
"orr w21, w21, w20",
|
||||
"orr w20, w22, w20",
|
||||
"orr w22, w22, w20",
|
||||
"eor x21, x21, #0x1",
|
||||
"rmif x21, #63, #nzCv",
|
||||
"rmif x20, #62, #nZcv",
|
||||
"rmif x22, #62, #nZcv",
|
||||
"strb w20, [x28, #1008]",
|
||||
"csetm x20, ls",
|
||||
"dup v6.2d, x20",
|
||||
"bsl v6.16b, v3.16b, v2.16b",
|
||||
@@ -737,6 +741,7 @@
|
||||
"rmif x21, #63, #nzCv",
|
||||
"rmif x22, #62, #nZcv",
|
||||
"eor w26, w20, #0x1",
|
||||
"strb w20, [x28, #1008]",
|
||||
"ldrb w20, [x28, #1019]",
|
||||
"sub w20, w20, #0x2 (2)",
|
||||
"and w20, w20, #0x7",
|
||||
@@ -1202,7 +1207,7 @@
|
||||
},
|
||||
"Block5": {
|
||||
"x86InstructionCount": 49,
|
||||
"ExpectedInstructionCount": 299,
|
||||
"ExpectedInstructionCount": 300,
|
||||
"x86Insts": [
|
||||
"fld dword [esp + 0x80]",
|
||||
"fsub dword [esp + 0x7c]",
|
||||
@@ -1534,6 +1539,7 @@
|
||||
"rmif x21, #63, #nzCv",
|
||||
"rmif x22, #62, #nZcv",
|
||||
"eor w26, w20, #0x1",
|
||||
"strb w20, [x28, #1008]",
|
||||
"cset x20, hi",
|
||||
"strb w20, [x8, #48]",
|
||||
"ldrb w4, [x8, #48]",
|
||||
@@ -1558,7 +1564,7 @@
|
||||
},
|
||||
"Block6": {
|
||||
"x86InstructionCount": 39,
|
||||
"ExpectedInstructionCount": 295,
|
||||
"ExpectedInstructionCount": 296,
|
||||
"x86Insts": [
|
||||
"push ebp",
|
||||
"push edi",
|
||||
@@ -1864,6 +1870,7 @@
|
||||
"rmif x21, #63, #nzCv",
|
||||
"rmif x22, #62, #nZcv",
|
||||
"eor w26, w20, #0x1",
|
||||
"strb w20, [x28, #1008]",
|
||||
"ldrb w20, [x28, #1019]",
|
||||
"sub w20, w20, #0x4 (4)",
|
||||
"and w20, w20, #0x7",
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,3 @@
|
||||
pr72867.c.gcc-target-test-32.n500.gcc-target-32
|
||||
pr72867.c.gcc-target-test-32.n1.gcc-target-32
|
||||
|
||||
sse2-mmx-pextrw.c.gcc-target-test-32.n500.gcc-target-32
|
||||
sse2-mmx-pextrw.c.gcc-target-test-32.n1.gcc-target-32
|
||||
|
||||
|
||||
Reference in new issue
Block a user