emit_arm64_memory: Simplify interface to just require a bitsize

This commit is contained in:
merry 2022-12-06 15:04:26 +00:00
parent f8d8618af1
commit ac0a20795a
4 changed files with 177 additions and 77 deletions

View file

@ -26,82 +26,82 @@ void EmitIR<IR::Opcode::A32ClearExclusive>(oaknut::CodeGenerator& code, EmitCont
template<>
void EmitIR<IR::Opcode::A32ReadMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory8);
EmitReadMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ReadMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory16);
EmitReadMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ReadMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory32);
EmitReadMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ReadMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory64);
EmitReadMemory<64>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveReadMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory8);
EmitExclusiveReadMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveReadMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory16);
EmitExclusiveReadMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveReadMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory32);
EmitExclusiveReadMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveReadMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory64);
EmitExclusiveReadMemory<64>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32WriteMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory8);
EmitWriteMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32WriteMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory16);
EmitWriteMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32WriteMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory32);
EmitWriteMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32WriteMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory64);
EmitWriteMemory<64>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory8);
EmitExclusiveWriteMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory16);
EmitExclusiveWriteMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory32);
EmitExclusiveWriteMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A32ExclusiveWriteMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory64);
EmitExclusiveWriteMemory<64>(code, ctx, inst);
}
} // namespace Dynarmic::Backend::Arm64

View file

@ -27,102 +27,102 @@ void EmitIR<IR::Opcode::A64ClearExclusive>(oaknut::CodeGenerator& code, EmitCont
template<>
void EmitIR<IR::Opcode::A64ReadMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory8);
EmitReadMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ReadMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory16);
EmitReadMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ReadMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory32);
EmitReadMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ReadMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory(code, ctx, inst, LinkTarget::ReadMemory64);
EmitReadMemory<64>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ReadMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitReadMemory128(code, ctx, inst, LinkTarget::ReadMemory128);
EmitReadMemory<128>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveReadMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory8);
EmitExclusiveReadMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveReadMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory16);
EmitExclusiveReadMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveReadMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory32);
EmitExclusiveReadMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveReadMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory(code, ctx, inst, LinkTarget::ExclusiveReadMemory64);
EmitExclusiveReadMemory<64>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveReadMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveReadMemory128(code, ctx, inst, LinkTarget::ExclusiveReadMemory128);
EmitExclusiveReadMemory<128>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64WriteMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory8);
EmitWriteMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64WriteMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory16);
EmitWriteMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64WriteMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory32);
EmitWriteMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64WriteMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory64);
EmitWriteMemory<64>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64WriteMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitWriteMemory(code, ctx, inst, LinkTarget::WriteMemory128);
EmitWriteMemory<128>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory8);
EmitExclusiveWriteMemory<8>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory16);
EmitExclusiveWriteMemory<16>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory32);
EmitExclusiveWriteMemory<32>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory64);
EmitExclusiveWriteMemory<64>(code, ctx, inst);
}
template<>
void EmitIR<IR::Opcode::A64ExclusiveWriteMemory128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
EmitExclusiveWriteMemory(code, ctx, inst, LinkTarget::ExclusiveWriteMemory128);
EmitExclusiveWriteMemory<128>(code, ctx, inst);
}
} // namespace Dynarmic::Backend::Arm64

View file

