40 changes: 15 additions & 25 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_BackPatch.cpp
Expand Up @@ -211,55 +211,45 @@ void JitArm64::EmitBackpatchRoutine(u32 flags, MemAccessMode mode, ARM64Reg RS,
src_reg = dst_reg;
}

if (dst_reg != src_reg)
MOV(dst_reg, src_reg);

const bool reverse = (flags & BackPatchInfo::FLAG_REVERSE) != 0;

MOVP2R(ARM64Reg::X2, &m_mmu);

if (access_size == 64)
{
MOVP2R(ARM64Reg::X8,
reverse ? &PowerPC::WriteU64SwapFromJitArm64 : &PowerPC::WriteU64FromJitArm64);
ABI_CallFunction(reverse ? &PowerPC::WriteU64SwapFromJitArm64 :
&PowerPC::WriteU64FromJitArm64,
src_reg, ARM64Reg::W1, &m_mmu);
}
else if (access_size == 32)
{
MOVP2R(ARM64Reg::X8,
reverse ? &PowerPC::WriteU32SwapFromJitArm64 : &PowerPC::WriteU32FromJitArm64);
ABI_CallFunction(reverse ? &PowerPC::WriteU32SwapFromJitArm64 :
&PowerPC::WriteU32FromJitArm64,
src_reg, ARM64Reg::W1, &m_mmu);
}
else if (access_size == 16)
{
MOVP2R(ARM64Reg::X8,
reverse ? &PowerPC::WriteU16SwapFromJitArm64 : &PowerPC::WriteU16FromJitArm64);
ABI_CallFunction(reverse ? &PowerPC::WriteU16SwapFromJitArm64 :
&PowerPC::WriteU16FromJitArm64,
src_reg, ARM64Reg::W1, &m_mmu);
}
else
{
MOVP2R(ARM64Reg::X8, &PowerPC::WriteU8FromJitArm64);
ABI_CallFunction(&PowerPC::WriteU8FromJitArm64, src_reg, ARM64Reg::W1, &m_mmu);
}

BLR(ARM64Reg::X8);
}
else if (flags & BackPatchInfo::FLAG_ZERO_256)
{
MOVP2R(ARM64Reg::X1, &m_mmu);
MOVP2R(ARM64Reg::X8, &PowerPC::ClearDCacheLineFromJitArm64);
BLR(ARM64Reg::X8);
ABI_CallFunction(&PowerPC::ClearDCacheLineFromJitArm64, ARM64Reg::W0, &m_mmu);
}
else
{
MOVP2R(ARM64Reg::X1, &m_mmu);

if (access_size == 64)
MOVP2R(ARM64Reg::X8, &PowerPC::ReadU64FromJitArm64);
ABI_CallFunction(&PowerPC::ReadU64FromJitArm64, ARM64Reg::W0, &m_mmu);
else if (access_size == 32)
MOVP2R(ARM64Reg::X8, &PowerPC::ReadU32FromJitArm64);
ABI_CallFunction(&PowerPC::ReadU32FromJitArm64, ARM64Reg::W0, &m_mmu);
else if (access_size == 16)
MOVP2R(ARM64Reg::X8, &PowerPC::ReadU16FromJitArm64);
ABI_CallFunction(&PowerPC::ReadU16FromJitArm64, ARM64Reg::W0, &m_mmu);
else
MOVP2R(ARM64Reg::X8, &PowerPC::ReadU8FromJitArm64);

BLR(ARM64Reg::X8);
ABI_CallFunction(&PowerPC::ReadU8FromJitArm64, ARM64Reg::W0, &m_mmu);
}

m_float_emit.ABI_PopRegisters(fprs_to_push, ARM64Reg::X30);
Expand Down
14 changes: 9 additions & 5 deletions Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp
Expand Up @@ -770,13 +770,17 @@ void JitArm64::dcbx(UGeckoInstruction inst)
ABI_PushRegisters(gprs_to_push);
m_float_emit.ABI_PushRegisters(fprs_to_push, WA);

MOVP2R(ARM64Reg::X0, &m_system.GetJitInterface());
// effective_address and loop_counter are already in W1 and W2 respectively
// For efficiency, effective_addr and loop_counter are already in W1 and W2 respectively
if (make_loop)
MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLinesFromJIT);
{
ABI_CallFunction(&JitInterface::InvalidateICacheLinesFromJIT, &m_system.GetJitInterface(),
effective_addr, loop_counter);
}
else
MOVP2R(ARM64Reg::X8, &JitInterface::InvalidateICacheLineFromJIT);
BLR(ARM64Reg::X8);
{
ABI_CallFunction(&JitInterface::InvalidateICacheLineFromJIT, &m_system.GetJitInterface(),
effective_addr);
}

