#include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "SPUDisAsm.h" #include "SPUThread.h" #include "SPUInterpreter.h" #include "SPUASMJITRecompiler.h" #include #define ASMJIT_STATIC #define ASMJIT_DEBUG #include "asmjit.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__)) #define SPU_OFF_32(x, ...) asmjit::x86::dword_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__)) #define SPU_OFF_16(x, ...) asmjit::x86::word_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__)) #define SPU_OFF_8(x, ...) asmjit::x86::byte_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__)) const spu_decoder s_spu_interpreter; // TODO: remove const spu_decoder s_spu_decoder; spu_recompiler::spu_recompiler() : m_jit(std::make_shared()) { LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created..."); 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())); } } void spu_recompiler::compile(spu_function_t& f) { std::lock_guard lock(m_mutex); if (f.compiled) { // 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); } using namespace asmjit; SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode); dis_asm.offset = reinterpret_cast(f.data.data()) - f.addr; StringLogger logger; logger.addOptions(Logger::kOptionBinaryForm); std::string log; if (g_cfg.core.spu_debug) { fmt::append(log, "========== SPU FUNCTION 0x%05x - 0x%05x ==========\n\n", f.addr, f.addr + f.size); } this->m_func = &f; asmjit::CodeHolder code; code.init(m_jit->getCodeInfo()); this->codeHolder = &code; X86Compiler compiler(&code); this->c = &compiler; if (g_cfg.core.spu_debug) { // Set logger codeHolder->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; 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; 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; std::array vec_vars; 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; } // Initialize labels std::vector