From de07124df9aad67ca43e08f2cd70b77b2af360ac Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 2 Nov 2025 12:30:26 +0100 Subject: [PATCH] Jit64: Add fres unit test --- Source/UnitTests/Core/CMakeLists.txt | 1 + .../Jit64Common/ConvertDoubleToSingle.cpp | 3 +- .../Core/PowerPC/Jit64Common/Fres.cpp | 81 +++++++++++++++++++ .../Core/PowerPC/Jit64Common/Frsqrte.cpp | 11 ++- .../UnitTests/Core/PowerPC/JitArm64/Fres.cpp | 2 + .../Core/PowerPC/JitArm64/Frsqrte.cpp | 2 +- Source/UnitTests/UnitTests.vcxproj | 1 + 7 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 Source/UnitTests/Core/PowerPC/Jit64Common/Fres.cpp diff --git a/Source/UnitTests/Core/CMakeLists.txt b/Source/UnitTests/Core/CMakeLists.txt index 865064ed68d..8725995729f 100644 --- a/Source/UnitTests/Core/CMakeLists.txt +++ b/Source/UnitTests/Core/CMakeLists.txt @@ -22,6 +22,7 @@ if(_M_X86_64) add_dolphin_test(PowerPCTest PowerPC/DivUtilsTest.cpp PowerPC/Jit64Common/ConvertDoubleToSingle.cpp + PowerPC/Jit64Common/Fres.cpp PowerPC/Jit64Common/Frsqrte.cpp ) elseif(_M_ARM_64) diff --git a/Source/UnitTests/Core/PowerPC/Jit64Common/ConvertDoubleToSingle.cpp b/Source/UnitTests/Core/PowerPC/Jit64Common/ConvertDoubleToSingle.cpp index 05c80854b2f..c9f69d0de1a 100644 --- a/Source/UnitTests/Core/PowerPC/Jit64Common/ConvertDoubleToSingle.cpp +++ b/Source/UnitTests/Core/PowerPC/Jit64Common/ConvertDoubleToSingle.cpp @@ -64,7 +64,8 @@ TEST(Jit64, ConvertDoubleToSingle) const u32 expected = ConvertToSingle(input); const u32 actual = routines.wrapped_cdts(input); - fmt::print("{:016x} -> {:08x} == {:08x}\n", input, actual, expected); + if (expected != actual) + fmt::print("{:016x} -> {:08x} == {:08x}\n", input, actual, expected); EXPECT_EQ(expected, actual); } diff --git a/Source/UnitTests/Core/PowerPC/Jit64Common/Fres.cpp b/Source/UnitTests/Core/PowerPC/Jit64Common/Fres.cpp new file mode 100644 index 00000000000..7c106bb339c --- /dev/null +++ b/Source/UnitTests/Core/PowerPC/Jit64Common/Fres.cpp @@ -0,0 +1,81 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "Common/CommonTypes.h" +#include "Common/FloatUtils.h" +#include "Common/ScopeGuard.h" +#include "Common/x64ABI.h" +#include "Core/Core.h" +#include "Core/PowerPC/Jit64/Jit.h" +#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" +#include "Core/System.h" + +#include "../TestValues.h" + +#include +#include + +namespace +{ +class TestFres : public CommonAsmRoutines +{ +public: + explicit TestFres(Core::System& system) : CommonAsmRoutines(jit), jit(system) + { + using namespace Gen; + + AllocCodeSpace(4096); + m_const_pool.Init(AllocChildCodeSpace(1024), 1024); + + const auto raw_fres = reinterpret_cast(AlignCode4()); + GenFres(); + + wrapped_fres = reinterpret_cast(AlignCode4()); + ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, 16); + + // We know that the only part of PowerPCState that the fres routine accesses is the fpscr. + // We manufacture a PPCSTATE pointer so it reads from our provided fpscr instead. + MOV(64, R(RPPCSTATE), R(ABI_PARAM2)); + SUB(64, R(RPPCSTATE), Imm32(PPCSTATE_OFF(fpscr))); + + // Call + MOVQ_xmm(XMM0, R(ABI_PARAM1)); + ABI_CallFunction(raw_fres); + MOVQ_xmm(R(ABI_RETURN), XMM0); + + ABI_PopRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, 16); + RET(); + } + + u64 (*wrapped_fres)(u64, const UReg_FPSCR&); + Jit64 jit; +}; + +} // namespace + +TEST(Jit64, Fres) +{ + Core::DeclareAsCPUThread(); + Common::ScopeGuard cpu_thread_guard([] { Core::UndeclareAsCPUThread(); }); + + TestFres test(Core::System::GetInstance()); + + // FPSCR with NI set + const UReg_FPSCR fpscr = UReg_FPSCR(0x00000004); + + for (const u64 ivalue : double_test_values) + { + const double dvalue = std::bit_cast(ivalue); + + const u64 expected = std::bit_cast(Common::ApproximateReciprocal(dvalue)); + const u64 actual = test.wrapped_fres(ivalue, fpscr); + + if (expected != actual) + fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected); + + EXPECT_EQ(expected, actual); + } +} diff --git a/Source/UnitTests/Core/PowerPC/Jit64Common/Frsqrte.cpp b/Source/UnitTests/Core/PowerPC/Jit64Common/Frsqrte.cpp index a59f577c7b5..96926e48bc5 100644 --- a/Source/UnitTests/Core/PowerPC/Jit64Common/Frsqrte.cpp +++ b/Source/UnitTests/Core/PowerPC/Jit64Common/Frsqrte.cpp @@ -38,12 +38,10 @@ public: wrapped_frsqrte = reinterpret_cast(AlignCode4()); ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, 16); - // We know the frsqrte implementation only accesses the fpscr. We manufacture a - // PPCSTATE pointer so we read/write to our provided fpscr argument instead. - XOR(32, R(RPPCSTATE), R(RPPCSTATE)); - LEA(64, RSCRATCH, PPCSTATE(fpscr)); - SUB(64, R(ABI_PARAM2), R(RSCRATCH)); + // We know that the only part of PowerPCState that the frsqrte routine accesses is the fpscr. + // We manufacture a PPCSTATE pointer so it reads/writes to our provided fpscr instead. MOV(64, R(RPPCSTATE), R(ABI_PARAM2)); + SUB(64, R(RPPCSTATE), Imm32(PPCSTATE_OFF(fpscr))); // Call MOVQ_xmm(XMM0, R(ABI_PARAM1)); @@ -76,7 +74,8 @@ TEST(Jit64, Frsqrte) u64 actual = routines.wrapped_frsqrte(ivalue, fpscr); - fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected); + if (expected != actual) + fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected); EXPECT_EQ(expected, actual); } diff --git a/Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp b/Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp index fcfc8577a2b..cf132215ffb 100644 --- a/Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp +++ b/Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp @@ -6,6 +6,7 @@ #include "Common/Arm64Emitter.h" #include "Common/CommonTypes.h" +#include "Common/FloatUtils.h" #include "Common/ScopeGuard.h" #include "Core/Core.h" #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" @@ -15,6 +16,7 @@ #include "../TestValues.h" +#include #include namespace diff --git a/Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp b/Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp index 14f1fdfe786..a6e2940343b 100644 --- a/Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp +++ b/Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp @@ -5,8 +5,8 @@ #include #include "Common/Arm64Emitter.h" -#include "Common/BitUtils.h" #include "Common/CommonTypes.h" +#include "Common/FloatUtils.h" #include "Common/ScopeGuard.h" #include "Core/Core.h" #include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" diff --git a/Source/UnitTests/UnitTests.vcxproj b/Source/UnitTests/UnitTests.vcxproj index f35f6a691a9..f2d5a9e7049 100644 --- a/Source/UnitTests/UnitTests.vcxproj +++ b/Source/UnitTests/UnitTests.vcxproj @@ -80,6 +80,7 @@ +