// Copyright 2021 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include "Common/Arm64Emitter.h" #include "Common/Assert.h" #include "Common/BitUtils.h" #include "Common/Random.h" #include namespace { using namespace Arm64Gen; class TestMovI2R : public ARM64CodeBlock { public: TestMovI2R() { AllocCodeSpace(4096); } void Check32(u32 value) { ResetCodePtr(); const u8* fn = GetCodePtr(); { const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes; MOVI2R(ARM64Reg::W0, value); RET(); } FlushIcacheSection(const_cast(fn), const_cast(GetCodePtr())); const u64 result = Common::BitCast(fn)(); EXPECT_EQ(value, result); } void Check64(u64 value) { ResetCodePtr(); const u8* fn = GetCodePtr(); { const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes; MOVI2R(ARM64Reg::X0, value); RET(); } FlushIcacheSection(const_cast(fn), const_cast(GetCodePtr())); const u64 result = Common::BitCast(fn)(); EXPECT_EQ(value, result); } }; } // namespace TEST(JitArm64, MovI2R_32BitValues) { Common::Random::PRNG rng{0}; TestMovI2R test; for (u64 i = 0; i < 0x100000; i++) { const u32 value = rng.GenerateValue(); test.Check32(value); test.Check64(value); } } TEST(JitArm64, MovI2R_Rand) { Common::Random::PRNG rng{0}; TestMovI2R test; for (u64 i = 0; i < 0x100000; i++) { test.Check64(rng.GenerateValue()); } } // Construct and test every 64-bit logical immediate TEST(JitArm64, MovI2R_LogImm) { TestMovI2R test; for (unsigned size = 2; size <= 64; size *= 2) { for (unsigned length = 1; length < size; ++length) { u64 imm = ~u64{0} >> (64 - length); for (unsigned e = size; e < 64; e *= 2) { imm |= imm << e; } for (unsigned rotation = 0; rotation < size; ++rotation) { test.Check64(imm); EXPECT_EQ(static_cast(LogicalImm(imm, 64)), true); if (size < 64) { test.Check32(imm); EXPECT_EQ(static_cast(LogicalImm(static_cast(imm), 32)), true); } imm = (imm >> 63) | (imm << 1); } } } } TEST(JitArm64, MovI2R_ADP) { TestMovI2R test; const u64 base = Common::BitCast(test.GetCodePtr()); // Test offsets around 0 for (s64 i = -0x20000; i < 0x20000; i++) { const u64 offset = static_cast(i); test.Check64(base + offset); } // Test offsets around the maximum for (const s64 i : {-0x200000ll, 0x200000ll}) { for (s64 j = -4; j < 4; j++) { const u64 offset = static_cast(i + j); test.Check64(base + offset); } } } TEST(JitArm64, MovI2R_ADRP) { TestMovI2R test; const u64 base = Common::BitCast(test.GetCodePtr()) & ~0xFFF; // Test offsets around 0 for (s64 i = -0x20000; i < 0x20000; i++) { const u64 offset = static_cast(i) << 12; test.Check64(base + offset); } // Test offsets around the maximum for (const s64 i : {-0x100000000ll, -0x80000000ll, 0x80000000ll, 0x100000000ll}) { for (s64 j = -4; j < 4; j++) { const u64 offset = static_cast(i + (j << 12)); test.Check64(base + offset); } } }