@ -20,65 +20,118 @@ namespace Dynarmic::Backend::Arm64 {
using namespace oaknut::util;
namespace {
bool IsOrdered(IR::AccType acctype) {
return acctype == IR::AccType::ORDERED || acctype == IR::AccType::ORDEREDRW || acctype == IR::AccType::LIMITEDORDERED;
}
void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
LinkTarget ReadMemoryLinkTarget(size_t bitsize) {
switch (bitsize) {
case 8:
return LinkTarget::ReadMemory8;
case 16:
return LinkTarget::ReadMemory16;
case 32:
return LinkTarget::ReadMemory32;
case 64:
return LinkTarget::ReadMemory64;
case 128:
return LinkTarget::ReadMemory128;
}
UNREACHABLE();
}
LinkTarget WriteMemoryLinkTarget(size_t bitsize) {
switch (bitsize) {
case 8:
return LinkTarget::WriteMemory8;
case 16:
return LinkTarget::WriteMemory16;
case 32:
return LinkTarget::WriteMemory32;
case 64:
return LinkTarget::WriteMemory64;
case 128:
return LinkTarget::WriteMemory128;
}
UNREACHABLE();
}
LinkTarget ExclusiveReadMemoryLinkTarget(size_t bitsize) {
switch (bitsize) {
case 8:
return LinkTarget::ExclusiveReadMemory8;
case 16:
return LinkTarget::ExclusiveReadMemory16;
case 32:
return LinkTarget::ExclusiveReadMemory32;
case 64:
return LinkTarget::ExclusiveReadMemory64;
case 128:
return LinkTarget::ExclusiveReadMemory128;
}
UNREACHABLE();
}
LinkTarget ExclusiveWriteMemoryLinkTarget(size_t bitsize) {
switch (bitsize) {
case 8:
return LinkTarget::ExclusiveWriteMemory8;
case 16:
return LinkTarget::ExclusiveWriteMemory16;
case 32:
return LinkTarget::ExclusiveWriteMemory32;
case 64:
return LinkTarget::ExclusiveWriteMemory64;
case 128:
return LinkTarget::ExclusiveWriteMemory128;
}
UNREACHABLE();
}
template<size_t bitsize>
void CallbackOnlyEmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall({}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
EmitRelocation(code, ctx, fn);
EmitRelocation(code, ctx, ReadMemoryLinkTarget(bitsize));
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
ctx.reg_alloc.DefineAsRegister(inst, X0);
}
void EmitReadMemory128(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall({}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
EmitRelocation(code, ctx, fn);
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
if constexpr (bitsize == 128) {
code.MOV(Q8.B16(), Q0.B16());
ctx.reg_alloc.DefineAsRegister(inst, Q8);
} else {
ctx.reg_alloc.DefineAsRegister(inst, X0);
}
}
void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
template<size_t bitsize>
void CallbackOnlyEmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall({}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
code.MOV(Wscratch0, 1);
code.STRB(Wscratch0, Xstate, ctx.conf.state_exclusive_state_offset);
EmitRelocation(code, ctx, fn);
EmitRelocation(code, ctx, ExclusiveReadMemoryLinkTarget(bitsize));
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
ctx.reg_alloc.DefineAsRegister(inst, X0);
}
void EmitExclusiveReadMemory128(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall({}, args[1]);
const bool ordered = IsOrdered(args[2].GetImmediateAccType());
code.MOV(Wscratch0, 1);
code.STRB(Wscratch0, Xstate, ctx.conf.state_exclusive_state_offset);
EmitRelocation(code, ctx, fn);
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
if constexpr (bitsize == 128) {
code.MOV(Q8.B16(), Q0.B16());
ctx.reg_alloc.DefineAsRegister(inst, Q8);
} else {
ctx.reg_alloc.DefineAsRegister(inst, X0);
}
}
void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
template<size_t bitsize>
void CallbackOnlyEmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall({}, args[1], args[2]);
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
@ -86,13 +139,14 @@ void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* in
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
EmitRelocation(code, ctx, fn);
EmitRelocation(code, ctx, WriteMemoryLinkTarget(bitsize));
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
}
void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn) {
template<size_t bitsize>
void CallbackOnlyEmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.PrepareForCall({}, args[1], args[2]);
const bool ordered = IsOrdered(args[3].GetImmediateAccType());
@ -106,7 +160,7 @@ void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR:
code.LDRB(Wscratch0, Xstate, ctx.conf.state_exclusive_state_offset);
code.CBZ(Wscratch0, end);
code.STRB(WZR, Xstate, ctx.conf.state_exclusive_state_offset);
EmitRelocation(code, ctx, fn);
EmitRelocation(code, ctx, ExclusiveWriteMemoryLinkTarget(bitsize));
if (ordered) {
code.DMB(oaknut::BarrierOp::ISH);
}
@ -114,4 +168,47 @@ void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR:
ctx.reg_alloc.DefineAsRegister(inst, X0);
}
} // namespace
template<size_t bitsize>
void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
CallbackOnlyEmitReadMemory<bitsize>(code, ctx, inst);
}
template<size_t bitsize>
void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
CallbackOnlyEmitExclusiveReadMemory<bitsize>(code, ctx, inst);
}
template<size_t bitsize>
void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
CallbackOnlyEmitWriteMemory<bitsize>(code, ctx, inst);
}
template<size_t bitsize>
void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) {
CallbackOnlyEmitExclusiveWriteMemory<bitsize>(code, ctx, inst);
}
template void EmitReadMemory<8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitReadMemory<16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitReadMemory<32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitReadMemory<64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitReadMemory<128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveReadMemory<8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveReadMemory<16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveReadMemory<32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveReadMemory<64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveReadMemory<128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitWriteMemory<8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitWriteMemory<16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitWriteMemory<32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitWriteMemory<64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitWriteMemory<128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveWriteMemory<8>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveWriteMemory<16>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveWriteMemory<32>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveWriteMemory<64>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template void EmitExclusiveWriteMemory<128>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
} // namespace Dynarmic::Backend::Arm64

View file

@ -3,6 +3,8 @@
* SPDX-License-Identifier: 0BSD
*/
#include <mcl/stdint.hpp>
namespace oaknut {
struct PointerCodeGeneratorPolicy;
template<typename>
@ -21,12 +23,13 @@ namespace Dynarmic::Backend::Arm64 {
struct EmitContext;
enum class LinkTarget;
bool IsOrdered(IR::AccType acctype);
void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn);
void EmitReadMemory128(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn);
void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn);
void EmitExclusiveReadMemory128(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn);
void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn);
void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst, LinkTarget fn);
template<size_t bitsize>
void EmitReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template<size_t bitsize>
void EmitExclusiveReadMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template<size_t bitsize>
void EmitWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
template<size_t bitsize>
void EmitExclusiveWriteMemory(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst);
} // namespace Dynarmic::Backend::Arm64