From 1b374204591274dff475048674ba916597b954d1 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Fri, 7 Apr 2017 10:52:44 +0100 Subject: [PATCH] backend_x64: Simplify dispatcher --- src/backend_x64/block_of_code.cpp | 68 +++++++++++++++++++++++++------ src/backend_x64/block_of_code.h | 28 +++++++++---- src/backend_x64/emit_x64.cpp | 4 +- src/backend_x64/interface_x64.cpp | 21 ++++++---- 4 files changed, 90 insertions(+), 31 deletions(-) diff --git a/src/backend_x64/block_of_code.cpp b/src/backend_x64/block_of_code.cpp index e4f4ec02..7148bd40 100644 --- a/src/backend_x64/block_of_code.cpp +++ b/src/backend_x64/block_of_code.cpp @@ -18,9 +18,14 @@ namespace Dynarmic { 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(); - GenReturnFromRunCode(); GenMemoryAccessors(); unwind_handler.Register(this); user_code_begin = getCurr(); @@ -30,20 +35,32 @@ void BlockOfCode::ClearCache() { 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(std::numeric_limitscycles_remaining)>::max()); ASSERT(cycles_to_run <= max_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. } 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() { + Xbyak::Label loop; + align(); run_code = getCurr(); @@ -54,19 +71,44 @@ void BlockOfCode::GenRunCode() { ABI_PushCalleeSaveRegistersAndAdjustStack(this); mov(r15, ABI_PARAM1); + + L(loop); + mov(ABI_PARAM1, u64(lookup_block_arg)); + CallFunction(lookup_block); + SwitchMxcsrOnEntry(); - jmp(ABI_PARAM2); -} + jmp(ABI_RETURN); -void BlockOfCode::GenReturnFromRunCode() { - return_from_run_code = getCurr(); + // 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(); + if (!force_return) { + cmp(qword[r15 + offsetof(JitState, cycles_remaining)], 0); + jg(loop); + } - return_from_run_code_without_mxcsr_switch = getCurr(); + ABI_PopCalleeSaveRegistersAndAdjustStack(this); + ret(); + }; - ABI_PopCalleeSaveRegistersAndAdjustStack(this); - ret(); + align(); + return_from_run_code[0] = getCurr(); + emit_return_from_run_code(false, false); + + align(); + return_from_run_code[NO_SWITCH_MXCSR] = getCurr(); + emit_return_from_run_code(true, false); + + align(); + return_from_run_code[FORCE_RETURN] = getCurr(); + emit_return_from_run_code(false, true); + + align(); + return_from_run_code[NO_SWITCH_MXCSR | FORCE_RETURN] = getCurr(); + emit_return_from_run_code(true, true); } void BlockOfCode::GenMemoryAccessors() { diff --git a/src/backend_x64/block_of_code.h b/src/backend_x64/block_of_code.h index 9bf1b7bd..ca1bce9d 100644 --- a/src/backend_x64/block_of_code.h +++ b/src/backend_x64/block_of_code.h @@ -19,17 +19,21 @@ namespace Dynarmic { namespace BackendX64 { +using LookupBlockCallback = CodePtr(*)(void*); + class BlockOfCode final : public Xbyak::CodeGenerator { 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. void ClearCache(); /// Runs emulated code for approximately `cycles_to_run` cycles. - size_t RunCode(JitState* jit_state, CodePtr basic_block, size_t cycles_to_run) const; - /// Code emitter: Returns to host + size_t RunCode(JitState* jit_state, size_t cycles_to_run) const; + /// Code emitter: Returns to dispatcher 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 void SwitchMxcsrOnEntry(); /// Code emitter: Makes saved host MXCSR the current MXCSR @@ -56,7 +60,11 @@ public: Xbyak::Address MConst(u64 constant); 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 { @@ -116,18 +124,20 @@ public: private: UserCallbacks cb; + LookupBlockCallback lookup_block; + void* lookup_block_arg; + CodePtr user_code_begin; ConstantPool constant_pool; - using RunCodeFuncType = void(*)(JitState*, CodePtr); + using RunCodeFuncType = void(*)(JitState*); RunCodeFuncType run_code = nullptr; + static constexpr size_t NO_SWITCH_MXCSR = 1 << 0; + static constexpr size_t FORCE_RETURN = 1 << 1; + std::array return_from_run_code; 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_16 = nullptr; const void* read_memory_32 = nullptr; diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index b13adace..1d9d3b82 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -3403,7 +3403,7 @@ void EmitX64::EmitTerminal(IR::Term::LinkBlock terminal, IR::LocationDescriptor } 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) { @@ -3464,7 +3464,7 @@ void EmitX64::EmitTerminal(IR::Term::CheckHalt terminal, IR::LocationDescriptor using namespace Xbyak::util; code->cmp(code->byte[r15 + offsetof(JitState, halt_requested)], u8(0)); - code->jne(code->GetReturnFromRunCodeAddress()); + code->jne(code->GetForceReturnFromRunCodeAddress()); EmitTerminal(terminal.else_, initial_location); } diff --git a/src/backend_x64/interface_x64.cpp b/src/backend_x64/interface_x64.cpp index 632cee3c..151c16e6 100644 --- a/src/backend_x64/interface_x64.cpp +++ b/src/backend_x64/interface_x64.cpp @@ -32,7 +32,7 @@ using namespace BackendX64; struct Jit::Impl { Impl(Jit* jit, UserCallbacks callbacks) - : block_of_code(callbacks) + : block_of_code(callbacks, &GetCurrentBlock, this) , jit_state() , emitter(&block_of_code, callbacks, jit) , callbacks(callbacks) @@ -48,12 +48,7 @@ struct Jit::Impl { std::queue invalid_cache_ranges; size_t Execute(size_t cycle_count) { - u32 pc = jit_state.Reg[15]; - - 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); + return block_of_code.RunCode(&jit_state, cycle_count); } std::string Disassemble(const IR::LocationDescriptor& descriptor) { @@ -119,6 +114,18 @@ struct Jit::Impl { private: Jit* jit_interface; + static CodePtr GetCurrentBlock(void *this_voidptr) { + Jit::Impl& this_ = *reinterpret_cast(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) { auto block = emitter.GetBasicBlock(descriptor); if (block)