From 8ca33bcb94617c8caf64a7cd7a31b4ad0a5952a3 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 9 Apr 2018 17:45:37 +0300 Subject: [PATCH] SPU ASMJIT v2.0 Use X86Assembler and blocks --- Utilities/sysinfo.cpp | 6 + Utilities/sysinfo.h | 2 + rpcs3/Emu/CPU/CPUDisAsm.h | 4 +- rpcs3/Emu/Cell/RawSPUThread.cpp | 2 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 2011 ++++++++++++------------ rpcs3/Emu/Cell/SPUASMJITRecompiler.h | 90 +- rpcs3/Emu/Cell/SPUAnalyser.cpp | 101 +- rpcs3/Emu/Cell/SPUAnalyser.h | 26 +- rpcs3/Emu/Cell/SPURecompiler.cpp | 211 ++- rpcs3/Emu/Cell/SPURecompiler.h | 31 +- rpcs3/Emu/Cell/SPUThread.cpp | 35 +- rpcs3/Emu/Cell/SPUThread.h | 31 +- 12 files changed, 1363 insertions(+), 1187 deletions(-) diff --git a/Utilities/sysinfo.cpp b/Utilities/sysinfo.cpp index 00075a5ec7..921dc7c2f0 100644 --- a/Utilities/sysinfo.cpp +++ b/Utilities/sysinfo.cpp @@ -13,6 +13,12 @@ bool utils::has_ssse3() return g_value; } +bool utils::has_sse41() +{ + static const bool g_value = get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x80000; + return g_value; +} + bool utils::has_avx() { static const bool g_value = get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x10000000 && (get_cpuid(1, 0)[2] & 0x0C000000) == 0x0C000000 && (get_xgetbv(0) & 0x6) == 0x6; diff --git a/Utilities/sysinfo.h b/Utilities/sysinfo.h index ad55ba724e..1fbdd9e5f9 100644 --- a/Utilities/sysinfo.h +++ b/Utilities/sysinfo.h @@ -29,6 +29,8 @@ namespace utils bool has_ssse3(); + bool has_sse41(); + bool has_avx(); bool has_avx2(); diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index 8991f55c84..f64d20d356 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -42,10 +42,10 @@ protected: public: std::string last_opcode; u32 dump_pc; - u8* offset; + const u8* offset; protected: - CPUDisAsm(CPUDisAsmMode mode) + CPUDisAsm(CPUDisAsmMode mode) : m_mode(mode) , offset(0) { diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 448dc198b9..cffcdc7661 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -37,7 +37,7 @@ void RawSPUThread::on_init(const std::shared_ptr& _this) } RawSPUThread::RawSPUThread(const std::string& name) - : SPUThread(name) + : SPUThread(name, 0, nullptr) { } diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index ad673f95a2..81c70f11d0 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -1,19 +1,17 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" +#include "Emu/IdManager.h" #include "SPUDisAsm.h" #include "SPUThread.h" #include "SPUInterpreter.h" -#include "SPUASMJITRecompiler.h" #include "Utilities/sysinfo.h" #include +#include -#define ASMJIT_STATIC -#define ASMJIT_DEBUG - -#include "asmjit.h" +#include "SPUASMJITRecompiler.h" #define SPU_OFF_128(x, ...) asmjit::x86::oword_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__)) #define SPU_OFF_64(x, ...) asmjit::x86::qword_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__)) @@ -24,37 +22,51 @@ extern const spu_decoder g_spu_interpreter_fast; // TODO: avoid const spu_decoder s_spu_decoder; -spu_recompiler::spu_recompiler() - : m_jit(std::make_shared()) -{ - LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created..."); +extern u64 get_timebased_time(); +std::unique_ptr spu_recompiler_base::make_asmjit_recompiler(SPUThread& spu) +{ + return std::make_unique(spu); +} + +spu_runtime::spu_runtime() +{ if (g_cfg.core.spu_debug) { fs::file log(Emu.GetCachePath() + "SPUJIT.log", fs::rewrite); - log.write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); + log.write(fmt::format("SPU JIT Log...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); } + + LOG_SUCCESS(SPU, "SPU Recompiler Runtime (ASMJIT) initialized..."); + + // Initialize lookup table + for (auto& v : m_dispatcher) + { + v.raw() = &spu_recompiler_base::dispatch; + } + + // Initialize "empty" block + m_map[std::vector()] = &spu_recompiler_base::dispatch; } -void spu_recompiler::compile(spu_function_t& f) +spu_recompiler::spu_recompiler(SPUThread& spu) + : spu_recompiler_base(spu) + , m_rt(std::make_shared()) { - std::lock_guard lock(m_mutex); +} - if (f.compiled) +spu_function_t spu_recompiler::compile(const std::vector& func) +{ + // Initialize if necessary + if (!m_spurt) { - // return if function already compiled - return; - } - - if (f.addr >= 0x40000 || f.addr % 4 || f.size == 0 || f.size > 0x40000 - f.addr || f.size % 4) - { - fmt::throw_exception("Invalid SPU function (addr=0x%05x, size=0x%x)" HERE, f.addr, f.size); + m_spurt = fxm::get_always(); } using namespace asmjit; SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode); - dis_asm.offset = reinterpret_cast(f.data.data()) - f.addr; + dis_asm.offset = reinterpret_cast(func.data() + 1) - func[0]; StringLogger logger; logger.addOptions(Logger::kOptionBinaryForm); @@ -63,121 +75,505 @@ void spu_recompiler::compile(spu_function_t& f) if (g_cfg.core.spu_debug) { - fmt::append(log, "========== SPU FUNCTION 0x%05x - 0x%05x ==========\n\n", f.addr, f.addr + f.size); + fmt::append(log, "========== SPU BLOCK 0x%05x (size %u) ==========\n\n", func[0], func.size() - 1); } - this->m_func = &f; - asmjit::CodeHolder code; - code.init(m_jit->getCodeInfo()); - this->codeHolder = &code; + code.init(m_rt->getCodeInfo()); - X86Compiler compiler(&code); + X86Assembler compiler(&code); this->c = &compiler; if (g_cfg.core.spu_debug) { // Set logger - codeHolder->setLogger(&logger); + code.setLogger(&logger); } - compiler.addFunc(FuncSignature2(asmjit::CallConv::kIdHost)); - // Initialize variables - X86Gp cpu_var = compiler.newIntPtr("cpu"); - compiler.setArg(0, cpu_var); - compiler.alloc(cpu_var, asmjit::x86::rbp); // ASMJIT bug workaround - this->cpu = &cpu_var; +#ifdef _WIN32 + this->cpu = &x86::rcx; + this->ls = &x86::rdx; +#else + this->cpu = &x86::rdi; + this->ls = &x86::rsi; +#endif - X86Gp ls_var = compiler.newIntPtr("ls"); - compiler.setArg(1, ls_var); - compiler.alloc(ls_var, asmjit::x86::rbx); // ASMJIT bug workaround - this->ls = &ls_var; + this->addr = &x86::eax; +#ifdef _WIN32 + this->qw0 = &x86::r8; + this->qw1 = &x86::r9; +#else + this->qw0 = &x86::rdx; + this->qw1 = &x86::rcx; +#endif - X86Gp addr_var = compiler.newUInt32("addr"); - this->addr = &addr_var; - X86Gp qw0_var = compiler.newUInt64("qw0"); - this->qw0 = &qw0_var; - X86Gp qw1_var = compiler.newUInt64("qw1"); - this->qw1 = &qw1_var; - X86Gp qw2_var = compiler.newUInt64("qw2"); - this->qw2 = &qw2_var; - X86Gp qw3_var = compiler.newUInt64("qw3"); - this->qw3 = &qw3_var; - - std::array vec_vars; + const std::array vec_vars + { + &x86::xmm0, + &x86::xmm1, + &x86::xmm2, + &x86::xmm3, + &x86::xmm4, + &x86::xmm5, + }; for (u32 i = 0; i < vec_vars.size(); i++) { - vec_vars[i] = compiler.newXmm(fmt::format("vec%d", i).c_str()); - vec.at(i) = vec_vars.data() + i; + vec[i] = vec_vars[i]; } - compiler.alloc(vec_vars[0], asmjit::x86::xmm0); - compiler.alloc(vec_vars[1], asmjit::x86::xmm1); - compiler.alloc(vec_vars[2], asmjit::x86::xmm2); - compiler.alloc(vec_vars[3], asmjit::x86::xmm3); - compiler.alloc(vec_vars[4], asmjit::x86::xmm4); - compiler.alloc(vec_vars[5], asmjit::x86::xmm5); - - // Initialize labels - std::vector