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();
read_memory_8 = code.getCurr<const void*>();
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);
code.ret();
code.align();
read_memory_16 = code.getCurr<const void*>();
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);
code.ret();
code.align();
read_memory_32 = code.getCurr<const void*>();
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);
code.ret();
code.align();
read_memory_64 = code.getCurr<const void*>();
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);
code.ret();
code.align();
write_memory_8 = code.getCurr<const void*>();
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);
code.ret();
code.align();
write_memory_16 = code.getCurr<const void*>();
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);
code.ret();
code.align();
write_memory_32 = code.getCurr<const void*>();
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);
code.ret();
code.align();
write_memory_64 = code.getCurr<const void*>();
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);
code.ret();
}
@ -605,12 +605,12 @@ void A32EmitX64::EmitA32CallSupervisor(A32EmitContext& ctx, IR::Inst* inst) {
code.SwitchMxcsrOnExit();
code.mov(code.ABI_PARAM2, qword[r15 + offsetof(A32JitState, cycles_to_run)]);
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();
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
DEVIRT(config.callbacks, &A32::UserCallbacks::CallSVC).EmitCall(code);
DEVIRT(config.callbacks, &A32::UserCallbacks::GetTicksRemaining).EmitCall(code);
Devirtualize<&A32::UserCallbacks::CallSVC>(config.callbacks).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_remaining)], code.ABI_RETURN);
code.SwitchMxcsrOnEntry();
@ -622,7 +622,7 @@ void A32EmitX64::EmitA32ExceptionRaised(A32EmitContext& ctx, IR::Inst* inst) {
ASSERT(args[0].IsImmediate() && args[1].IsImmediate());
u32 pc = args[0].GetImmediateU32();
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[1], exception);
});
@ -691,7 +691,7 @@ static void ReadMemory(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* inst, c
if (!config.page_table) {
reg_alloc.HostCall(inst, {}, args[0]);
DEVIRT(config.callbacks, raw_fn).EmitCall(code);
Devirtualize<raw_fn>(config.callbacks).EmitCall(code);
return;
}
@ -744,7 +744,7 @@ static void WriteMemory(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* inst,
if (!config.page_table) {
reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
DEVIRT(config.callbacks, raw_fn).EmitCall(code);
Devirtualize<raw_fn>(config.callbacks).EmitCall(code);
return;
}
@ -848,7 +848,7 @@ static void ExclusiveWrite(BlockOfCode& code, RegAlloc& reg_alloc, IR::Inst* ins
code.shl(code.ABI_PARAM4, 32);
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.L(end);
@ -1143,7 +1143,7 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDesc
code.mov(code.ABI_PARAM3.cvt32(), 1);
code.mov(MJitStateReg(A32::Reg::PC), code.ABI_PARAM2.cvt32());
code.SwitchMxcsrOnExit();
DEVIRT(config.callbacks, &A32::UserCallbacks::InterpreterFallback).EmitCall(code);
Devirtualize<&A32::UserCallbacks::InterpreterFallback>(config.callbacks).EmitCall(code);
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) {
return RunCodeCallbacks{
std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A32::UserCallbacks::AddTicks)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A32::UserCallbacks::GetTicksRemaining)),
std::make_unique<ArgCallback>(Devirtualize<&A32::UserCallbacks::AddTicks>(cb)),
std::make_unique<ArgCallback>(Devirtualize<&A32::UserCallbacks::GetTicksRemaining>(cb)),
};
}

View file