m_float_emit.ABI_PopRegisters(fprs_to_push, WA);
ABI_PopRegisters(gprs_to_push);
Expand Down
Expand Up @@ -81,9 +81,7 @@ void JitArm64::UpdateRoundingMode()

ABI_PushRegisters(gprs_to_save);
m_float_emit.ABI_PushRegisters(fprs_to_save, ARM64Reg::X8);
MOVP2R(ARM64Reg::X0, &m_ppc_state);
MOVP2R(ARM64Reg::X8, &PowerPC::RoundingModeUpdated);
BLR(ARM64Reg::X8);
ABI_CallFunction(&PowerPC::RoundingModeUpdated, &m_ppc_state);
m_float_emit.ABI_PopRegisters(fprs_to_save, ARM64Reg::X8);
ABI_PopRegisters(gprs_to_save);
}
Expand Down
8 changes: 2 additions & 6 deletions Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp
Expand Up @@ -169,10 +169,7 @@ void JitArm64::GenerateAsm()

// Call JIT
ResetStack();
MOVP2R(ARM64Reg::X0, this);
MOV(ARM64Reg::W1, DISPATCHER_PC);
MOVP2R(ARM64Reg::X8, reinterpret_cast<void*>(&JitTrampoline));
BLR(ARM64Reg::X8);
ABI_CallFunction(&JitTrampoline, this, DISPATCHER_PC);
LDR(IndexType::Unsigned, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc));
B(dispatcher_no_check);

Expand All @@ -189,8 +186,7 @@ void JitArm64::GenerateAsm()
FixupBranch exit = CBNZ(ARM64Reg::W0);

SetJumpTarget(to_start_of_timing_slice);
MOVP2R(ARM64Reg::X8, &CoreTiming::GlobalAdvance);
BLR(ARM64Reg::X8);
ABI_CallFunction(&CoreTiming::GlobalAdvance);

// When we've just entered the jit we need to update the membase
// GlobalAdvance also checks exceptions after which we need to
Expand Down
12 changes: 5 additions & 7 deletions Source/Core/Core/PowerPC/JitArm64/Jit_Util.cpp
Expand Up @@ -78,10 +78,8 @@ class MMIOWriteCodeGenerator : public MMIO::WriteHandlingMethodVisitor<T>

m_emit->ABI_PushRegisters(m_gprs_in_use);
float_emit.ABI_PushRegisters(m_fprs_in_use, ARM64Reg::X1);
m_emit->MOVP2R(ARM64Reg::X1, m_system);
m_emit->MOVI2R(ARM64Reg::W2, m_address);
m_emit->MOV(ARM64Reg::W3, m_src_reg);
m_emit->BLR(m_emit->ABI_SetupLambda(lambda));

m_emit->ABI_CallLambdaFunction(lambda, m_system, m_address, m_src_reg);

float_emit.ABI_PopRegisters(m_fprs_in_use, ARM64Reg::X1);
m_emit->ABI_PopRegisters(m_gprs_in_use);
Expand Down Expand Up @@ -176,9 +174,9 @@ class MMIOReadCodeGenerator : public MMIO::ReadHandlingMethodVisitor<T>

m_emit->ABI_PushRegisters(m_gprs_in_use);
float_emit.ABI_PushRegisters(m_fprs_in_use, ARM64Reg::X1);
m_emit->MOVP2R(ARM64Reg::X1, m_system);
m_emit->MOVI2R(ARM64Reg::W2, m_address);
m_emit->BLR(m_emit->ABI_SetupLambda(lambda));

m_emit->ABI_CallLambdaFunction(lambda, m_system, m_address);

if (m_sign_extend)
m_emit->SBFM(m_dst_reg, ARM64Reg::W0, 0, sbits - 1);
else
Expand Down
178 changes: 178 additions & 0 deletions Source/UnitTests/Common/Arm64EmitterTest.cpp
@@ -0,0 +1,178 @@
// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "Common/Arm64Emitter.h"
#include "Common/BitSet.h"
#include "Common/BitUtils.h"

#include <gtest/gtest.h>

using namespace Arm64Gen;

namespace
{
u32 ZeroParameterFunction()
{
return 123;
}

u32 OneParameterFunction(u64 a)
{
return a + 23;
}

u32 TwoParameterFunction(u64 a, u64 b)
{
return a * 10 + b + 3;
}

u32 ThreeParameterFunction(u64 a, u64 b, u64 c)
{
return a * 10 + b + c / 10;
}

u32 EightParameterFunction(u64 a, u64 b, u64 c, u64 d, u64 e, u64 f, u64 g, u64 h)
{
return a / 20 + b / 8 + c / 10 + d / 2 + e / 5 - f + g + h / 3;
}

class TestCallFunction : public ARM64CodeBlock
{
public:
TestCallFunction() { AllocCodeSpace(4096); }

template <typename F>
void Emit(F f)
{
ResetCodePtr();

m_code_pointer = GetCodePtr();
{
const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes;

constexpr BitSet32 link_register{DecodeReg(ARM64Reg::X30)};
ABI_PushRegisters(link_register);
f();
ABI_PopRegisters(link_register);
RET();
}

FlushIcacheSection(const_cast<u8*>(m_code_pointer), const_cast<u8*>(GetCodePtr()));
}

void Run()
{
const u64 actual = Common::BitCast<u64 (*)()>(m_code_pointer)();
constexpr u64 expected = 123;
EXPECT_EQ(expected, actual);
}

private:
const u8* m_code_pointer = nullptr;
};

} // namespace

