From e0a31e7fbcc730e54f55fdecdef6cf2fb185c92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 13 Oct 2026 22:15:09 +0200 Subject: [PATCH] VFPU: Generate the VFPU's NaN in vbfy, vocp and vsocp on all cores These are sums, so a NaN result is 0x7F800001 like vadd's (cpu/vfpu/specials). Co-Authored-By: Claude Opus 5.5 --- Core/MIPS/ARM/ArmCompVFPU.cpp | 2 ++ Core/MIPS/ARM64/Arm64CompVFPU.cpp | 6 ++++++ Core/MIPS/IR/IRCompVFPU.cpp | 8 ++++++++ Core/MIPS/InterpreterVFPU.cpp | 19 +++++++++---------- Core/MIPS/x86/CompVFPU.cpp | 6 ++++++ 5 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index dc52c2ace1..9fda9c0b86 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -2421,6 +2421,8 @@ namespace MIPSComp for (int i = 0; i < n; ++i) { fpr.MapDirtyInInV(tempregs[i], sregs[i], tregs[i]); VADD(fpr.V(tempregs[i]), fpr.V(tregs[i]), fpr.V(sregs[i])); + // A NaN comes out as the VFPU's (cpu/vfpu/specials). + EmitVfpuSumNaN(fpr.V(tempregs[i])); } for (int i = 0; i < n; ++i) { diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp index 76be460bca..d4fac41e31 100644 --- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp @@ -2422,6 +2422,8 @@ namespace MIPSComp { for (int i = 0; i < n; ++i) { fpr.MapDirtyInInV(tempregs[i], sregs[i], tregs[i]); fp.FADD(fpr.V(tempregs[i]), fpr.V(tregs[i]), fpr.V(sregs[i])); + // A NaN comes out as the VFPU's (cpu/vfpu/specials). + EmitVfpuSumNaN(fpr.V(tempregs[i])); } for (int i = 0; i < n; ++i) { @@ -2542,6 +2544,10 @@ namespace MIPSComp { fp.FSUB(S3, fpr.V(sregs[2]), fpr.V(sregs[3])); } } + // A NaN comes out as the VFPU's (cpu/vfpu/specials). + for (int i = 0; i < n; i++) { + EmitVfpuSumNaN((ARM64Reg)(S0 + i)); + } fpr.MapRegsAndSpillLockV(dregs, sz, MAP_NOINIT); for (int i = 0; i < n; i++) { diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 93aaafe1a8..7b8ebd6fe7 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -2503,10 +2503,13 @@ namespace MIPSComp { GetVectorRegsPrefixT(tregs, sz, _VS); GetVectorRegsPrefixD(dregs, sz, _VD); + // A NaN comes out as the VFPU's (cpu/vfpu/specials). if (IsVec4(sz, dregs) && IsVec4(sz, sregs) && IsVec4(sz, tregs)) { ir.Write(IROp::Vec4Add, dregs[0], tregs[0], sregs[0]); + ir.Write(IROp::Vec4VfpuNaN, dregs[0], dregs[0]); } else if (IsVec3of4(sz, dregs) && IsVec3of4(sz, sregs) && IsVec3of4(sz, tregs) && opts.preferVec4) { ir.Write(IROp::Vec4Add, IRVTEMP_0, tregs[0], sregs[0]); + ir.Write(IROp::Vec4VfpuNaN, IRVTEMP_0, IRVTEMP_0); ir.Write(IROp::Vec4Blend, dregs[0], dregs[0], IRVTEMP_0, 0x7); } else { u8 tempregs[4]; @@ -2520,6 +2523,7 @@ namespace MIPSComp { for (int i = 0; i < n; ++i) { ir.Write(IROp::FAdd, tempregs[i], tregs[i], sregs[i]); + ir.Write(IROp::FVfpuNaN, tempregs[i], tempregs[i]); } for (int i = 0; i < n; ++i) { if (dregs[i] != tempregs[i]) { @@ -2642,6 +2646,10 @@ namespace MIPSComp { INVALIDOP; } + // A NaN comes out as the VFPU's (cpu/vfpu/specials). + for (int i = 0; i < n; ++i) { + ir.Write(IROp::FVfpuNaN, tempregs[i], tempregs[i]); + } for (int i = 0; i < n; ++i) { if (tempregs[i] != dregs[i]) ir.Write(IROp::FMov, dregs[i], tempregs[i]); diff --git a/Core/MIPS/InterpreterVFPU.cpp b/Core/MIPS/InterpreterVFPU.cpp index 19f8a3eae0..041a434306 100644 --- a/Core/MIPS/InterpreterVFPU.cpp +++ b/Core/MIPS/InterpreterVFPU.cpp @@ -753,8 +753,8 @@ namespace MIPSInt ApplyPrefixST(mips, t, VFPURewritePrefix(mips, VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz); for (int i = 0; i < GetNumVectorElements(sz); i++) { - // Always positive NaN. Note that s is always negated from the registers. - d[i] = my_isnan(s[i]) ? fabsf(s[i]) : t[i] + s[i]; + // Note that s is always negated from the registers. + d[i] = VfpuSumNaN(t[i] + s[i]); } RetainInvalidSwizzleST(mips, d, sz); ApplyPrefixD(mips, d, sz); @@ -786,11 +786,11 @@ namespace MIPSInt ApplyPrefixST(mips, t, VFPURewritePrefix(mips, VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), outSize); // Essentially D prefix saturation is forced. - d[0] = nanclamp(t[0] + s[0], 0.0f, 1.0f); - d[1] = nanclamp(t[1] + s[1], 0.0f, 1.0f); + d[0] = nanclamp(VfpuSumNaN(t[0] + s[0]), 0.0f, 1.0f); + d[1] = nanclamp(VfpuSumNaN(t[1] + s[1]), 0.0f, 1.0f); if (outSize == V_Quad) { - d[2] = nanclamp(t[2] + s[2], 0.0f, 1.0f); - d[3] = nanclamp(t[3] + s[3], 0.0f, 1.0f); + d[2] = nanclamp(VfpuSumNaN(t[2] + s[2]), 0.0f, 1.0f); + d[3] = nanclamp(VfpuSumNaN(t[3] + s[3]), 0.0f, 1.0f); } ApplyPrefixD(mips, d, sz, true); WriteVector(mips, d, outSize, vd); @@ -1335,10 +1335,9 @@ namespace MIPSInt } } - d[0] = s[0] + t[0]; - d[1] = s[1] + t[1]; - d[2] = s[2] + t[2]; - d[3] = s[3] + t[3]; + for (int i = 0; i < 4; i++) { + d[i] = VfpuSumNaN(s[i] + t[i]); + } ApplyPrefixD(mips, d, sz); WriteVector(mips, d, sz, vd); diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index 1492274a71..e5a50367a1 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -2247,6 +2247,8 @@ void Jit::Comp_Vocp(MIPSOpcode op) { } ADDSS(XMM0, fpr.V(sregs[i])); MOVSS(tempxregs[i], R(XMM0)); + // A NaN comes out as the VFPU's (cpu/vfpu/specials). + EmitVfpuSumNaN1(tempxregs[i]); } for (int i = 0; i < n; ++i) { @@ -2318,6 +2320,10 @@ void Jit::Comp_Vbfy(MIPSOpcode op) { DISABLE; } + // A NaN comes out as the VFPU's (cpu/vfpu/specials). + for (int i = 0; i < n; ++i) + EmitVfpuSumNaN1(tempxregs[i]); + for (int i = 0; i < n; ++i) { if (!fpr.V(dregs[i]).IsSimpleReg(tempxregs[i])) MOVSS(fpr.V(dregs[i]), tempxregs[i]);