From d56721ebb9910cd14115f778c57c58a6fd0ca366 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 13 Jun 2021 14:35:04 +0200 Subject: [PATCH] Interpreter: Fix FPRF handling of denormal singles --- Source/Core/Common/FloatUtils.h | 1 - .../Interpreter/Interpreter_FloatingPoint.cpp | 40 +++++++++---------- .../Interpreter/Interpreter_Paired.cpp | 32 +++++++-------- Source/Core/Core/PowerPC/PowerPC.cpp | 7 +++- Source/Core/Core/PowerPC/PowerPC.h | 3 +- .../UnitTests/Core/PowerPC/JitArm64/FPRF.cpp | 6 +-- 6 files changed, 47 insertions(+), 42 deletions(-) diff --git a/Source/Core/Common/FloatUtils.h b/Source/Core/Common/FloatUtils.h index 7fca042ace..7480cdcfea 100644 --- a/Source/Core/Common/FloatUtils.h +++ b/Source/Core/Common/FloatUtils.h @@ -87,7 +87,6 @@ enum PPCFpClass // Uses PowerPC conventions for the return value, so it can be easily // used directly in CPU emulation. u32 ClassifyDouble(double dvalue); -// More efficient float version. u32 ClassifyFloat(float fvalue); struct BaseAndDec diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index 66ccff82af..d02e8ae71b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -302,7 +302,7 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single if (!is_snan || FPSCR.VE == 0) { rPS(inst.FD).Fill(rounded); - PowerPC::UpdateFPRF(b); + PowerPC::UpdateFPRFSingle(rounded); } FPSCR.ClearFIFR(); @@ -311,7 +311,7 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single { SetFI(&FPSCR, b != rounded); FPSCR.FR = fabs(rounded) > fabs(b); - PowerPC::UpdateFPRF(rounded); + PowerPC::UpdateFPRFSingle(rounded); rPS(inst.FD).Fill(rounded); } @@ -333,7 +333,7 @@ void Interpreter::fmulx(UGeckoInstruction inst) rPS(inst.FD).SetPS0(result); FPSCR.FI = 0; // are these flags important? FPSCR.FR = 0; - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } if (inst.Rc) @@ -354,7 +354,7 @@ void Interpreter::fmulsx(UGeckoInstruction inst) rPS(inst.FD).Fill(result); FPSCR.FI = 0; FPSCR.FR = 0; - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) @@ -372,7 +372,7 @@ void Interpreter::fmaddx(UGeckoInstruction inst) { const double result = ForceDouble(FPSCR, product.value); rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } if (inst.Rc) @@ -395,7 +395,7 @@ void Interpreter::fmaddsx(UGeckoInstruction inst) rPS(inst.FD).Fill(result); FPSCR.FI = d_value.value != result; FPSCR.FR = 0; - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) @@ -413,7 +413,7 @@ void Interpreter::faddx(UGeckoInstruction inst) { const double result = ForceDouble(FPSCR, sum.value); rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } if (inst.Rc) @@ -430,7 +430,7 @@ void Interpreter::faddsx(UGeckoInstruction inst) { const double result = ForceSingle(FPSCR, sum.value); rPS(inst.FD).Fill(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) @@ -450,7 +450,7 @@ void Interpreter::fdivx(UGeckoInstruction inst) { const double result = ForceDouble(FPSCR, quotient.value); rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } // FR,FI,OX,UX??? @@ -470,7 +470,7 @@ void Interpreter::fdivsx(UGeckoInstruction inst) { const double result = ForceSingle(FPSCR, quotient.value); rPS(inst.FD).Fill(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) @@ -485,7 +485,7 @@ void Interpreter::fresx(UGeckoInstruction inst) const auto compute_result = [inst](double value) { const double result = Common::ApproximateReciprocal(value); rPS(inst.FD).Fill(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); }; if (b == 0.0) @@ -523,7 +523,7 @@ void Interpreter::frsqrtex(UGeckoInstruction inst) const auto compute_result = [inst](double value) { const double result = Common::ApproximateReciprocalSquareRoot(value); rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); }; if (b < 0.0) @@ -574,7 +574,7 @@ void Interpreter::fmsubx(UGeckoInstruction inst) { const double result = ForceDouble(FPSCR, product.value); rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } if (inst.Rc) @@ -594,7 +594,7 @@ void Interpreter::fmsubsx(UGeckoInstruction inst) { const double result = ForceSingle(FPSCR, product.value); rPS(inst.FD).Fill(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) @@ -615,7 +615,7 @@ void Interpreter::fnmaddx(UGeckoInstruction inst) const double result = std::isnan(tmp) ? tmp : -tmp; rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } if (inst.Rc) @@ -637,7 +637,7 @@ void Interpreter::fnmaddsx(UGeckoInstruction inst) const double result = std::isnan(tmp) ? tmp : -tmp; rPS(inst.FD).Fill(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) @@ -658,7 +658,7 @@ void Interpreter::fnmsubx(UGeckoInstruction inst) const double result = std::isnan(tmp) ? tmp : -tmp; rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } if (inst.Rc) @@ -680,7 +680,7 @@ void Interpreter::fnmsubsx(UGeckoInstruction inst) const double result = std::isnan(tmp) ? tmp : -tmp; rPS(inst.FD).Fill(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) @@ -698,7 +698,7 @@ void Interpreter::fsubx(UGeckoInstruction inst) { const double result = ForceDouble(FPSCR, difference.value); rPS(inst.FD).SetPS0(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFDouble(result); } if (inst.Rc) @@ -716,7 +716,7 @@ void Interpreter::fsubsx(UGeckoInstruction inst) { const double result = ForceSingle(FPSCR, difference.value); rPS(inst.FD).Fill(result); - PowerPC::UpdateFPRF(result); + PowerPC::UpdateFPRFSingle(result); } if (inst.Rc) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp index 89d51eabb7..140433892c 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp @@ -117,7 +117,7 @@ void Interpreter::ps_div(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, NI_div(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -145,7 +145,7 @@ void Interpreter::ps_res(UGeckoInstruction inst) const double ps1 = Common::ApproximateReciprocal(b); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -178,7 +178,7 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst) const double dst_ps1 = ForceSingle(FPSCR, Common::ApproximateReciprocalSquareRoot(ps1)); rPS(inst.FD).SetBoth(dst_ps0, dst_ps1); - PowerPC::UpdateFPRF(dst_ps0); + PowerPC::UpdateFPRFSingle(dst_ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -193,7 +193,7 @@ void Interpreter::ps_sub(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, NI_sub(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -208,7 +208,7 @@ void Interpreter::ps_add(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -226,7 +226,7 @@ void Interpreter::ps_mul(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -247,7 +247,7 @@ void Interpreter::ps_msub(UGeckoInstruction inst) ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -268,7 +268,7 @@ void Interpreter::ps_madd(UGeckoInstruction inst) ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -292,7 +292,7 @@ void Interpreter::ps_nmsub(UGeckoInstruction inst) const double ps1 = std::isnan(tmp1) ? tmp1 : -tmp1; rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -316,7 +316,7 @@ void Interpreter::ps_nmadd(UGeckoInstruction inst) const double ps1 = std::isnan(tmp1) ? tmp1 : -tmp1; rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -332,7 +332,7 @@ void Interpreter::ps_sum0(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, c.PS1AsDouble()); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -348,7 +348,7 @@ void Interpreter::ps_sum1(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps1); + PowerPC::UpdateFPRFSingle(ps1); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -364,7 +364,7 @@ void Interpreter::ps_muls0(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c0).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -380,7 +380,7 @@ void Interpreter::ps_muls1(UGeckoInstruction inst) const double ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -399,7 +399,7 @@ void Interpreter::ps_madds0(UGeckoInstruction inst) ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c0, b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); @@ -418,7 +418,7 @@ void Interpreter::ps_madds1(UGeckoInstruction inst) ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value); rPS(inst.FD).SetBoth(ps0, ps1); - PowerPC::UpdateFPRF(ps0); + PowerPC::UpdateFPRFSingle(ps0); if (inst.Rc) PowerPC::ppcState.UpdateCR1(); diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 73eac23a94..817276f8d7 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -626,11 +626,16 @@ void PowerPCState::SetSR(u32 index, u32 value) // FPSCR update functions -void UpdateFPRF(double dvalue) +void UpdateFPRFDouble(double dvalue) { FPSCR.FPRF = Common::ClassifyDouble(dvalue); } +void UpdateFPRFSingle(float fvalue) +{ + FPSCR.FPRF = Common::ClassifyFloat(fvalue); +} + void RoundingModeUpdated() { // The rounding mode is separate for each thread, so this must run on the CPU thread diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 73919161f2..fdc0f16a09 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -304,7 +304,8 @@ inline void SetXER_OV(bool value) SetXER_SO(value); } -void UpdateFPRF(double dvalue); +void UpdateFPRFDouble(double dvalue); +void UpdateFPRFSingle(float fvalue); void RoundingModeUpdated(); diff --git a/Source/UnitTests/Core/PowerPC/JitArm64/FPRF.cpp b/Source/UnitTests/Core/PowerPC/JitArm64/FPRF.cpp index 7bbdffdf64..270cc1b05d 100644 --- a/Source/UnitTests/Core/PowerPC/JitArm64/FPRF.cpp +++ b/Source/UnitTests/Core/PowerPC/JitArm64/FPRF.cpp @@ -74,14 +74,14 @@ TEST(JitArm64, FPRF) for (const u64 double_input : double_test_values) { const u32 expected_double = - RunUpdateFPRF([&] { PowerPC::UpdateFPRF(Common::BitCast(double_input)); }); + RunUpdateFPRF([&] { PowerPC::UpdateFPRFDouble(Common::BitCast(double_input)); }); const u32 actual_double = RunUpdateFPRF([&] { test.fprf_double(double_input); }); EXPECT_EQ(expected_double, actual_double); const u32 single_input = ConvertToSingle(double_input); - const u32 expected_single = RunUpdateFPRF( - [&] { PowerPC::UpdateFPRF(Common::BitCast(ConvertToDouble(single_input))); }); + const u32 expected_single = + RunUpdateFPRF([&] { PowerPC::UpdateFPRFSingle(Common::BitCast(single_input)); }); const u32 actual_single = RunUpdateFPRF([&] { test.fprf_single(single_input); }); EXPECT_EQ(expected_single, actual_single); }