@ -140,7 +140,8 @@ void A64EmitX64::GenMemory128Accessors() {
code.align();
memory_read_128 = code.getCurr<void(*)()>();
#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.sub(rsp, 8 + 16 + 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);
#else
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)) {
code.movq(xmm1, code.ABI_RETURN);
code.pinsrq(xmm1, code.ABI_RETURN2, 1);
@ -168,7 +169,7 @@ void A64EmitX64::GenMemory128Accessors() {
code.sub(rsp, 8 + 16 + ABI_SHADOW_SPACE);
code.lea(code.ABI_PARAM3, ptr[rsp + ABI_SHADOW_SPACE]);
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);
#else
code.sub(rsp, 8);
@ -180,7 +181,7 @@ void A64EmitX64::GenMemory128Accessors() {
code.punpckhqdq(xmm1, 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);
#endif
code.ret();
@ -189,16 +190,16 @@ void A64EmitX64::GenMemory128Accessors() {
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::vector<std::tuple<size_t, ArgCallback>> read_callbacks {
{8, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead8)},
{16, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead16)},
{32, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead32)},
{64, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead64)},
{8, Devirtualize<&A64::UserCallbacks::MemoryRead8>(conf.callbacks)},
{16, Devirtualize<&A64::UserCallbacks::MemoryRead16>(conf.callbacks)},
{32, Devirtualize<&A64::UserCallbacks::MemoryRead32>(conf.callbacks)},
{64, Devirtualize<&A64::UserCallbacks::MemoryRead64>(conf.callbacks)},
};
const std::vector<std::tuple<size_t, ArgCallback>> write_callbacks {
{8, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite8)},
{16, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite16)},
{32, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite32)},
{64, DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite64)},
{8, Devirtualize<&A64::UserCallbacks::MemoryWrite8>(conf.callbacks)},
{16, Devirtualize<&A64::UserCallbacks::MemoryWrite16>(conf.callbacks)},
{32, Devirtualize<&A64::UserCallbacks::MemoryWrite32>(conf.callbacks)},
{64, Devirtualize<&A64::UserCallbacks::MemoryWrite64>(conf.callbacks)},
};
for (int vaddr_idx : idxes) {
@ -502,7 +503,8 @@ void A64EmitX64::EmitA64CallSupervisor(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
ASSERT(args[0].IsImmediate());
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);
});
// 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());
u64 pc = args[0].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[1], exception);
});
@ -524,7 +527,7 @@ void A64EmitX64::EmitA64ExceptionRaised(A64EmitContext& ctx, IR::Inst* inst) {
void A64EmitX64::EmitA64DataCacheOperationRaised(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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*) {
@ -538,7 +541,7 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) {
void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(inst);
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) {
@ -719,7 +722,7 @@ void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -730,7 +733,7 @@ void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -741,7 +744,7 @@ void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -752,7 +755,7 @@ void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -791,7 +794,7 @@ void A64EmitX64::EmitA64WriteMemory8(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -802,7 +805,7 @@ void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -813,7 +816,7 @@ void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -824,7 +827,7 @@ void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
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) {
@ -979,7 +982,8 @@ void A64EmitX64::EmitA64ExclusiveWriteMemory128(A64EmitContext& ctx, IR::Inst* i
void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) {
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(qword[r15 + offsetof(A64JitState, pc)], param[0]);
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) {
return RunCodeCallbacks{
std::make_unique<ArgCallback>(LookupBlock, reinterpret_cast<u64>(arg)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A64::UserCallbacks::AddTicks)),
std::make_unique<ArgCallback>(DEVIRT(cb, &A64::UserCallbacks::GetTicksRemaining)),
std::make_unique<ArgCallback>(Devirtualize<&A64::UserCallbacks::AddTicks>(cb)),
std::make_unique<ArgCallback>(Devirtualize<&A64::UserCallbacks::GetTicksRemaining>(cb)),
};
}

View file

@ -32,19 +32,19 @@ struct ThunkBuilder<R(C::*)(Args...), mfp> {
} // namespace impl
template <typename FunctionType, FunctionType mfp>
ArgCallback DevirtualizeGeneric(Common::mp::class_type_t<FunctionType>* this_) {
return ArgCallback{&impl::ThunkBuilder<FunctionType, mfp>::Thunk, reinterpret_cast<u64>(this_)};
template<auto mfp>
ArgCallback DevirtualizeGeneric(Common::mp::class_type_t<decltype(mfp)>* this_) {
return ArgCallback{&impl::ThunkBuilder<decltype(mfp), mfp>::Thunk, reinterpret_cast<u64>(this_)};
}
template <typename FunctionType, FunctionType mfp>
ArgCallback DevirtualizeWindows(Common::mp::class_type_t<FunctionType>* this_) {
template<auto mfp>
ArgCallback DevirtualizeWindows(Common::mp::class_type_t<decltype(mfp)>* this_) {
static_assert(sizeof(mfp) == 8);
return ArgCallback{Common::BitCast<u64>(mfp), reinterpret_cast<u64>(this_)};
}
template <typename FunctionType, FunctionType mfp>
ArgCallback DevirtualizeItanium(Common::mp::class_type_t<FunctionType>* this_) {
template<auto mfp>
ArgCallback DevirtualizeItanium(Common::mp::class_type_t<decltype(mfp)>* this_) {
struct MemberFunctionPointer {
/// For a non-virtual function, this is a simple function pointer.
/// 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};
}
template<auto mfp>
ArgCallback Devirtualize(Common::mp::class_type_t<decltype(mfp)>* this_) {
#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__)
#define DEVIRT(this_, mfp) Dynarmic::BackendX64::DevirtualizeItanium<decltype(mfp), mfp>(this_)
return DevirtualizeItanium<mfp>(this_);
#elif defined(_WIN32)
#define DEVIRT(this_, mfp) Dynarmic::BackendX64::DevirtualizeWindows<decltype(mfp), mfp>(this_)
return DevirtualizeWindows<mfp>(this_);
#else
#define DEVIRT(this_, mfp) Dynarmic::BackendX64::DevirtualizeGeneric<decltype(mfp), mfp>(this_)
return DevirtualizeGeneric<mfp>(this_);
#endif
}
} // namespace BackendX64
} // namespace Dynarmic