From 965b963a6f62bec45c0810c01ab5a8a1aa231463 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 12 Apr 2018 01:40:55 -0400 Subject: [PATCH 1/2] Interpreter_FloatingPoint: Handle SNaNs properly in frsp If FPSCR[VE] is set, a result isn't supposed to be written to the destination, just the FPSCR[VXSNAN] bit gets set, and FPSCR[FR] and FPSCR[FI] get set to zero. If FPSCR[VE] isn't set, then we do write out a result, however, the FPSCR[FPRF] field is updated to signify a QNaN (yes, a QNaN, the FPRF field doesn't have a bit configuration for SNaNs). --- .../Interpreter/Interpreter_FloatingPoint.cpp | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index 4529d2ebe8..69f3a93de8 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -272,12 +272,31 @@ void Interpreter::fselx(UGeckoInstruction inst) // PS1 is said to be undefined void Interpreter::frspx(UGeckoInstruction inst) // round to single { - double b = rPS0(inst.FB); - double rounded = ForceSingle(b); - SetFI(b != rounded); - FPSCR.FR = fabs(rounded) > fabs(b); - PowerPC::UpdateFPRF(rounded); - rPS0(inst.FD) = rPS1(inst.FD) = rounded; + const double b = rPS0(inst.FB); + const double rounded = ForceSingle(b); + + if (MathUtil::IsSNAN(b)) + { + SetFPException(FPSCR_VXSNAN); + + if (FPSCR.VE == 0) + { + rPS0(inst.FD) = rounded; + rPS1(inst.FD) = rounded; + PowerPC::UpdateFPRF(b); + } + + SetFI(0); + FPSCR.FR = 0; + } + else + { + SetFI(b != rounded); + FPSCR.FR = fabs(rounded) > fabs(b); + PowerPC::UpdateFPRF(rounded); + rPS0(inst.FD) = rounded; + rPS1(inst.FD) = rounded; + } if (inst.Rc) Helper_UpdateCR1(); From a36bf438cde503f98964af16a958891ad9cd8ff9 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Thu, 12 Apr 2018 02:51:37 -0400 Subject: [PATCH 2/2] Interpreter_FloatingPoint: Handle QNaNs properly in frsp Essentially the same behavior as the SNaN path, minus the conditional result and setting of the VXSNAN FPSCR bit. --- .../PowerPC/Interpreter/Interpreter_FloatingPoint.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index 69f3a93de8..911f06af3b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -275,11 +275,14 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single const double b = rPS0(inst.FB); const double rounded = ForceSingle(b); - if (MathUtil::IsSNAN(b)) + if (std::isnan(b)) { - SetFPException(FPSCR_VXSNAN); + const bool is_snan = MathUtil::IsSNAN(b); - if (FPSCR.VE == 0) + if (is_snan) + SetFPException(FPSCR_VXSNAN); + + if (!is_snan || FPSCR.VE == 0) { rPS0(inst.FD) = rounded; rPS1(inst.FD) = rounded;