a32_emit_x64: Fully wrapped memory fallbacks
In the same style as the A64 backend
This commit is contained in:
parent
ad52c997f4
commit
f9b9081d4c
2 changed files with 67 additions and 112 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue