devirtualize: Replace DEVIRT macro with function template

This commit is contained in:
MerryMage 2018-08-03 09:09:29 +01:00
parent cd12a1862e
commit 2e0885388e
5 changed files with 76 additions and 69 deletions

View file

@ -154,56 +154,56 @@ void A32EmitX64::GenMemoryAccessors() {
code.align(); code.align();
read_memory_8 = code.getCurr<const void*>(); read_memory_8 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead8).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryRead8>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
code.align(); code.align();
read_memory_16 = code.getCurr<const void*>(); read_memory_16 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead16).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryRead16>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
code.align(); code.align();
read_memory_32 = code.getCurr<const void*>(); read_memory_32 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead32).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryRead32>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
code.align(); code.align();
read_memory_64 = code.getCurr<const void*>(); read_memory_64 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryRead64).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryRead64>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
code.align(); code.align();
write_memory_8 = code.getCurr<const void*>(); write_memory_8 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite8).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryWrite8>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
code.align(); code.align();
write_memory_16 = code.getCurr<const void*>(); write_memory_16 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite16).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryWrite16>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
code.align(); code.align();
write_memory_32 = code.getCurr<const void*>(); write_memory_32 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite32).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryWrite32>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
code.align(); code.align();
write_memory_64 = code.getCurr<const void*>(); write_memory_64 = code.getCurr<const void*>();
ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PushCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
DEVIRT(config.callbacks, &A32::UserCallbacks::MemoryWrite64).EmitCall(code); Devirtualize<&A32::UserCallbacks::MemoryWrite64>(config.callbacks).EmitCall(code);
ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN); ABI_PopCallerSaveRegistersAndAdjustStackExcept(code, ABI_RETURN);
code.ret(); code.ret();
} }
@ -605,12 +605,12 @@ void A32EmitX64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
code.SwitchMxcsrOnExit(); code.SwitchMxcsrOnExit();
code.mov(code.ABI_PARAM2, qword[r15 + offsetof(A32JitState, cycles_to_run)]); code.mov(code.ABI_PARAM2, qword[r15 + offsetof(A32JitState, cycles_to_run)]);
code.sub(code.ABI_PARAM2, qword[r15 + offsetof(A32JitState, cycles_remaining)]); code.sub(code.ABI_PARAM2, qword[r15 + offsetof(A32JitState, cycles_remaining)]);
DEVIRT(config.callbacks, &A32::UserCallbacks::AddTicks).EmitCall(code); Devirtualize<&A32::UserCallbacks::AddTicks>(config.callbacks).EmitCall(code);
ctx.reg_alloc.EndOfAllocScope(); ctx.reg_alloc.EndOfAllocScope();
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0]); ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
DEVIRT(config.callbacks, &A32::UserCallbacks::CallSVC).EmitCall(code); Devirtualize<&A32::UserCallbacks::CallSVC>(config.callbacks).EmitCall(code);
DEVIRT(config.callbacks, &A32::UserCallbacks::GetTicksRemaining).EmitCall(code); Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(config.callbacks).EmitCall(code);
code.mov(qword[r15 + offsetof(A32JitState, cycles_to_run)], code.ABI_RETURN); code.mov(qword[r15 + offsetof(A32JitState, cycles_to_run)], code.ABI_RETURN);
code.mov(qword[r15 + offsetof(A32JitState, cycles_remaining)], code.ABI_RETURN); code.mov(qword[r15 + offsetof(A32JitState, cycles_remaining)], code.ABI_RETURN);
code.SwitchMxcsrOnEntry(); code.SwitchMxcsrOnEntry();
@ -622,7 +622,7 @@ void A32EmitX64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
ASSERT(args[0].IsImmediate() && args[1].IsImmediate()); ASSERT(args[0].IsImmediate() && args[1].IsImmediate());
u32 pc = args[0].GetImmediateU32(); u32 pc = args[0].GetImmediateU32();
u64 exception = args[1].GetImmediateU64(); u64 exception = args[1].GetImmediateU64();
DEVIRT(config.callbacks, &A32::UserCallbacks::ExceptionRaised).EmitCall(code, [&](RegList param) { Devirtualize<&A32::UserCallbacks::ExceptionRaised>(config.callbacks).EmitCall(code, [&](RegList param) {
code.mov(param[0], pc); code.mov(param[0], pc);
code.mov(param[1], exception); code.mov(param[1], exception);
}); });
@ -691,7 +691,7 @@ static void ReadMemory(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* inst, c
if (!config.page_table) { if (!config.page_table) {
reg_alloc.HostCall(inst, {}, args[0]); reg_alloc.HostCall(inst, {}, args[0]);
DEVIRT(config.callbacks, raw_fn).EmitCall(code); Devirtualize<raw_fn>(config.callbacks).EmitCall(code);
return; return;
} }
@ -744,7 +744,7 @@ static void WriteMemory(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* inst,
if (!config.page_table) { if (!config.page_table) {
reg_alloc.HostCall(nullptr, {}, args[0], args[1]); reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
DEVIRT(config.callbacks, raw_fn).EmitCall(code); Devirtualize<raw_fn>(config.callbacks).EmitCall(code);
return; return;
} }
@ -848,7 +848,7 @@ static void ExclusiveWrite(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* ins
code.shl(code.ABI_PARAM4, 32); code.shl(code.ABI_PARAM4, 32);
code.or_(code.ABI_PARAM3, code.ABI_PARAM4); code.or_(code.ABI_PARAM3, code.ABI_PARAM4);
} }
DEVIRT(config.callbacks, fn).EmitCall(code); Devirtualize<fn>(config.callbacks).EmitCall(code);
code.xor_(passed, passed); code.xor_(passed, passed);
code.L(end); code.L(end);
@ -1143,7 +1143,7 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
code.mov(code.ABI_PARAM3.cvt32(), 1); code.mov(code.ABI_PARAM3.cvt32(), 1);
code.mov(MJitStateReg(A32::Reg::PC), code.ABI_PARAM2.cvt32()); code.mov(MJitStateReg(A32::Reg::PC), code.ABI_PARAM2.cvt32());
code.SwitchMxcsrOnExit(); code.SwitchMxcsrOnExit();
DEVIRT(config.callbacks, &A32::UserCallbacks::InterpreterFallback).EmitCall(code); Devirtualize<&A32::UserCallbacks::InterpreterFallback>(config.callbacks).EmitCall(code);
code.ReturnFromRunCode(true); // TODO: Check cycles code.ReturnFromRunCode(true); // TODO: Check cycles
} }

View file

@ -33,8 +33,8 @@ using namespace BackendX64;
static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg) { static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg) {
return RunCodeCallbacks{ return RunCodeCallbacks{
std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)), std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A32::UserCallbacks::AddTicks)), std::make_unique<ArgCallback>(Devirtualize<&A32::UserCallbacks::AddTicks>(cb)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A32::UserCallbacks::GetTicksRemaining)), std::make_unique<ArgCallback>(Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(cb)),
}; };
} }

View file

@ -140,7 +140,8 @@ void A64EmitX64::GenMemory128Accessors() {
code.align(); code.align();
memory_read_128 = code.getCurr<void(*)()>(); memory_read_128 = code.getCurr<void(*)()>();
#ifdef _WIN32 #ifdef _WIN32
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead128).EmitCallWithReturnPointer(code, [&](Xbyak::Reg64 return_value_ptr, RegList args) { Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCallWithReturnPointer(code,
[&](Xbyak::Reg64 return_value_ptr, RegList args) {
code.mov(code.ABI_PARAM3, code.ABI_PARAM2); code.mov(code.ABI_PARAM3, code.ABI_PARAM2);
code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE); code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE);
code.lea(return_value_ptr, ptr[rsp + ABI_SHADOW_SPACE]); code.lea(return_value_ptr, ptr[rsp + ABI_SHADOW_SPACE]);
@ -149,7 +150,7 @@ void A64EmitX64::GenMemory128Accessors() {
code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE); code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE);
#else #else
code.sub(rsp, 8); code.sub(rsp, 8);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead128).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryRead128>(conf.callbacks).EmitCall(code);
if (code.DoesCpuSupport(Xbyak::util::Cpu::tSSE41)) { if (code.DoesCpuSupport(Xbyak::util::Cpu::tSSE41)) {
code.movq(xmm1, code.ABI_RETURN); code.movq(xmm1, code.ABI_RETURN);
code.pinsrq(xmm1, code.ABI_RETURN2, 1); code.pinsrq(xmm1, code.ABI_RETURN2, 1);
@ -168,7 +169,7 @@ void A64EmitX64::GenMemory128Accessors() {
code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE); code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]); code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
code.movaps(xword[code.ABI_PARAM3], xmm1); code.movaps(xword[code.ABI_PARAM3], xmm1);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite128).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryWrite128>(conf.callbacks).EmitCall(code);
code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE); code.add(rsp, 8 + 16 + ABI_SHADOW_SPACE);
#else #else
code.sub(rsp, 8); code.sub(rsp, 8);
@ -180,7 +181,7 @@ void A64EmitX64::GenMemory128Accessors() {
code.punpckhqdq(xmm1, xmm1); code.punpckhqdq(xmm1, xmm1);
code.movq(code.ABI_PARAM4, xmm1); code.movq(code.ABI_PARAM4, xmm1);
} }
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite128).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryWrite128>(conf.callbacks).EmitCall(code);
code.add(rsp, 8); code.add(rsp, 8);
#endif #endif
code.ret(); code.ret();
@ -189,16 +190,16 @@ void A64EmitX64::GenMemory128Accessors() {
void A64EmitX64::GenFastmemFallbacks() { void A64EmitX64::GenFastmemFallbacks() {
const std::initializer_list<int> idxes{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; const std::initializer_list<int> idxes{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
const std::vector<std::tuple<size_t, ArgCallback>> read_callbacks { const std::vector<std::tuple<size_t, ArgCallback>> read_callbacks {
{8, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead8)}, {8, Devirtualize<&A64::UserCallbacks::MemoryRead8>(conf.callbacks)},
{16, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead16)}, {16, Devirtualize<&A64::UserCallbacks::MemoryRead16>(conf.callbacks)},
{32, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead32)}, {32, Devirtualize<&A64::UserCallbacks::MemoryRead32>(conf.callbacks)},
{64, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead64)}, {64, Devirtualize<&A64::UserCallbacks::MemoryRead64>(conf.callbacks)},
}; };
const std::vector<std::tuple<size_t, ArgCallback>> write_callbacks { const std::vector<std::tuple<size_t, ArgCallback>> write_callbacks {
{8, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite8)}, {8, Devirtualize<&A64::UserCallbacks::MemoryWrite8>(conf.callbacks)},
{16, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite16)}, {16, Devirtualize<&A64::UserCallbacks::MemoryWrite16>(conf.callbacks)},
{32, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite32)}, {32, Devirtualize<&A64::UserCallbacks::MemoryWrite32>(conf.callbacks)},
{64, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite64)}, {64, Devirtualize<&A64::UserCallbacks::MemoryWrite64>(conf.callbacks)},
}; };
for (int vaddr_idx : idxes) { for (int vaddr_idx : idxes) {
@ -502,7 +503,8 @@ void A64EmitX64::EmitA64CallSupervisor(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ASSERT(args[0].IsImmediate()); ASSERT(args[0].IsImmediate());
u32 imm = args[0].GetImmediateU32(); u32 imm = args[0].GetImmediateU32();
DEVIRT(conf.callbacks, &A64::UserCallbacks::CallSVC).EmitCall(code, [&](RegList param) { Devirtualize<&A64::UserCallbacks::CallSVC>(conf.callbacks).EmitCall(code,
[&](RegList param) {
code.mov(param[0], imm); code.mov(param[0], imm);
}); });
// The kernel would have to execute ERET to get here, which would clear exclusive state. // The kernel would have to execute ERET to get here, which would clear exclusive state.
@ -515,7 +517,8 @@ void A64EmitX64::EmitA64ExceptionRaised(A64EmitContext& ctx, IR::Inst* inst) {
ASSERT(args[0].IsImmediate() && args[1].IsImmediate()); ASSERT(args[0].IsImmediate() && args[1].IsImmediate());
u64 pc = args[0].GetImmediateU64(); u64 pc = args[0].GetImmediateU64();
u64 exception = args[1].GetImmediateU64(); u64 exception = args[1].GetImmediateU64();
DEVIRT(conf.callbacks, &A64::UserCallbacks::ExceptionRaised).EmitCall(code, [&](RegList param) { Devirtualize<&A64::UserCallbacks::ExceptionRaised>(conf.callbacks).EmitCall(code,
[&](RegList param) {
code.mov(param[0], pc); code.mov(param[0], pc);
code.mov(param[1], exception); code.mov(param[1], exception);
}); });
@ -524,7 +527,7 @@ void A64EmitX64::EmitA64ExceptionRaised(A64EmitContext& ctx, IR::Inst* inst) {
void A64EmitX64::EmitA64DataCacheOperationRaised(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64DataCacheOperationRaised(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, args[0], args[1]); ctx.reg_alloc.HostCall(nullptr, args[0], args[1]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::DataCacheOperationRaised).EmitCall(code); Devirtualize<&A64::UserCallbacks::DataCacheOperationRaised>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64DataSynchronizationBarrier(A64EmitContext&, IR::Inst*) { void A64EmitX64::EmitA64DataSynchronizationBarrier(A64EmitContext&, IR::Inst*) {
@ -538,7 +541,7 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) {
void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(inst); ctx.reg_alloc.HostCall(inst);
code.UpdateTicks(); code.UpdateTicks();
DEVIRT(conf.callbacks, &A64::UserCallbacks::GetCNTPCT).EmitCall(code); Devirtualize<&A64::UserCallbacks::GetCNTPCT>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64GetCTR(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetCTR(A64EmitContext& ctx, IR::Inst* inst) {
@ -719,7 +722,7 @@ void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(inst, {}, args[0]); ctx.reg_alloc.HostCall(inst, {}, args[0]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead8).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryRead8>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
@ -730,7 +733,7 @@ void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(inst, {}, args[0]); ctx.reg_alloc.HostCall(inst, {}, args[0]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead16).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryRead16>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
@ -741,7 +744,7 @@ void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(inst, {}, args[0]); ctx.reg_alloc.HostCall(inst, {}, args[0]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead32).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryRead32>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
@ -752,7 +755,7 @@ void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(inst, {}, args[0]); ctx.reg_alloc.HostCall(inst, {}, args[0]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead64).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryRead64>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
@ -791,7 +794,7 @@ void A64EmitX64::EmitA64WriteMemory8(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]); ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite8).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryWrite8>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
@ -802,7 +805,7 @@ void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]); ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite16).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryWrite16>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
@ -813,7 +816,7 @@ void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]); ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite32).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryWrite32>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
@ -824,7 +827,7 @@ void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst); auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]); ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite64).EmitCall(code); Devirtualize<&A64::UserCallbacks::MemoryWrite64>(conf.callbacks).EmitCall(code);
} }
void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) {
@ -979,7 +982,8 @@ void A64EmitX64::EmitA64ExclusiveWriteMemory128(A64EmitContext& ctx, IR::Inst* i
void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) { void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) {
code.SwitchMxcsrOnExit(); code.SwitchMxcsrOnExit();
DEVIRT(conf.callbacks, &A64::UserCallbacks::InterpreterFallback).EmitCall(code, [&](RegList param) { Devirtualize<&A64::UserCallbacks::InterpreterFallback>(conf.callbacks).EmitCall(code,
[&](RegList param) {
code.mov(param[0], A64::LocationDescriptor{terminal.next}.PC()); code.mov(param[0], A64::LocationDescriptor{terminal.next}.PC());
code.mov(qword[r15 + offsetof(A64JitState, pc)], param[0]); code.mov(qword[r15 + offsetof(A64JitState, pc)], param[0]);
code.mov(param[1].cvt32(), terminal.num_instructions); code.mov(param[1].cvt32(), terminal.num_instructions);

View file

@ -29,8 +29,8 @@ using namespace BackendX64;
static RunCodeCallbacks GenRunCodeCallbacks(A64::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg) { static RunCodeCallbacks GenRunCodeCallbacks(A64::UserCallbacks* cb, CodePtr (*LookupBlock)(void* lookup_block_arg), void* arg) {
return RunCodeCallbacks{ return RunCodeCallbacks{
std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)), std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A64::UserCallbacks::AddTicks)), std::make_unique<ArgCallback>(Devirtualize<&A64::UserCallbacks::AddTicks>(cb)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A64::UserCallbacks::GetTicksRemaining)), std::make_unique<ArgCallback>(Devirtualize<&A64::UserCallbacks::GetTicksRemaining>(cb)),
}; };
} }

View file

@ -32,19 +32,19 @@ struct ThunkBuilder<R(C::*)(Args...), mfp> {
} // namespace impl } // namespace impl
template <typename FunctionType, FunctionType mfp> template<auto mfp>
ArgCallback DevirtualizeGeneric(Common::mp::class_type_t<FunctionType>* this_) { ArgCallback DevirtualizeGeneric(Common::mp::class_type_t<decltype(mfp)>* this_) {
return ArgCallback{&impl::ThunkBuilder<FunctionType, mfp>::Thunk, reinterpret_cast<u64>(this_)}; return ArgCallback{&impl::ThunkBuilder<decltype(mfp), mfp>::Thunk, reinterpret_cast<u64>(this_)};
} }
template <typename FunctionType, FunctionType mfp> template<auto mfp>
ArgCallback DevirtualizeWindows(Common::mp::class_type_t<FunctionType>* this_) { ArgCallback DevirtualizeWindows(Common::mp::class_type_t<decltype(mfp)>* this_) {
static_assert(sizeof(mfp) == 8); static_assert(sizeof(mfp) == 8);
return ArgCallback{Common::BitCast<u64>(mfp), reinterpret_cast<u64>(this_)}; return ArgCallback{Common::BitCast<u64>(mfp), reinterpret_cast<u64>(this_)};
} }
template <typename FunctionType, FunctionType mfp> template<auto mfp>
ArgCallback DevirtualizeItanium(Common::mp::class_type_t<FunctionType>* this_) { ArgCallback DevirtualizeItanium(Common::mp::class_type_t<decltype(mfp)>* this_) {
struct MemberFunctionPointer { struct MemberFunctionPointer {
/// For a non-virtual function, this is a simple function pointer. /// For a non-virtual function, this is a simple function pointer.
/// For a virtual function, it is (1 + virtual table offset in bytes). /// For a virtual function, it is (1 + virtual table offset in bytes).
@ -65,15 +65,18 @@ ArgCallback DevirtualizeItanium(Common::mp::class_type_t<FunctionType>* this_) {
return ArgCallback{fn_ptr, this_ptr}; return ArgCallback{fn_ptr, this_ptr};
} }
template<auto mfp>
ArgCallback Devirtualize(Common::mp::class_type_t<decltype(mfp)>* this_) {
#if defined(__APPLE__) || defined(linux) || defined(__linux) || defined(__linux__) #if defined(__APPLE__) || defined(linux) || defined(__linux) || defined(__linux__)
#define DEVIRT(this_, mfp) Dynarmic::BackendX64::DevirtualizeItanium<decltype(mfp), mfp>(this_) return DevirtualizeItanium<mfp>(this_);
#elif defined(__MINGW64__) #elif defined(__MINGW64__)
#define DEVIRT(this_, mfp) Dynarmic::BackendX64::DevirtualizeItanium<decltype(mfp), mfp>(this_) return DevirtualizeItanium<mfp>(this_);
#elif defined(_WIN32) #elif defined(_WIN32)
#define DEVIRT(this_, mfp) Dynarmic::BackendX64::DevirtualizeWindows<decltype(mfp), mfp>(this_) return DevirtualizeWindows<mfp>(this_);
#else #else
#define DEVIRT(this_, mfp) Dynarmic::BackendX64::DevirtualizeGeneric<decltype(mfp), mfp>(this_) return DevirtualizeGeneric<mfp>(this_);
#endif #endif
}
} // namespace BackendX64 } // namespace BackendX64
} // namespace Dynarmic } // namespace Dynarmic