TEST(Arm64Emitter, CallFunction_ZeroParameters)
{
TestCallFunction test;
test.Emit([&] { test.ABI_CallFunction(&ZeroParameterFunction); });
test.Run();
}

TEST(Arm64Emitter, CallFunction_OneConstantParameter)
{
TestCallFunction test;
test.Emit([&] { test.ABI_CallFunction(&OneParameterFunction, 100); });
test.Run();
}

TEST(Arm64Emitter, CallFunction_OneRegisterParameterNoMov)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X0, 100);
test.ABI_CallFunction(&OneParameterFunction, ARM64Reg::X0);
});
test.Run();
}

TEST(Arm64Emitter, CallFunction_OneRegisterParameterMov)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X8, 100);
test.ABI_CallFunction(&OneParameterFunction, ARM64Reg::X8);
});
test.Run();
}

TEST(Arm64Emitter, CallFunction_TwoRegistersMixed)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X0, 20);
test.ABI_CallFunction(&TwoParameterFunction, 10, ARM64Reg::X0);
});
test.Run();
}

TEST(Arm64Emitter, CallFunction_TwoRegistersCycle)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X0, 20);
test.MOVI2R(ARM64Reg::X1, 10);
test.ABI_CallFunction(&TwoParameterFunction, ARM64Reg::X1, ARM64Reg::X0);
});
test.Run();
}

TEST(Arm64Emitter, CallFunction_ThreeRegistersMixed)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X1, 10);
test.MOVI2R(ARM64Reg::X2, 20);
test.ABI_CallFunction(&ThreeParameterFunction, ARM64Reg::X1, ARM64Reg::X2, 30);
});
test.Run();
}

TEST(Arm64Emitter, CallFunction_ThreeRegistersCycle1)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X0, 30);
test.MOVI2R(ARM64Reg::X1, 10);
test.MOVI2R(ARM64Reg::X2, 20);
test.ABI_CallFunction(&ThreeParameterFunction, ARM64Reg::X1, ARM64Reg::X2, ARM64Reg::X0);
});
test.Run();
}

TEST(Arm64Emitter, CallFunction_ThreeRegistersCycle2)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X0, 20);
test.MOVI2R(ARM64Reg::X1, 30);
test.MOVI2R(ARM64Reg::X2, 10);
test.ABI_CallFunction(&ThreeParameterFunction, ARM64Reg::X2, ARM64Reg::X0, ARM64Reg::X1);
});
test.Run();
}

TEST(Arm64Emitter, CallFunction_EightRegistersMixed)
{
TestCallFunction test;
test.Emit([&] {
test.MOVI2R(ARM64Reg::X3, 12);
test.MOVI2R(ARM64Reg::X4, 23);
test.MOVI2R(ARM64Reg::X5, 24);
test.MOVI2R(ARM64Reg::X30, 2000);
test.ABI_CallFunction(&EightParameterFunction, ARM64Reg::X30, 40, ARM64Reg::X4, ARM64Reg::X5,
ARM64Reg::X4, ARM64Reg::X3, 5, ARM64Reg::X4);
});
test.Run();
}
2 changes: 2 additions & 0 deletions Source/UnitTests/Common/CMakeLists.txt
Expand Up @@ -21,4 +21,6 @@ add_dolphin_test(SwapTest SwapTest.cpp)
if (_M_X86)
add_dolphin_test(x64EmitterTest x64EmitterTest.cpp)
target_link_libraries(x64EmitterTest PRIVATE bdisasm)
elseif (_M_ARM_64)
add_dolphin_test(Arm64EmitterTest Arm64EmitterTest.cpp)
endif()
1 change: 1 addition & 0 deletions Source/UnitTests/UnitTests.vcxproj
Expand Up @@ -80,6 +80,7 @@
<ClCompile Include="Core\PowerPC\Jit64Common\Frsqrte.cpp" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)'=='ARM64'">
<ClCompile Include="Common\Arm64EmitterTest.cpp" />
<ClCompile Include="Core\PowerPC\JitArm64\ConvertSingleDouble.cpp" />
<ClCompile Include="Core\PowerPC\JitArm64\FPRF.cpp" />
<ClCompile Include="Core\PowerPC\JitArm64\Fres.cpp" />
Expand Down