callback: Properly handle calls with return pointers and simplify interface
This commit is contained in:
parent
15871910af
commit
ad428cbd7a
5 changed files with 86 additions and 128 deletions
|
@ -590,9 +590,9 @@ 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, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {
|
||||
code.mov(param1, pc);
|
||||
code.mov(param2, exception);
|
||||
DEVIRT(config.callbacks, &A32::UserCallbacks::ExceptionRaised).EmitCall(code, [&](RegList param) {
|
||||
code.mov(param[0], pc);
|
||||
code.mov(param[1], exception);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -293,8 +293,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, [&](Xbyak::Reg64 param1) {
|
||||
code.mov(param1.cvt32(), imm);
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::CallSVC).EmitCall(code, [&](RegList param) {
|
||||
code.mov(param[0], imm);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -304,42 +304,34 @@ 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, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {
|
||||
code.mov(param1, pc);
|
||||
code.mov(param2, exception);
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::ExceptionRaised).EmitCall(code, [&](RegList param) {
|
||||
code.mov(param[0], pc);
|
||||
code.mov(param[1], exception);
|
||||
});
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead8).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead8).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead16).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead16).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead32).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead32).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead64).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(inst, {}, args[0]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead64).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
|
@ -348,11 +340,10 @@ void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
|||
|
||||
static_assert(ABI_SHADOW_SPACE >= 16);
|
||||
ctx.reg_alloc.HostCall(nullptr, {}, {}, args[0]);
|
||||
code.lea(code.ABI_PARAM2, ptr[rsp]);
|
||||
code.sub(rsp, ABI_SHADOW_SPACE);
|
||||
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead128).EmitCall(code, [&](Xbyak::Reg64 return_value, Xbyak::Reg64 vaddr) {
|
||||
ASSERT(return_value == code.ABI_PARAM2 && vaddr == code.ABI_PARAM3);
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead128).EmitCallWithReturnPointer(code, [&](Xbyak::Reg64 return_value_ptr, RegList) {
|
||||
code.lea(return_value_ptr, ptr[rsp]);
|
||||
code.sub(rsp, ABI_SHADOW_SPACE);
|
||||
});
|
||||
|
||||
Xbyak::Xmm result = xmm0;
|
||||
|
@ -361,11 +352,10 @@ void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
|||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
#else
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead128).EmitCall(code, [&](Xbyak::Reg64 vaddr) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(nullptr, {}, args[0]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryRead128).EmitCall(code);
|
||||
|
||||
Xbyak::Xmm result = xmm0;
|
||||
if (code.DoesCpuSupport(Xbyak::util::Cpu::tSSE41)) {
|
||||
code.movq(result, code.ABI_RETURN);
|
||||
|
@ -381,35 +371,27 @@ void A64EmitX64::EmitA64ReadMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
|||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory8(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite8).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2 && value == code.ABI_PARAM3);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite8).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory16(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite16).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2 && value == code.ABI_PARAM3);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite16).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory32(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite32).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2 && value == code.ABI_PARAM3);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite32).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory64(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite64).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2 && value == code.ABI_PARAM3);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.HostCall(nullptr, {}, args[0], args[1]);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite64).EmitCall(code);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
|
@ -425,14 +407,10 @@ void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
|||
code.sub(rsp, ABI_SHADOW_SPACE);
|
||||
code.movaps(xword[code.ABI_PARAM3], xmm_value);
|
||||
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite128).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value_ptr) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2 && value_ptr == code.ABI_PARAM3);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite128).EmitCall(code);
|
||||
|
||||
code.add(rsp, ABI_SHADOW_SPACE);
|
||||
#else
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite128).EmitCall(code, [&](Xbyak::Reg64 vaddr, Xbyak::Reg64 value0, Xbyak::Reg64 value1) {
|
||||
ASSERT(vaddr == code.ABI_PARAM2 && value0 == code.ABI_PARAM3 && value1 == code.ABI_PARAM4);
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
ctx.reg_alloc.Use(args[0], ABI_PARAM2);
|
||||
ctx.reg_alloc.ScratchGpr({ABI_PARAM3});
|
||||
|
@ -449,16 +427,16 @@ void A64EmitX64::EmitA64WriteMemory128(A64EmitContext& ctx, IR::Inst* inst) {
|
|||
}
|
||||
ctx.reg_alloc.EndOfAllocScope();
|
||||
ctx.reg_alloc.HostCall(nullptr);
|
||||
});
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::MemoryWrite128).EmitCall(code);
|
||||
#endif
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor) {
|
||||
code.SwitchMxcsrOnExit();
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::InterpreterFallback).EmitCall(code, [&](Xbyak::Reg64 param1, Xbyak::Reg64 param2) {
|
||||
code.mov(param1, A64::LocationDescriptor{terminal.next}.PC());
|
||||
code.mov(qword[r15 + offsetof(A64JitState, pc)], param1);
|
||||
code.mov(param2.cvt32(), terminal.num_instructions);
|
||||
DEVIRT(conf.callbacks, &A64::UserCallbacks::InterpreterFallback).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);
|
||||
});
|
||||
code.ReturnFromRunCode(true); // TODO: Check cycles
|
||||
}
|
||||
|
|
|
@ -152,9 +152,9 @@ void BlockOfCode::GenRunCode() {
|
|||
SwitchMxcsrOnExit();
|
||||
}
|
||||
|
||||
cb.AddTicks->EmitCall(*this, [this](Xbyak::Reg64 param1) {
|
||||
mov(param1, qword[r15 + jsi.offsetof_cycles_to_run]);
|
||||
sub(param1, qword[r15 + jsi.offsetof_cycles_remaining]);
|
||||
cb.AddTicks->EmitCall(*this, [this](RegList param) {
|
||||
mov(param[0], qword[r15 + jsi.offsetof_cycles_to_run]);
|
||||
sub(param[0], qword[r15 + jsi.offsetof_cycles_remaining]);
|
||||
});
|
||||
|
||||
ABI_PopCalleeSaveRegistersAndAdjustStack(*this);
|
||||
|
|
|
@ -9,47 +9,30 @@
|
|||
|
||||
namespace Dynarmic::BackendX64 {
|
||||
|
||||
void SimpleCallback::EmitCall(BlockOfCode& code, std::function<void()> l) {
|
||||
l();
|
||||
void SimpleCallback::EmitCall(BlockOfCode& code, std::function<void(RegList)> l) {
|
||||
l({code.ABI_PARAM1, code.ABI_PARAM2, code.ABI_PARAM3, code.ABI_PARAM4});
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
void SimpleCallback::EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64)> l) {
|
||||
l(code.ABI_PARAM1);
|
||||
void SimpleCallback::EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Xbyak::Reg64, RegList)> l) {
|
||||
l(code.ABI_PARAM1, {code.ABI_PARAM2, code.ABI_PARAM3, code.ABI_PARAM4});
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
void SimpleCallback::EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64)> l) {
|
||||
l(code.ABI_PARAM1, code.ABI_PARAM2);
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
void SimpleCallback::EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64, Xbyak::Reg64)> l) {
|
||||
l(code.ABI_PARAM1, code.ABI_PARAM2, code.ABI_PARAM3);
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
void ArgCallback::EmitCall(BlockOfCode& code, std::function<void()> l) {
|
||||
l();
|
||||
void ArgCallback::EmitCall(BlockOfCode& code, std::function<void(RegList)> l) {
|
||||
l({code.ABI_PARAM2, code.ABI_PARAM3, code.ABI_PARAM4});
|
||||
code.mov(code.ABI_PARAM1, arg);
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
void ArgCallback::EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64)> l) {
|
||||
l(code.ABI_PARAM2);
|
||||
code.mov(code.ABI_PARAM1, arg);
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
void ArgCallback::EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64)> l) {
|
||||
l(code.ABI_PARAM2, code.ABI_PARAM3);
|
||||
code.mov(code.ABI_PARAM1, arg);
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
void ArgCallback::EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64, Xbyak::Reg64)> l) {
|
||||
l(code.ABI_PARAM2, code.ABI_PARAM3, code.ABI_PARAM4);
|
||||
void ArgCallback::EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Xbyak::Reg64, RegList)> l) {
|
||||
#if defined(WIN32) && !defined(__MINGW64__)
|
||||
l(code.ABI_PARAM2, {code.ABI_PARAM3, code.ABI_PARAM4});
|
||||
code.mov(code.ABI_PARAM1, arg);
|
||||
#else
|
||||
l(code.ABI_PARAM1, {code.ABI_PARAM3, code.ABI_PARAM4});
|
||||
code.mov(code.ABI_PARAM2, arg);
|
||||
#endif
|
||||
code.CallFunction(fn);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include <xbyak.h>
|
||||
|
||||
|
@ -14,16 +15,16 @@
|
|||
|
||||
namespace Dynarmic::BackendX64 {
|
||||
|
||||
using RegList = std::vector<Xbyak::Reg64>;
|
||||
|
||||
class BlockOfCode;
|
||||
|
||||
class Callback {
|
||||
public:
|
||||
virtual ~Callback() = default;
|
||||
|
||||
virtual void EmitCall(BlockOfCode& code, std::function<void()> fn = []{}) = 0;
|
||||
virtual void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64)> fn) = 0;
|
||||
virtual void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64)> fn) = 0;
|
||||
virtual void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64, Xbyak::Reg64)> fn) = 0;
|
||||
virtual void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList){}) = 0;
|
||||
virtual void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Xbyak::Reg64, RegList)> fn) = 0;
|
||||
};
|
||||
|
||||
class SimpleCallback final : public Callback {
|
||||
|
@ -33,10 +34,8 @@ public:
|
|||
|
||||
~SimpleCallback() override = default;
|
||||
|
||||
void EmitCall(BlockOfCode& code, std::function<void()> l = []{}) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64)> l) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64)> l) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64, Xbyak::Reg64)> l) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList){}) override;
|
||||
void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Xbyak::Reg64, RegList)> fn) override;
|
||||
|
||||
private:
|
||||
void (*fn)();
|
||||
|
@ -49,10 +48,8 @@ public:
|
|||
|
||||
~ArgCallback() override = default;
|
||||
|
||||
void EmitCall(BlockOfCode& code, std::function<void()> l = []{}) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64)> l) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64)> l) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(Xbyak::Reg64, Xbyak::Reg64, Xbyak::Reg64)> l) override;
|
||||
void EmitCall(BlockOfCode& code, std::function<void(RegList)> fn = [](RegList){}) override;
|
||||
void EmitCallWithReturnPointer(BlockOfCode& code, std::function<void(Xbyak::Reg64, RegList)> fn) override;
|
||||
|
||||
private:
|
||||
void (*fn)();
|
||||
|
|
Loading…
Reference in a new issue