backend_x64: Simplify dispatcher
This commit is contained in:
parent
523ae542f4
commit
1b37420459
4 changed files with 90 additions and 31 deletions
|
@ -18,9 +18,14 @@
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace BackendX64 {
|
namespace BackendX64 {
|
||||||
|
|
||||||
BlockOfCode::BlockOfCode(UserCallbacks cb) : Xbyak::CodeGenerator(128 * 1024 * 1024), cb(cb), constant_pool(this, 256) {
|
BlockOfCode::BlockOfCode(UserCallbacks cb, LookupBlockCallback lookup_block, void* lookup_block_arg)
|
||||||
|
: Xbyak::CodeGenerator(128 * 1024 * 1024)
|
||||||
|
, cb(cb)
|
||||||
|
, lookup_block(lookup_block)
|
||||||
|
, lookup_block_arg(lookup_block_arg)
|
||||||
|
, constant_pool(this, 256)
|
||||||
|
{
|
||||||
GenRunCode();
|
GenRunCode();
|
||||||
GenReturnFromRunCode();
|
|
||||||
GenMemoryAccessors();
|
GenMemoryAccessors();
|
||||||
unwind_handler.Register(this);
|
unwind_handler.Register(this);
|
||||||
user_code_begin = getCurr<CodePtr>();
|
user_code_begin = getCurr<CodePtr>();
|
||||||
|
@ -30,20 +35,32 @@ void BlockOfCode::ClearCache() {
|
||||||
SetCodePtr(user_code_begin);
|
SetCodePtr(user_code_begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t BlockOfCode::RunCode(JitState* jit_state, CodePtr basic_block, size_t cycles_to_run) const {
|
size_t BlockOfCode::RunCode(JitState* jit_state, size_t cycles_to_run) const {
|
||||||
constexpr size_t max_cycles_to_run = static_cast<size_t>(std::numeric_limits<decltype(jit_state->cycles_remaining)>::max());
|
constexpr size_t max_cycles_to_run = static_cast<size_t>(std::numeric_limits<decltype(jit_state->cycles_remaining)>::max());
|
||||||
ASSERT(cycles_to_run <= max_cycles_to_run);
|
ASSERT(cycles_to_run <= max_cycles_to_run);
|
||||||
|
|
||||||
jit_state->cycles_remaining = cycles_to_run;
|
jit_state->cycles_remaining = cycles_to_run;
|
||||||
run_code(jit_state, basic_block);
|
run_code(jit_state);
|
||||||
return cycles_to_run - jit_state->cycles_remaining; // Return number of cycles actually run.
|
return cycles_to_run - jit_state->cycles_remaining; // Return number of cycles actually run.
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::ReturnFromRunCode(bool MXCSR_switch) {
|
void BlockOfCode::ReturnFromRunCode(bool MXCSR_switch) {
|
||||||
jmp(MXCSR_switch ? return_from_run_code : return_from_run_code_without_mxcsr_switch);
|
size_t index = 0;
|
||||||
|
if (!MXCSR_switch)
|
||||||
|
index |= NO_SWITCH_MXCSR;
|
||||||
|
jmp(return_from_run_code[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlockOfCode::ForceReturnFromRunCode(bool MXCSR_switch) {
|
||||||
|
size_t index = FORCE_RETURN;
|
||||||
|
if (!MXCSR_switch)
|
||||||
|
index |= NO_SWITCH_MXCSR;
|
||||||
|
jmp(return_from_run_code[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::GenRunCode() {
|
void BlockOfCode::GenRunCode() {
|
||||||
|
Xbyak::Label loop;
|
||||||
|
|
||||||
align();
|
align();
|
||||||
run_code = getCurr<RunCodeFuncType>();
|
run_code = getCurr<RunCodeFuncType>();
|
||||||
|
|
||||||
|
@ -54,19 +71,44 @@ void BlockOfCode::GenRunCode() {
|
||||||
ABI_PushCalleeSaveRegistersAndAdjustStack(this);
|
ABI_PushCalleeSaveRegistersAndAdjustStack(this);
|
||||||
|
|
||||||
mov(r15, ABI_PARAM1);
|
mov(r15, ABI_PARAM1);
|
||||||
|
|
||||||
|
L(loop);
|
||||||
|
mov(ABI_PARAM1, u64(lookup_block_arg));
|
||||||
|
CallFunction(lookup_block);
|
||||||
|
|
||||||
SwitchMxcsrOnEntry();
|
SwitchMxcsrOnEntry();
|
||||||
jmp(ABI_PARAM2);
|
jmp(ABI_RETURN);
|
||||||
}
|
|
||||||
|
|
||||||
void BlockOfCode::GenReturnFromRunCode() {
|
|
||||||
return_from_run_code = getCurr<const void*>();
|
|
||||||
|
|
||||||
|
// Return from run code variants
|
||||||
|
const auto emit_return_from_run_code = [this, &loop](bool no_mxcsr_switch, bool force_return){
|
||||||
|
if (!no_mxcsr_switch) {
|
||||||
SwitchMxcsrOnExit();
|
SwitchMxcsrOnExit();
|
||||||
|
}
|
||||||
|
|
||||||
return_from_run_code_without_mxcsr_switch = getCurr<const void*>();
|
if (!force_return) {
|
||||||
|
cmp(qword[r15 + offsetof(JitState, cycles_remaining)], 0);
|
||||||
|
jg(loop);
|
||||||
|
}
|
||||||
|
|
||||||
ABI_PopCalleeSaveRegistersAndAdjustStack(this);
|
ABI_PopCalleeSaveRegistersAndAdjustStack(this);
|
||||||
ret();
|
ret();
|
||||||
|
};
|
||||||
|
|
||||||
|
align();
|
||||||
|
return_from_run_code[0] = getCurr<const void*>();
|
||||||
|
emit_return_from_run_code(false, false);
|
||||||
|
|
||||||
|
align();
|
||||||
|
return_from_run_code[NO_SWITCH_MXCSR] = getCurr<const void*>();
|
||||||
|
emit_return_from_run_code(true, false);
|
||||||
|
|
||||||
|
align();
|
||||||
|
return_from_run_code[FORCE_RETURN] = getCurr<const void*>();
|
||||||
|
emit_return_from_run_code(false, true);
|
||||||
|
|
||||||
|
align();
|
||||||
|
return_from_run_code[NO_SWITCH_MXCSR | FORCE_RETURN] = getCurr<const void*>();
|
||||||
|
emit_return_from_run_code(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockOfCode::GenMemoryAccessors() {
|
void BlockOfCode::GenMemoryAccessors() {
|
||||||
|
|
|
@ -19,17 +19,21 @@
|
||||||
namespace Dynarmic {
|
namespace Dynarmic {
|
||||||
namespace BackendX64 {
|
namespace BackendX64 {
|
||||||
|
|
||||||
|
using LookupBlockCallback = CodePtr(*)(void*);
|
||||||
|
|
||||||
class BlockOfCode final : public Xbyak::CodeGenerator {
|
class BlockOfCode final : public Xbyak::CodeGenerator {
|
||||||
public:
|
public:
|
||||||
explicit BlockOfCode(UserCallbacks cb);
|
BlockOfCode(UserCallbacks cb, LookupBlockCallback lookup_block, void* lookup_block_arg);
|
||||||
|
|
||||||
/// Clears this block of code and resets code pointer to beginning.
|
/// Clears this block of code and resets code pointer to beginning.
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
|
||||||
/// Runs emulated code for approximately `cycles_to_run` cycles.
|
/// Runs emulated code for approximately `cycles_to_run` cycles.
|
||||||
size_t RunCode(JitState* jit_state, CodePtr basic_block, size_t cycles_to_run) const;
|
size_t RunCode(JitState* jit_state, size_t cycles_to_run) const;
|
||||||
/// Code emitter: Returns to host
|
/// Code emitter: Returns to dispatcher
|
||||||
void ReturnFromRunCode(bool MXCSR_switch = true);
|
void ReturnFromRunCode(bool MXCSR_switch = true);
|
||||||
|
/// Code emitter: Returns to dispatcher, forces return to host
|
||||||
|
void ForceReturnFromRunCode(bool MXCSR_switch = true);
|
||||||
/// Code emitter: Makes guest MXCSR the current MXCSR
|
/// Code emitter: Makes guest MXCSR the current MXCSR
|
||||||
void SwitchMxcsrOnEntry();
|
void SwitchMxcsrOnEntry();
|
||||||
/// Code emitter: Makes saved host MXCSR the current MXCSR
|
/// Code emitter: Makes saved host MXCSR the current MXCSR
|
||||||
|
@ -56,7 +60,11 @@ public:
|
||||||
Xbyak::Address MConst(u64 constant);
|
Xbyak::Address MConst(u64 constant);
|
||||||
|
|
||||||
const void* GetReturnFromRunCodeAddress() const {
|
const void* GetReturnFromRunCodeAddress() const {
|
||||||
return return_from_run_code;
|
return return_from_run_code[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* GetForceReturnFromRunCodeAddress() const {
|
||||||
|
return return_from_run_code[FORCE_RETURN];
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* GetMemoryReadCallback(size_t bit_size) const {
|
const void* GetMemoryReadCallback(size_t bit_size) const {
|
||||||
|
@ -116,18 +124,20 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UserCallbacks cb;
|
UserCallbacks cb;
|
||||||
|
LookupBlockCallback lookup_block;
|
||||||
|
void* lookup_block_arg;
|
||||||
|
|
||||||
CodePtr user_code_begin;
|
CodePtr user_code_begin;
|
||||||
|
|
||||||
ConstantPool constant_pool;
|
ConstantPool constant_pool;
|
||||||
|
|
||||||
using RunCodeFuncType = void(*)(JitState*, CodePtr);
|
using RunCodeFuncType = void(*)(JitState*);
|
||||||
RunCodeFuncType run_code = nullptr;
|
RunCodeFuncType run_code = nullptr;
|
||||||
|
static constexpr size_t NO_SWITCH_MXCSR = 1 << 0;
|
||||||
|
static constexpr size_t FORCE_RETURN = 1 << 1;
|
||||||
|
std::array<const void*, 4> return_from_run_code;
|
||||||
void GenRunCode();
|
void GenRunCode();
|
||||||
|
|
||||||
const void* return_from_run_code = nullptr;
|
|
||||||
const void* return_from_run_code_without_mxcsr_switch = nullptr;
|
|
||||||
void GenReturnFromRunCode();
|
|
||||||
|
|
||||||
const void* read_memory_8 = nullptr;
|
const void* read_memory_8 = nullptr;
|
||||||
const void* read_memory_16 = nullptr;
|
const void* read_memory_16 = nullptr;
|
||||||
const void* read_memory_32 = nullptr;
|
const void* read_memory_32 = nullptr;
|
||||||
|
|
|
@ -3403,7 +3403,7 @@ void EmitX64::EmitTerminal(IR::Term::LinkBlock terminal, IR::LocationDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
code->mov(MJitStateReg(Arm::Reg::PC), terminal.next.PC());
|
code->mov(MJitStateReg(Arm::Reg::PC), terminal.next.PC());
|
||||||
code->ReturnFromRunCode(); // TODO: Check cycles, Properly do a link
|
code->ForceReturnFromRunCode(); // TODO: Check cycles, Properly do a link
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitX64::EmitTerminal(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) {
|
void EmitX64::EmitTerminal(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) {
|
||||||
|
@ -3464,7 +3464,7 @@ void EmitX64::EmitTerminal(IR::Term::CheckHalt terminal, IR::LocationDescriptor
|
||||||
using namespace Xbyak::util;
|
using namespace Xbyak::util;
|
||||||
|
|
||||||
code->cmp(code->byte[r15 + offsetof(JitState, halt_requested)], u8(0));
|
code->cmp(code->byte[r15 + offsetof(JitState, halt_requested)], u8(0));
|
||||||
code->jne(code->GetReturnFromRunCodeAddress());
|
code->jne(code->GetForceReturnFromRunCodeAddress());
|
||||||
EmitTerminal(terminal.else_, initial_location);
|
EmitTerminal(terminal.else_, initial_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ using namespace BackendX64;
|
||||||
|
|
||||||
struct Jit::Impl {
|
struct Jit::Impl {
|
||||||
Impl(Jit* jit, UserCallbacks callbacks)
|
Impl(Jit* jit, UserCallbacks callbacks)
|
||||||
: block_of_code(callbacks)
|
: block_of_code(callbacks, &GetCurrentBlock, this)
|
||||||
, jit_state()
|
, jit_state()
|
||||||
, emitter(&block_of_code, callbacks, jit)
|
, emitter(&block_of_code, callbacks, jit)
|
||||||
, callbacks(callbacks)
|
, callbacks(callbacks)
|
||||||
|
@ -48,12 +48,7 @@ struct Jit::Impl {
|
||||||
std::queue<Common::AddressRange> invalid_cache_ranges;
|
std::queue<Common::AddressRange> invalid_cache_ranges;
|
||||||
|
|
||||||
size_t Execute(size_t cycle_count) {
|
size_t Execute(size_t cycle_count) {
|
||||||
u32 pc = jit_state.Reg[15];
|
return block_of_code.RunCode(&jit_state, cycle_count);
|
||||||
|
|
||||||
IR::LocationDescriptor descriptor{pc, Arm::PSR{jit_state.Cpsr}, Arm::FPSCR{jit_state.FPSCR_mode}};
|
|
||||||
|
|
||||||
CodePtr entrypoint = GetBasicBlock(descriptor).entrypoint;
|
|
||||||
return block_of_code.RunCode(&jit_state, entrypoint, cycle_count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Disassemble(const IR::LocationDescriptor& descriptor) {
|
std::string Disassemble(const IR::LocationDescriptor& descriptor) {
|
||||||
|
@ -119,6 +114,18 @@ struct Jit::Impl {
|
||||||
private:
|
private:
|
||||||
Jit* jit_interface;
|
Jit* jit_interface;
|
||||||
|
|
||||||
|
static CodePtr GetCurrentBlock(void *this_voidptr) {
|
||||||
|
Jit::Impl& this_ = *reinterpret_cast<Jit::Impl*>(this_voidptr);
|
||||||
|
JitState& jit_state = this_.jit_state;
|
||||||
|
|
||||||
|
u32 pc = jit_state.Reg[15];
|
||||||
|
Arm::PSR cpsr{jit_state.Cpsr};
|
||||||
|
Arm::FPSCR fpscr{jit_state.FPSCR_mode};
|
||||||
|
IR::LocationDescriptor descriptor{pc, cpsr, fpscr};
|
||||||
|
|
||||||
|
return this_.GetBasicBlock(descriptor).entrypoint;
|
||||||
|
}
|
||||||
|
|
||||||
EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
EmitX64::BlockDescriptor GetBasicBlock(IR::LocationDescriptor descriptor) {
|
||||||
auto block = emitter.GetBasicBlock(descriptor);
|
auto block = emitter.GetBasicBlock(descriptor);
|
||||||
if (block)
|
if (block)
|
||||||
|
|
Loading…
Reference in a new issue