summaryrefslogtreecommitdiff
path: root/Source/UnitTests/Core
diff options
context:
space:
mode:
authorMai M <mathew1800@gmail.com>2021-05-20 10:23:49 -0400
committerGitHub <noreply@github.com>2021-05-20 10:23:49 -0400
commit6958df596706ec3090b102467b68274a08a5453f (patch)
tree18156b037845c7dd14e5d58d38bbbec5b4c479ce /Source/UnitTests/Core
parent539c2cb00ed920262a310868146368bb3b3ba4c9 (diff)
parente5f2dcd891bc126b5e75e6858ae8040c67df509a (diff)
Merge pull request #9695 from JosJuice/jitarm64-fres
JitArm64: Implement fres and frsqrte
Diffstat (limited to 'Source/UnitTests/Core')
-rw-r--r--Source/UnitTests/Core/CMakeLists.txt2
-rw-r--r--Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp66
-rw-r--r--Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp66
-rw-r--r--Source/UnitTests/Core/PowerPC/TestValues.h22
4 files changed, 154 insertions, 2 deletions
diff --git a/Source/UnitTests/Core/CMakeLists.txt b/Source/UnitTests/Core/CMakeLists.txt
index 6dd344e638..134f7da78b 100644
--- a/Source/UnitTests/Core/CMakeLists.txt
+++ b/Source/UnitTests/Core/CMakeLists.txt
@@ -25,6 +25,8 @@ elseif(_M_ARM_64)
PowerPC/DivUtilsTest.cpp
PowerPC/JitArm64/ConvertSingleDouble.cpp
PowerPC/JitArm64/FPRF.cpp
+ PowerPC/JitArm64/Fres.cpp
+ PowerPC/JitArm64/Frsqrte.cpp
PowerPC/JitArm64/MovI2R.cpp
)
else()
diff --git a/Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp b/Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp
new file mode 100644
index 0000000000..027a3ac89f
--- /dev/null
+++ b/Source/UnitTests/Core/PowerPC/JitArm64/Fres.cpp
@@ -0,0 +1,66 @@
+// Copyright 2021 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <functional>
+
+#include "Common/Arm64Emitter.h"
+#include "Common/BitUtils.h"
+#include "Common/CommonTypes.h"
+#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
+#include "Core/PowerPC/JitArm64/Jit.h"
+#include "Core/PowerPC/PowerPC.h"
+
+#include "../TestValues.h"
+
+#include <gtest/gtest.h>
+
+namespace
+{
+using namespace Arm64Gen;
+
+class TestFres : public JitArm64
+{
+public:
+ TestFres()
+ {
+ AllocCodeSpace(4096);
+
+ const u8* raw_fres = GetCodePtr();
+ GenerateFres();
+
+ fres = Common::BitCast<u64 (*)(u64)>(GetCodePtr());
+ MOV(ARM64Reg::X15, ARM64Reg::X30);
+ MOV(ARM64Reg::X14, PPC_REG);
+ MOVP2R(PPC_REG, &PowerPC::ppcState);
+ MOV(ARM64Reg::X1, ARM64Reg::X0);
+ m_float_emit.FMOV(ARM64Reg::D0, ARM64Reg::X0);
+ m_float_emit.FRECPE(ARM64Reg::D0, ARM64Reg::D0);
+ BL(raw_fres);
+ MOV(ARM64Reg::X30, ARM64Reg::X15);
+ MOV(PPC_REG, ARM64Reg::X14);
+ RET();
+ }
+
+ std::function<u64(u64)> fres;
+};
+
+} // namespace
+
+TEST(JitArm64, Fres)
+{
+ TestFres test;
+
+ for (const u64 ivalue : double_test_values)
+ {
+ const double dvalue = Common::BitCast<double>(ivalue);
+
+ const u64 expected = Common::BitCast<u64>(Common::ApproximateReciprocal(dvalue));
+ const u64 actual = test.fres(ivalue);
+
+ if (expected != actual)
+ fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected);
+
+ EXPECT_EQ(expected, actual);
+ }
+}
diff --git a/Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp b/Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp
new file mode 100644
index 0000000000..749b147dcb
--- /dev/null
+++ b/Source/UnitTests/Core/PowerPC/JitArm64/Frsqrte.cpp
@@ -0,0 +1,66 @@
+// Copyright 2021 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <functional>
+
+#include "Common/Arm64Emitter.h"
+#include "Common/BitUtils.h"
+#include "Common/CommonTypes.h"
+#include "Core/PowerPC/Interpreter/Interpreter_FPUtils.h"
+#include "Core/PowerPC/JitArm64/Jit.h"
+#include "Core/PowerPC/PowerPC.h"
+
+#include "../TestValues.h"
+
+#include <gtest/gtest.h>
+
+namespace
+{
+using namespace Arm64Gen;
+
+class TestFrsqrte : public JitArm64
+{
+public:
+ TestFrsqrte()
+ {
+ AllocCodeSpace(4096);
+
+ const u8* raw_frsqrte = GetCodePtr();
+ GenerateFrsqrte();
+
+ frsqrte = Common::BitCast<u64 (*)(u64)>(GetCodePtr());
+ MOV(ARM64Reg::X15, ARM64Reg::X30);
+ MOV(ARM64Reg::X14, PPC_REG);
+ MOVP2R(PPC_REG, &PowerPC::ppcState);
+ MOV(ARM64Reg::X1, ARM64Reg::X0);
+ m_float_emit.FMOV(ARM64Reg::D0, ARM64Reg::X0);
+ m_float_emit.FRSQRTE(ARM64Reg::D0, ARM64Reg::D0);
+ BL(raw_frsqrte);
+ MOV(ARM64Reg::X30, ARM64Reg::X15);
+ MOV(PPC_REG, ARM64Reg::X14);
+ RET();
+ }
+
+ std::function<u64(u64)> frsqrte;
+};
+
+} // namespace
+
+TEST(JitArm64, Frsqrte)
+{
+ TestFrsqrte test;
+
+ for (const u64 ivalue : double_test_values)
+ {
+ const double dvalue = Common::BitCast<double>(ivalue);
+
+ const u64 expected = Common::BitCast<u64>(Common::ApproximateReciprocalSquareRoot(dvalue));
+ const u64 actual = test.frsqrte(ivalue);
+
+ if (expected != actual)
+ fmt::print("{:016x} -> {:016x} == {:016x}\n", ivalue, actual, expected);
+
+ EXPECT_EQ(expected, actual);
+ }
+}
diff --git a/Source/UnitTests/Core/PowerPC/TestValues.h b/Source/UnitTests/Core/PowerPC/TestValues.h
index 20fbbe913c..a1df5b0ff5 100644
--- a/Source/UnitTests/Core/PowerPC/TestValues.h
+++ b/Source/UnitTests/Core/PowerPC/TestValues.h
@@ -8,7 +8,7 @@
#include "Common/CommonTypes.h"
-constexpr std::array<u64, 49> double_test_values{
+constexpr std::array<u64, 57> double_test_values{
// Special values
0x0000'0000'0000'0000, // positive zero
0x0000'0000'0000'0001, // smallest positive denormal
@@ -54,13 +54,25 @@ constexpr std::array<u64, 49> double_test_values{
0x3680'1234'5678'9ABC, 0x36A0'1234'5678'9ABC, 0x36B0'1234'5678'9ABC, 0xB680'1234'5678'9ABC,
0xB6A0'1234'5678'9ABC, 0xB6B0'1234'5678'9ABC,
+ // (exp > 1148) Boundary case for fres
+ 0x47C0'0000'0000'0000, // 2^125 = fres result is non-zero
+ 0x47D0'0000'0000'0000, // 2^126 = fres result is zero
+ 0xC7C0'0000'0000'0000, // -2^125 = fres result is non-zero
+ 0xC7D0'0000'0000'0000, // -2^126 = fres result is zero
+
+ // (exp < 895) Boundary case for fres
+ 0x37F0'0000'0000'0000, // 2^(-128) = fres result is non-max
+ 0x37E0'0000'0000'0000, // 2^(-129) = fres result is max
+ 0xB7F0'0000'0000'0000, // -2^(-128) = fres result is non-max
+ 0xB7E0'0000'0000'0000, // -2^(-129) = fres result is max
+
// Some typical numbers
0x3FF8'0000'0000'0000, // 1.5
0x408F'4000'0000'0000, // 1000
0xC008'0000'0000'0000, // -3
};
-constexpr std::array<u32, 29> single_test_values{
+constexpr std::array<u32, 33> single_test_values{
// Special values
0x0000'0000, // positive zero
0x0000'0001, // smallest positive denormal
@@ -89,6 +101,12 @@ constexpr std::array<u32, 29> single_test_values{
0xFFC0'0000, // first negative QNaN
0xFFFF'FFFF, // last negative QNaN
+ // (exp > 252) Boundary case for fres
+ 0x7E00'0000, // 2^125 = fres result is non-zero
+ 0x7E80'0000, // 2^126 = fres result is zero
+ 0xC7C0'0000, // -2^125 = fres result is non-zero
+ 0xC7D0'0000, // -2^126 = fres result is zero
+
// Some typical numbers
0x3FC0'0000, // 1.5
0x447A'0000, // 1000