diff --git a/src/backend/x64/a32_emit_x64.cpp b/src/backend/x64/a32_emit_x64.cpp index fd00fcc0..a2ee984b 100644 --- a/src/backend/x64/a32_emit_x64.cpp +++ b/src/backend/x64/a32_emit_x64.cpp @@ -4,6 +4,7 @@ * General Public License version 2 or any later version. */ +#include #include #include #include @@ -85,7 +86,15 @@ A32EmitX64::BlockDescriptor A32EmitX64::Emit(IR::Block& block) { // Start emitting. EmitCondPrelude(block); - RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg, any_gpr, any_xmm}; + static const std::vector gpr_order = [this]{ + std::vector gprs{any_gpr}; + if (config.page_table) { + gprs.erase(std::find(gprs.begin(), gprs.end(), HostLoc::R14)); + } + return gprs; + }(); + + RegAlloc reg_alloc{code, A32JitState::SpillCount, SpillToOpArg, gpr_order, any_xmm}; A32EmitContext ctx{reg_alloc, block}; for (auto iter = block.begin(); iter != block.end(); ++iter) { @@ -778,21 +787,20 @@ static Xbyak::RegExp EmitVAddrLookup(BlockOfCode& code, RegAlloc& reg_alloc, Xbyak::Reg64 vaddr, std::optional arg_scratch = {}) { constexpr size_t page_bits = A32::UserConfig::PAGE_BITS; - const Xbyak::Reg64 page_table = arg_scratch ? *arg_scratch : reg_alloc.ScratchGpr(); - const Xbyak::Reg64 tmp = reg_alloc.ScratchGpr(); - code.mov(page_table, reinterpret_cast(config.page_table)); + const Xbyak::Reg64 page = arg_scratch ? *arg_scratch : reg_alloc.ScratchGpr(); + const Xbyak::Reg64 tmp = config.absolute_offset_page_table ? page : reg_alloc.ScratchGpr(); code.mov(tmp, vaddr); code.shr(tmp, static_cast(page_bits)); - code.mov(page_table, qword[page_table + tmp * sizeof(void*)]); - code.test(page_table, page_table); + code.mov(page, qword[r14 + tmp * sizeof(void*)]); + code.test(page, page); code.jz(abort); if (config.absolute_offset_page_table) { - return page_table + vaddr; + return page + vaddr; } constexpr size_t page_mask = (1 << page_bits) - 1; code.mov(tmp, vaddr); code.and_(tmp, static_cast(page_mask)); - return page_table + tmp; + return page + tmp; } template diff --git a/src/backend/x64/a32_interface.cpp b/src/backend/x64/a32_interface.cpp index 9c00f486..cb1fe53c 100644 --- a/src/backend/x64/a32_interface.cpp +++ b/src/backend/x64/a32_interface.cpp @@ -4,6 +4,7 @@ * General Public License version 2 or any later version. */ +#include #include #include @@ -19,6 +20,7 @@ #include "backend/x64/devirtualize.h" #include "backend/x64/jitstate_info.h" #include "common/assert.h" +#include "common/cast_util.h" #include "common/common_types.h" #include "common/llvm_disassemble.h" #include "common/scope_exit.h" @@ -39,9 +41,20 @@ static RunCodeCallbacks GenRunCodeCallbacks(A32::UserCallbacks* cb, CodePtr (*Lo }; } +static std::function GenRCP(const A32::UserConfig& config) { + if (!config.page_table) { + return [](BlockOfCode&){}; + } + + const u64 r14_value = Common::BitCast(config.page_table); + return [r14_value](BlockOfCode& code) { + code.mov(code.r14, r14_value); + }; +} + struct Jit::Impl { Impl(Jit* jit, A32::UserConfig config) - : block_of_code(GenRunCodeCallbacks(config.callbacks, &GetCurrentBlockThunk, this), JitStateInfo{jit_state}) + : block_of_code(GenRunCodeCallbacks(config.callbacks, &GetCurrentBlockThunk, this), JitStateInfo{jit_state}, GenRCP(config)) , emitter(block_of_code, config, jit) , config(std::move(config)) , jit_interface(jit) diff --git a/src/backend/x64/a64_interface.cpp b/src/backend/x64/a64_interface.cpp index 31d221d8..d53b5b13 100644 --- a/src/backend/x64/a64_interface.cpp +++ b/src/backend/x64/a64_interface.cpp @@ -34,11 +34,15 @@ static RunCodeCallbacks GenRunCodeCallbacks(A64::UserCallbacks* cb, CodePtr (*Lo }; } +static std::function GenRCP(const A64::UserConfig&) { + return [](BlockOfCode&){}; +} + struct Jit::Impl final { public: Impl(Jit* jit, UserConfig conf) : conf(conf) - , block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this), JitStateInfo{jit_state}) + , block_of_code(GenRunCodeCallbacks(conf.callbacks, &GetCurrentBlockThunk, this), JitStateInfo{jit_state}, GenRCP(conf)) , emitter(block_of_code, conf, jit) { ASSERT(conf.page_table_address_space_bits >= 12 && conf.page_table_address_space_bits <= 64); diff --git a/src/backend/x64/block_of_code.cpp b/src/backend/x64/block_of_code.cpp index 079a5cfa..470be9ea 100644 --- a/src/backend/x64/block_of_code.cpp +++ b/src/backend/x64/block_of_code.cpp @@ -75,14 +75,14 @@ void ProtectMemory(const void* base, size_t size, bool is_executable) { } // anonymous namespace -BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi) +BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, std::function rcp) : Xbyak::CodeGenerator(TOTAL_CODE_SIZE, nullptr, &s_allocator) , cb(std::move(cb)) , jsi(jsi) , constant_pool(*this, CONSTANT_POOL_SIZE) { EnableWriting(); - GenRunCode(); + GenRunCode(rcp); } void BlockOfCode::PreludeComplete() { @@ -155,7 +155,7 @@ void BlockOfCode::ForceReturnFromRunCode(bool mxcsr_already_exited) { jmp(return_from_run_code[index]); } -void BlockOfCode::GenRunCode() { +void BlockOfCode::GenRunCode(std::function rcp) { Xbyak::Label loop, enter_mxcsr_then_loop; align(); @@ -168,14 +168,16 @@ void BlockOfCode::GenRunCode() { ABI_PushCalleeSaveRegistersAndAdjustStack(*this); mov(r15, ABI_PARAM1); - mov(r14, ABI_PARAM2); // save temporarily in non-volatile register + mov(rbx, ABI_PARAM2); // save temporarily in non-volatile register cb.GetTicksRemaining->EmitCall(*this); mov(qword[r15 + jsi.offsetof_cycles_to_run], ABI_RETURN); mov(qword[r15 + jsi.offsetof_cycles_remaining], ABI_RETURN); + rcp(*this); + SwitchMxcsrOnEntry(); - jmp(r14); + jmp(rbx); align(); step_code = getCurr(); @@ -187,6 +189,8 @@ void BlockOfCode::GenRunCode() { mov(qword[r15 + jsi.offsetof_cycles_to_run], 1); mov(qword[r15 + jsi.offsetof_cycles_remaining], 1); + rcp(*this); + SwitchMxcsrOnEntry(); jmp(ABI_PARAM2); diff --git a/src/backend/x64/block_of_code.h b/src/backend/x64/block_of_code.h index 171efa68..e629c009 100644 --- a/src/backend/x64/block_of_code.h +++ b/src/backend/x64/block_of_code.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include @@ -31,7 +32,7 @@ struct RunCodeCallbacks { class BlockOfCode final : public Xbyak::CodeGenerator { public: - BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi); + BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, std::function rcp); BlockOfCode(const BlockOfCode&) = delete; /// Call when external emitters have finished emitting their preludes. @@ -162,7 +163,7 @@ private: static constexpr size_t MXCSR_ALREADY_EXITED = 1 << 0; static constexpr size_t FORCE_RETURN = 1 << 1; std::array return_from_run_code; - void GenRunCode(); + void GenRunCode(std::function rcp); Xbyak::util::Cpu cpu_info; };