a32_emit_x64: Fully wrapped memory fallbacks

In the same style as the A64 backend
This commit is contained in:
MerryMage 2020-04-08 14:49:01 +01:00
parent ad52c997f4
commit f9b9081d4c
2 changed files with 67 additions and 112 deletions

View file

@ -68,7 +68,7 @@ FP::FPCR A32EmitContext::FPCR() const {
A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig config, A32::Jit* jit_interface) A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig config, A32::Jit* jit_interface)
: EmitX64(code), config(std::move(config)), jit_interface(jit_interface) { : EmitX64(code), config(std::move(config)), jit_interface(jit_interface) {
GenMemoryAccessors(); GenFastmemFallbacks();
GenTerminalHandlers(); GenTerminalHandlers();
code.PreludeComplete(); code.PreludeComplete();
ClearFastDispatchTable(); ClearFastDispatchTable();
@ -159,70 +159,65 @@ void A32EmitX64::ClearFastDispatchTable() {
} }
} }
void A32EmitX64::GenMemoryAccessors() { void A32EmitX64::GenFastmemFallbacks() {
code.align(); const std::initializer_list<int> idxes{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
read_memory_8 = code.getCurr<const void*>(); const std::array<std::pair<size_t, ArgCallback>, 4> read_callbacks{{
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); {8, Devirtualize<&A32::UserCallbacks::MemoryRead8>(config.callbacks)},
Devirtualize<&A32::UserCallbacks::MemoryRead8>(config.callbacks).EmitCall(code); {16, Devirtualize<&A32::UserCallbacks::MemoryRead16>(config.callbacks)},
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); {32, Devirtualize<&A32::UserCallbacks::MemoryRead32>(config.callbacks)},
code.ret(); {64, Devirtualize<&A32::UserCallbacks::MemoryRead64>(config.callbacks)},
PerfMapRegister(read_memory_8, code.getCurr(), "a32_read_memory_8"); }};
const std::array<std::pair<size_t, ArgCallback>, 4> write_callbacks{{
{8, Devirtualize<&A32::UserCallbacks::MemoryWrite8>(config.callbacks)},
{16, Devirtualize<&A32::UserCallbacks::MemoryWrite16>(config.callbacks)},
{32, Devirtualize<&A32::UserCallbacks::MemoryWrite32>(config.callbacks)},
{64, Devirtualize<&A32::UserCallbacks::MemoryWrite64>(config.callbacks)},
}};
code.align(); for (int vaddr_idx : idxes) {
read_memory_16 = code.getCurr<const void*>(); for (int value_idx : idxes) {
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); for (const auto& [bitsize, callback] : read_callbacks) {
Devirtualize<&A32::UserCallbacks::MemoryRead16>(config.callbacks).EmitCall(code); code.align();
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); read_fallbacks[std::make_tuple(bitsize, vaddr_idx, value_idx)] = code.getCurr<void(*)()>();
code.ret(); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
PerfMapRegister(read_memory_16, code.getCurr(), "a32_read_memory_16"); if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
}
callback.EmitCall(code);
if (value_idx != code.ABI_RETURN.getIdx()) {
code.mov(Xbyak::Reg64{value_idx}, code.ABI_RETURN);
}
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, HostLocRegIdx(value_idx));
code.ret();
PerfMapRegister(read_fallbacks[std::make_tuple(bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a32_read_fallback_{}", bitsize));
}
code.align(); for (const auto& [bitsize, callback] : write_callbacks) {
read_memory_32 = code.getCurr<const void*>(); code.align();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); write_fallbacks[std::make_tuple(bitsize, vaddr_idx, value_idx)] = code.getCurr<void(*)()>();
Devirtualize<&A32::UserCallbacks::MemoryRead32>(config.callbacks).EmitCall(code); ABI_PushCallerSaveRegistersAndAdjustStack(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); if (vaddr_idx == code.ABI_PARAM3.getIdx() && value_idx == code.ABI_PARAM2.getIdx()) {
code.ret(); code.xchg(code.ABI_PARAM2, code.ABI_PARAM3);
PerfMapRegister(read_memory_32, code.getCurr(), "a32_read_memory_32"); } else if (vaddr_idx == code.ABI_PARAM3.getIdx()) {
code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
code.align(); if (value_idx != code.ABI_PARAM3.getIdx()) {
read_memory_64 = code.getCurr<const void*>(); code.mov(code.ABI_PARAM3, Xbyak::Reg64{value_idx});
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); }
Devirtualize<&A32::UserCallbacks::MemoryRead64>(config.callbacks).EmitCall(code); } else {
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); if (value_idx != code.ABI_PARAM3.getIdx()) {
code.ret(); code.mov(code.ABI_PARAM3, Xbyak::Reg64{value_idx});
PerfMapRegister(read_memory_64, code.getCurr(), "a32_read_memory_64"); }
if (vaddr_idx != code.ABI_PARAM2.getIdx()) {
code.align(); code.mov(code.ABI_PARAM2, Xbyak::Reg64{vaddr_idx});
write_memory_8 = code.getCurr<const void*>(); }
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); }
Devirtualize<&A32::UserCallbacks::MemoryWrite8>(config.callbacks).EmitCall(code); callback.EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStack(code);
code.ret(); code.ret();
PerfMapRegister(write_memory_8, code.getCurr(), "a32_write_memory_8"); PerfMapRegister(write_fallbacks[std::make_tuple(bitsize, vaddr_idx, value_idx)], code.getCurr(), fmt::format("a32_write_fallback_{}", bitsize));
}
code.align(); }
write_memory_16 = code.getCurr<const void*>(); }
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
Devirtualize<&A32::UserCallbacks::MemoryWrite16>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret();
PerfMapRegister(write_memory_16, code.getCurr(), "a32_write_memory_16");
code.align();
write_memory_32 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
Devirtualize<&A32::UserCallbacks::MemoryWrite32>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret();
PerfMapRegister(write_memory_32, code.getCurr(), "a32_write_memory_32");
code.align();
write_memory_64 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
Devirtualize<&A32::UserCallbacks::MemoryWrite64>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret();
PerfMapRegister(write_memory_64, code.getCurr(), "a32_write_memory_64");
} }
void A32EmitX64::GenTerminalHandlers() { void A32EmitX64::GenTerminalHandlers() {
@ -828,28 +823,12 @@ void A32EmitX64::ReadMemory(A32EmitContext& ctx, IR::Inst* inst) {
return; return;
} }
const auto wrapped_fn = [this]{
switch (bitsize) {
case 8:
return read_memory_8;
case 16:
return read_memory_16;
case 32:
return read_memory_32;
case 64:
return read_memory_64;
default:
UNREACHABLE();
return static_cast<const void*>(nullptr);
}
}();
Xbyak::Label abort, end; Xbyak::Label abort, end;
ctx.reg_alloc.UseScratch(args[0], ABI_PARAM2); const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
const Xbyak::Reg64 value = ctx.reg_alloc.ScratchGpr();
const Xbyak::Reg64 vaddr = code.ABI_PARAM2; const auto wrapped_fn = read_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value.getIdx())];
const Xbyak::Reg64 value = ctx.reg_alloc.ScratchGpr(ABI_RETURN);
const auto src_ptr = EmitVAddrLookup(code, ctx.reg_alloc, config, abort, vaddr, value); const auto src_ptr = EmitVAddrLookup(code, ctx.reg_alloc, config, abort, vaddr, value);
switch (bitsize) { switch (bitsize) {
@ -902,30 +881,12 @@ void A32EmitX64::WriteMemory(A32EmitContext& ctx, IR::Inst* inst) {
return; return;
} }
const auto wrapped_fn = [this]{
switch (bitsize) {
case 8:
return write_memory_8;
case 16:
return write_memory_16;
case 32:
return write_memory_32;
case 64:
return write_memory_64;
default:
UNREACHABLE();
return static_cast<const void*>(nullptr);
}
}();
Xbyak::Label abort, end; Xbyak::Label abort, end;
ctx.reg_alloc.ScratchGpr(ABI_RETURN); const Xbyak::Reg64 vaddr = ctx.reg_alloc.UseGpr(args[0]);
ctx.reg_alloc.UseScratch(args[0], ABI_PARAM2); const Xbyak::Reg64 value = ctx.reg_alloc.UseGpr(args[1]);
ctx.reg_alloc.UseScratch(args[1], ABI_PARAM3);
const Xbyak::Reg64 vaddr = code.ABI_PARAM2; const auto wrapped_fn = write_fallbacks[std::make_tuple(bitsize, vaddr.getIdx(), value.getIdx())];
const Xbyak::Reg64 value = code.ABI_PARAM3;
const auto dest_ptr = EmitVAddrLookup(code, ctx.reg_alloc, config, abort, vaddr); const auto dest_ptr = EmitVAddrLookup(code, ctx.reg_alloc, config, abort, vaddr);
switch (bitsize) { switch (bitsize) {

View file

@ -58,15 +58,9 @@ protected:
std::array<FastDispatchEntry, fast_dispatch_table_size> fast_dispatch_table; std::array<FastDispatchEntry, fast_dispatch_table_size> fast_dispatch_table;
void ClearFastDispatchTable(); void ClearFastDispatchTable();
const void* read_memory_8; std::map<std::tuple<size_t, int, int>, void(*)()> read_fallbacks;
const void* read_memory_16; std::map<std::tuple<size_t, int, int>, void(*)()> write_fallbacks;
const void* read_memory_32; void GenFastmemFallbacks();
const void* read_memory_64;
const void* write_memory_8;
const void* write_memory_16;
const void* write_memory_32;
const void* write_memory_64;
void GenMemoryAccessors();
const void* terminal_handler_pop_rsb_hint; const void* terminal_handler_pop_rsb_hint;
const void* terminal_handler_fast_dispatch_hint = nullptr; const void* terminal_handler_fast_dispatch_hint = nullptr;