UnitTests/PowerPC: Check FPSCR output for fres/frsqrte

No games are known to care about this, but since we've gone through the
effort of implementing it, we should also go through the effort of
testing it.
This commit is contained in:
JosJuice 2024-12-26 11:26:18 +01:00
parent c528a70e64
commit 1a8619c85b
3 changed files with 91 additions and 11 deletions

View File

@ -64,20 +64,51 @@ TEST(Jit64, Frsqrte)
Core::DeclareAsCPUThread(); Core::DeclareAsCPUThread();
Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); }); Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); });
TestCommonAsmRoutines routines(Core::System::GetInstance()); Core::System& system = Core::System::GetInstance();
TestCommonAsmRoutines routines(system);
UReg_FPSCR fpscr; UReg_FPSCR fpscr;
for (const u64 ivalue : double_test_values) for (const u64 ivalue : double_test_values)
{ {
SCOPED_TRACE(fmt::format("frsqrte input: {:016x}\n", ivalue));
double dvalue = std::bit_cast<double>(ivalue); double dvalue = std::bit_cast<double>(ivalue);
u64 expected = std::bit_cast<u64>(Common::ApproximateReciprocalSquareRoot(dvalue)); u64 expected = std::bit_cast<u64>(Common::ApproximateReciprocalSquareRoot(dvalue));
u64 actual = routines.wrapped_frsqrte(ivalue, fpscr); u64 actual = routines.wrapped_frsqrte(ivalue, fpscr);
fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected);
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);
for (u32 zx = 0; zx < 2; ++zx)
{
for (u32 vxsqrt = 0; vxsqrt < 2; ++vxsqrt)
{
fpscr = {};
fpscr.ZX = zx;
fpscr.VXSQRT = vxsqrt;
routines.wrapped_frsqrte(ivalue, fpscr);
const u32 value_class = Common::ClassifyDouble(dvalue);
const bool input_is_zero =
value_class == Common::PPC_FPCLASS_NZ || value_class == Common::PPC_FPCLASS_PZ;
const bool input_is_negative = value_class == Common::PPC_FPCLASS_NN ||
value_class == Common::PPC_FPCLASS_ND ||
value_class == Common::PPC_FPCLASS_NINF;
const bool zx_expected = input_is_zero || zx;
const bool vxsqrt_expected = input_is_negative || vxsqrt;
const bool fx_expected = (input_is_zero && !zx) || (input_is_negative && !vxsqrt);
const u32 fpscr_expected = (zx_expected ? FPSCR_ZX : 0) |
(vxsqrt_expected ? FPSCR_VXSQRT : 0) |
(fx_expected ? FPSCR_FX : 0);
EXPECT_EQ(fpscr_expected, fpscr.Hex);
}
}
} }
} }

View File

@ -56,18 +56,36 @@ TEST(JitArm64, Fres)
Core::DeclareAsCPUThread(); Core::DeclareAsCPUThread();
Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); }); Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); });
TestFres test(Core::System::GetInstance()); Core::System& system = Core::System::GetInstance();
TestFres test(system);
for (const u64 ivalue : double_test_values) for (const u64 ivalue : double_test_values)
{ {
SCOPED_TRACE(fmt::format("fres input: {:016x}\n", ivalue));
const double dvalue = std::bit_cast<double>(ivalue); const double dvalue = std::bit_cast<double>(ivalue);
const u64 expected = std::bit_cast<u64>(Common::ApproximateReciprocal(dvalue)); const u64 expected = std::bit_cast<u64>(Common::ApproximateReciprocal(dvalue));
const u64 actual = test.fres(ivalue); const u64 actual = test.fres(ivalue);
if (expected != actual)
fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected);
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);
for (u32 zx = 0; zx < 2; ++zx)
{
UReg_FPSCR& fpscr = system.GetPPCState().fpscr;
fpscr = {};
fpscr.ZX = zx;
test.fres(ivalue);
const bool input_is_zero = (ivalue & (Common::DOUBLE_EXP | Common::DOUBLE_FRAC)) == 0;
const bool zx_expected = input_is_zero || zx;
const bool fx_expected = input_is_zero && !zx;
const u32 fpscr_expected = (zx_expected ? FPSCR_ZX : 0) | (fx_expected ? FPSCR_FX : 0);
EXPECT_EQ(fpscr_expected, fpscr.Hex);
}
} }
} }

View File

@ -57,18 +57,49 @@ TEST(JitArm64, Frsqrte)
Core::DeclareAsCPUThread(); Core::DeclareAsCPUThread();
Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); }); Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); });
TestFrsqrte test(Core::System::GetInstance()); Core::System& system = Core::System::GetInstance();
TestFrsqrte test(system);
for (const u64 ivalue : double_test_values) for (const u64 ivalue : double_test_values)
{ {
SCOPED_TRACE(fmt::format("frsqrte input: {:016x}\n", ivalue));
const double dvalue = std::bit_cast<double>(ivalue); const double dvalue = std::bit_cast<double>(ivalue);
const u64 expected = std::bit_cast<u64>(Common::ApproximateReciprocalSquareRoot(dvalue)); const u64 expected = std::bit_cast<u64>(Common::ApproximateReciprocalSquareRoot(dvalue));
const u64 actual = test.frsqrte(ivalue); const u64 actual = test.frsqrte(ivalue);
if (expected != actual)
fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected);
EXPECT_EQ(expected, actual); EXPECT_EQ(expected, actual);
for (u32 zx = 0; zx < 2; ++zx)
{
for (u32 vxsqrt = 0; vxsqrt < 2; ++vxsqrt)
{
UReg_FPSCR& fpscr = system.GetPPCState().fpscr;
fpscr = {};
fpscr.ZX = zx;
fpscr.VXSQRT = vxsqrt;
test.frsqrte(ivalue);
const u32 value_class = Common::ClassifyDouble(dvalue);
const bool input_is_zero =
value_class == Common::PPC_FPCLASS_NZ || value_class == Common::PPC_FPCLASS_PZ;
const bool input_is_negative = value_class == Common::PPC_FPCLASS_NN ||
value_class == Common::PPC_FPCLASS_ND ||
value_class == Common::PPC_FPCLASS_NINF;
const bool zx_expected = input_is_zero || zx;
const bool vxsqrt_expected = input_is_negative || vxsqrt;
const bool fx_expected = (input_is_zero && !zx) || (input_is_negative && !vxsqrt);
const u32 fpscr_expected = (zx_expected ? FPSCR_ZX : 0) |
(vxsqrt_expected ? FPSCR_VXSQRT : 0) |
(fx_expected ? FPSCR_FX : 0);
EXPECT_EQ(fpscr_expected, fpscr.Hex);
}
}
} }
} }