diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index b45f6ef737..4c2a142478 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -282,7 +282,15 @@ const Executable *RecompilationEngine::GetExecutable(u32 address, bool isFunctio return isFunction ? &executeFunc : &executeUntilReturn; } -const Executable *RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address, std::mutex *mut) +std::mutex* RecompilationEngine::GetMutexForAddress(u32 address) { + std::lock_guard lock(m_address_locks_lock); + std::unordered_map::iterator It = m_address_locks.find(address); + if (It == m_address_locks.end()) + return nullptr; + return &(It->second); +} + +const Executable *RecompilationEngine::GetCompiledExecutableIfAvailable(u32 address) { std::lock_guard lock(m_address_to_function_lock); std::unordered_map::iterator It = m_address_to_function.find(address); @@ -290,7 +298,6 @@ const Executable *RecompilationEngine::GetCompiledExecutableIfAvailable(u32 addr return nullptr; if (std::get<1>(It->second) == nullptr) return nullptr; - mut = &(std::get<3>(It->second)); return &(std::get<0>(It->second)); } @@ -528,8 +535,14 @@ void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { std::get<1>(m_address_to_function[block_entry.cfg.start_address]) = nullptr; } - // Prevent access on this block - std::lock_guard lock(std::get<3>(m_address_to_function[block_entry.cfg.start_address])); + std::unordered_map::iterator It2 = m_address_locks.find(block_entry.cfg.start_address); + if (It2 == m_address_locks.end()) + { + std::lock_guard lock(m_address_locks_lock); + (void)m_address_locks[block_entry.cfg.start_address]; + } + + std::lock_guard lock(m_address_locks[block_entry.cfg.start_address]); std::get<1>(m_address_to_function[block_entry.cfg.start_address]) = std::unique_ptr(compileResult.second); std::get<0>(m_address_to_function[block_entry.cfg.start_address]) = compileResult.first; @@ -679,17 +692,16 @@ u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteTillReturn(PPUThread execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledFunction, context >> 32, context & 0xFFFFFFFF); while (PollStatus(ppu_state) == false) { - std::mutex mut; - const Executable *executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC, &mut); - if (executable) { - std::lock_guard lock(mut); + std::mutex *mut = execution_engine->m_recompilation_engine->GetMutexForAddress(ppu_state->PC); + if (mut) { + std::lock_guard lock(*mut); + const Executable *executable = execution_engine->m_recompilation_engine->GetCompiledExecutableIfAvailable(ppu_state->PC); auto entry = ppu_state->PC; u32 exit = (u32)(*executable)(ppu_state, 0); execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledBlock, entry, exit); if (exit == 0) return 0; - } - else { + } else { execution_engine->m_tracer.Trace(Tracer::TraceType::Instruction, ppu_state->PC, 0); u32 instruction = vm::ps3::read32(ppu_state->PC); u32 oldPC = ppu_state->PC; @@ -702,11 +714,12 @@ u32 ppu_recompiler_llvm::CPUHybridDecoderRecompiler::ExecuteTillReturn(PPUThread execution_engine->m_tracer.Trace(Tracer::TraceType::Return, 0, 0); if (Emu.GetCPUThreadStop() == ppu_state->PC) ppu_state->fast_stop(); return 0; - case BranchType::FunctionCall: + case BranchType::FunctionCall: { execution_engine->m_tracer.Trace(Tracer::TraceType::CallFunction, ppu_state->PC, 0); - executable = execution_engine->m_recompilation_engine->GetExecutable(ppu_state->PC, true); + const Executable *executable = execution_engine->m_recompilation_engine->GetExecutable(ppu_state->PC, true); (*executable)(ppu_state, 0); break; + } case BranchType::LocalBranch: break; case BranchType::NonBranch: diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index ccc05bcc92..36495acc21 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -998,6 +998,7 @@ namespace ppu_recompiler_llvm { * using atomic based locks to avoid undefined behavior. **/ class RecompilationEngine final : protected thread_t { + friend class CPUHybridDecoderRecompiler; public: virtual ~RecompilationEngine() override; @@ -1008,11 +1009,16 @@ namespace ppu_recompiler_llvm { **/ const Executable *GetExecutable(u32 address, bool isFunction); + /** + * Get a mutex for an address. Used to avoid modifying a block currently in execution. + **/ + std::mutex* GetMutexForAddress(u32 address); + /** * Get the executable for the specified address if a compiled version is * available, otherwise returns nullptr. **/ - const Executable *GetCompiledExecutableIfAvailable(u32 address, std::mutex*); + const Executable *GetCompiledExecutableIfAvailable(u32 address); /// Notify the recompilation engine about a newly detected trace. It takes ownership of the trace. void NotifyTrace(ExecutionTrace * execution_trace); @@ -1094,11 +1100,14 @@ namespace ppu_recompiler_llvm { /// Lock for accessing m_address_to_function. std::mutex m_address_to_function_lock; + /// Lock for modifying address mutex table + std::mutex m_address_locks_lock; /// (function, module containing function, times hit, mutex for access). - typedef std::tuple, u32, std::mutex> ExecutableStorage; + typedef std::tuple, u32> ExecutableStorage; /// Address to ordinal cahce. Key is address. std::unordered_map m_address_to_function; + std::unordered_map m_address_locks; /// The time at which the m_address_to_ordinal cache was last cleared std::chrono::high_resolution_clock::time_point m_last_cache_clear_time; @@ -1233,7 +1242,7 @@ namespace ppu_recompiler_llvm { std::unordered_map::const_iterator It = executableMap.find(Name); if (It != executableMap.end()) return (uint64_t)It->second; - return 0; + return getSymbolAddressInProcess(Name); } }; } diff --git a/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp b/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp index f4cbe17ef0..234266ee0e 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompilerTests.cpp @@ -496,8 +496,8 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCTSXS, 5, 5, 0u, 3u, 1u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCTUXS, 0, 5, 0u, 0u, 1u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VCTUXS, 5, 5, 0u, 3u, 1u); - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VEXPTEFP, 0, 5, 0u, 1u); CRASH! - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VLOGEFP, 0, 5, 0u, 1u); CRASH! + VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VEXPTEFP, 0, 5, 0u, 1u); + VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VLOGEFP, 0, 5, 0u, 1u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VMADDFP, 0, 5, 0u, 1u, 2u, 3u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VMAXFP, 0, 5, 0u, 1u, 2u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(VMAXSB, 0, 5, 0u, 1u, 2u); @@ -931,9 +931,9 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWX, 0, input, 3u, 0u, 23u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWX, 1, input, 3u, 14u, 23u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWUX, 0, input, 3u, 14u, 23u); - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 0, input, 0u, 0u, 23u); CRASH - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 1, input, 0u, 14u, 23u); CRASH - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 2, input, 0u, 21u, 23u); CRASH + VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 0, input, 0u, 0u, 23u); + VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 1, input, 0u, 14u, 23u); + VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVLX, 2, input, 0u, 21u, 23u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STWBRX, 0, input, 3u, 14u, 23u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STD, 0, input, 3u, 0u, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STD, 1, input, 3u, 14u, 0x10000); @@ -948,9 +948,9 @@ void Compiler::RunAllTests() { VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSU, 0, input, 3u, 14u, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSX, 0, input, 3u, 0u, 23u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSX, 1, input, 3u, 14u, 23u); - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 0, input, 0u, 0u, 23u); CRASH - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 1, input, 0u, 14u, 23u); CRASH - //VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 2, input, 0u, 21u, 23u); CRASH + VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 0, input, 0u, 0u, 23u); + VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 1, input, 0u, 14u, 23u); + VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STVRX, 2, input, 0u, 21u, 23u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFSUX, 0, input, 3u, 14u, 23u); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFD, 0, input, 3u, 0u, 0x10000); VERIFY_INSTRUCTION_AGAINST_INTERPRETER(STFD, 1, input, 3u, 14u, 0x10000);