diff --git a/Source/UnitTests/Core/CMakeLists.txt b/Source/UnitTests/Core/CMakeLists.txt index 894310e126..1588afefe9 100644 --- a/Source/UnitTests/Core/CMakeLists.txt +++ b/Source/UnitTests/Core/CMakeLists.txt @@ -15,5 +15,8 @@ add_dolphin_test(ESFormatsTest IOS/ES/FormatsTest.cpp IOS/ES/TestBinaryData.cpp) add_dolphin_test(FileSystemTest IOS/FS/FileSystemTest.cpp) if(_M_X86) - add_dolphin_test(PowerPCTest PowerPC/Jit64Common/Frsqrte.cpp) + add_dolphin_test(PowerPCTest + PowerPC/Jit64Common/ConvertDoubleToSingle.cpp + PowerPC/Jit64Common/Frsqrte.cpp + ) endif() diff --git a/Source/UnitTests/Core/PowerPC/Jit64Common/ConvertDoubleToSingle.cpp b/Source/UnitTests/Core/PowerPC/Jit64Common/ConvertDoubleToSingle.cpp new file mode 100644 index 0000000000..c21ef579aa --- /dev/null +++ b/Source/UnitTests/Core/PowerPC/Jit64Common/ConvertDoubleToSingle.cpp @@ -0,0 +1,116 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/x64ABI.h" +#include "Core/PowerPC/Gekko.h" +#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h" +#include "Core/PowerPC/Jit64/Jit.h" +#include "Core/PowerPC/Jit64Common/Jit64AsmCommon.h" +#include "Core/PowerPC/Jit64Common/Jit64PowerPCState.h" + +#include + +namespace +{ +class TestCommonAsmRoutines : public CommonAsmRoutines +{ +public: + TestCommonAsmRoutines() : CommonAsmRoutines(jit) + { + using namespace Gen; + + AllocCodeSpace(4096); + m_const_pool.Init(AllocChildCodeSpace(1024), 1024); + + const auto raw_cdts = reinterpret_cast(AlignCode4()); + GenConvertDoubleToSingle(); + + wrapped_cdts = reinterpret_cast(AlignCode4()); + ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, 16); + + // Call + MOVQ_xmm(XMM0, R(ABI_PARAM1)); + ABI_CallFunction(raw_cdts); + MOVQ_xmm(R(ABI_RETURN), XMM0); + + ABI_PopRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8, 16); + RET(); + } + + u32 (*wrapped_cdts)(u64); + Jit64 jit; +}; +} // namespace + +TEST(Jit64, ConvertDoubleToSingle) +{ + TestCommonAsmRoutines routines; + + const std::vector input_values{ + // Special values + 0x0000'0000'0000'0000, // positive zero + 0x0000'0000'0000'0001, // smallest positive denormal + 0x0000'0000'0100'0000, + 0x000F'FFFF'FFFF'FFFF, // largest positive denormal + 0x0010'0000'0000'0000, // smallest positive normal + 0x0010'0000'0000'0002, + 0x3FF0'0000'0000'0000, // 1.0 + 0x7FEF'FFFF'FFFF'FFFF, // largest positive normal + 0x7FF0'0000'0000'0000, // positive infinity + 0x7FF0'0000'0000'0001, // first positive SNaN + 0x7FF7'FFFF'FFFF'FFFF, // last positive SNaN + 0x7FF8'0000'0000'0000, // first positive QNaN + 0x7FFF'FFFF'FFFF'FFFF, // last positive QNaN + 0x8000'0000'0000'0000, // negative zero + 0x8000'0000'0000'0001, // smallest negative denormal + 0x8000'0000'0100'0000, + 0x800F'FFFF'FFFF'FFFF, // largest negative denormal + 0x8010'0000'0000'0000, // smallest negative normal + 0x8010'0000'0000'0002, + 0xBFF0'0000'0000'0000, // -1.0 + 0xFFEF'FFFF'FFFF'FFFF, // largest negative normal + 0xFFF0'0000'0000'0000, // negative infinity + 0xFFF0'0000'0000'0001, // first negative SNaN + 0xFFF7'FFFF'FFFF'FFFF, // last negative SNaN + 0xFFF8'0000'0000'0000, // first negative QNaN + 0xFFFF'FFFF'FFFF'FFFF, // last negative QNaN + + // (exp > 896) Boundary Case + 0x3800'0000'0000'0000, // 2^(-127) = Denormal in single-prec + 0x3810'0000'0000'0000, // 2^(-126) = Smallest single-prec normal + 0xB800'0000'0000'0000, // -2^(-127) = Denormal in single-prec + 0xB810'0000'0000'0000, // -2^(-126) = Smallest single-prec normal + 0x3800'1234'5678'9ABC, 0x3810'1234'5678'9ABC, 0xB800'1234'5678'9ABC, 0xB810'1234'5678'9ABC, + + // (exp >= 874) Boundary Case + 0x3680'0000'0000'0000, // 2^(-150) = Unrepresentable in single-prec + 0x36A0'0000'0000'0000, // 2^(-149) = Smallest single-prec denormal + 0x36B0'0000'0000'0000, // 2^(-148) = Single-prec denormal + 0xB680'0000'0000'0000, // -2^(-150) = Unrepresentable in single-prec + 0xB6A0'0000'0000'0000, // -2^(-149) = Smallest single-prec denormal + 0xB6B0'0000'0000'0000, // -2^(-148) = Single-prec denormal + 0x3680'1234'5678'9ABC, 0x36A0'1234'5678'9ABC, 0x36B0'1234'5678'9ABC, 0xB680'1234'5678'9ABC, + 0xB6A0'1234'5678'9ABC, 0xB6B0'1234'5678'9ABC, + + // Some typical numbers + 0x3FF8'0000'0000'0000, // 1.5 + 0x408F'4000'0000'0000, // 1000 + 0xC008'0000'0000'0000, // -3 + }; + + for (const u64 input : input_values) + { + const u32 expected = ConvertToSingle(input); + const u32 actual = routines.wrapped_cdts(input); + + printf("%016llx -> %08x == %08x\n", input, 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 6577229382..18e0ee8044 100644 --- a/Source/UnitTests/Core/PowerPC/Jit64Common/Frsqrte.cpp +++ b/Source/UnitTests/Core/PowerPC/Jit64Common/Frsqrte.cpp @@ -16,6 +16,8 @@ #include +namespace +{ class TestCommonAsmRoutines : public CommonAsmRoutines { public: @@ -51,6 +53,7 @@ public: u64 (*wrapped_frsqrte)(u64, UReg_FPSCR&); Jit64 jit; }; +} // namespace TEST(Jit64, Frsqrte) {