diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index eb7ad0fa8d..5e48bb5548 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -4991,6 +4991,17 @@ void RecompilationEngine::ProcessExecutionTrace(const ExecutionTrace & execution block_i = m_block_table.find(&key); if (block_i == m_block_table.end()) { block_i = m_block_table.insert(m_block_table.end(), new BlockEntry(key.cfg.start_address, key.cfg.function_address)); + + // Update the function to block map + auto function_to_block_i = m_function_to_blocks.find(execution_trace.function_address); + if (function_to_block_i == m_function_to_blocks.end()) { + function_to_block_i = m_function_to_blocks.insert(m_function_to_blocks.end(), std::make_pair(execution_trace.function_address, std::vector())); + } + + auto i = std::find(function_to_block_i->second.begin(), function_to_block_i->second.end(), *block_i); + if (i == function_to_block_i->second.end()) { + function_to_block_i->second.push_back(*block_i); + } } tmp_block_list.push_back(*block_i); @@ -5013,7 +5024,7 @@ void RecompilationEngine::ProcessExecutionTrace(const ExecutionTrace & execution if (!(*i)->is_compiled) { (*i)->num_hits++; if ((*i)->num_hits >= 1000) { // TODO: Make this configurable - CompileBlock(*(*i), false); + CompileBlock(*(*i)); (*i)->is_compiled = true; } } @@ -5046,16 +5057,32 @@ void RecompilationEngine::UpdateControlFlowGraph(ControlFlowGraph & cfg, const E } } -void RecompilationEngine::CompileBlock(BlockEntry & block_entry, bool inline_referenced_blocks) { +void RecompilationEngine::CompileBlock(BlockEntry & block_entry) { #ifdef _DEBUG Log() << "Compile: " << block_entry.ToString() << "\n"; #endif - auto is_function = block_entry.cfg.start_address == block_entry.cfg.function_address; - auto ordinal = AllocateOrdinal(block_entry.cfg.start_address, is_function); - auto executable = m_compiler.Compile(fmt::Format("fn_0x%08X_%u", block_entry.cfg.start_address, block_entry.revision++), block_entry.cfg, - is_function ? false : true /*inline_all*/, - is_function ? true : false /*generate_linkable_exits*/); + ControlFlowGraph * cfg; + ControlFlowGraph temp_cfg(block_entry.cfg.start_address, block_entry.cfg.function_address); + if (block_entry.IsFunction()) { + // Form a CFG by merging all the blocks in this function + auto function_to_block_i = m_function_to_blocks.find(block_entry.cfg.function_address); + for (auto block_i = function_to_block_i->second.begin(); block_i != function_to_block_i->second.end(); block_i++) { + temp_cfg += (*block_i)->cfg; + } + + cfg = &temp_cfg; + } else { + cfg = &block_entry.cfg; + } + +#ifdef _DEBUG + Log() << "CFG: " << cfg->ToString() << "\n"; +#endif + + auto ordinal = AllocateOrdinal(block_entry.cfg.start_address, block_entry.IsFunction()); + auto executable = m_compiler.Compile(fmt::Format("fn_0x%08X_%u", block_entry.cfg.start_address, block_entry.revision++), *cfg, true, + block_entry.IsFunction() ? true : false /*generate_linkable_exits*/); m_executable_lookup[ordinal] = executable; } diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index 8c3fd6c699..20523aa5a4 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -182,6 +182,34 @@ namespace ppu_recompiler_llvm { , function_address(function_address) { } + void operator += (const ControlFlowGraph & other) { + for (auto i = other.instruction_addresses.begin(); i != other.instruction_addresses.end(); i++) { + instruction_addresses.insert(*i); + } + + for (auto i = other.branches.begin(); i != other.branches.end(); i++) { + auto j = branches.find(i->first); + if (j == branches.end()) { + j = branches.insert(branches.begin(), std::make_pair(i->first, std::set())); + } + + for (auto k = i->second.begin(); k != i->second.end(); k++) { + j->second.insert(*k); + } + } + + for (auto i = other.calls.begin(); i != other.calls.end(); i++) { + auto j = calls.find(i->first); + if (j == calls.end()) { + j = calls.insert(calls.begin(), std::make_pair(i->first, std::set())); + } + + for (auto k = i->second.begin(); k != i->second.end(); k++) { + j->second.insert(*k); + } + } + } + std::string ToString() const { auto s = fmt::Format("0x%08X (0x%08X):", start_address, function_address); for (auto i = instruction_addresses.begin(); i != instruction_addresses.end(); i++) { @@ -240,13 +268,18 @@ namespace ppu_recompiler_llvm { } std::string ToString() const { - return fmt::Format("%s\nNumHits=%u, Revision=%u, IsCompiled=%c", cfg.ToString().c_str(), num_hits, revision, is_compiled ? 'Y' : 'N'); + return fmt::Format("0x%08X (0x%08X): NumHits=%u, Revision=%u, IsCompiled=%c", + cfg.start_address, cfg.function_address, num_hits, revision, is_compiled ? 'Y' : 'N'); } bool operator == (const BlockEntry & other) const { return cfg.start_address == other.cfg.start_address; } + bool IsFunction() const { + return cfg.function_address == cfg.start_address; + } + struct hash { size_t operator()(const BlockEntry * e) const { return e->cfg.start_address; @@ -984,6 +1017,9 @@ namespace ppu_recompiler_llvm { /// Block table std::unordered_set m_block_table; + /// Maps a function to the set of all blocks in the function. Key is the address of the function. + std::unordered_map> m_function_to_blocks; + /// Execution traces that have been already encountered. Data is the list of all blocks that this trace includes. std::unordered_map> m_processed_execution_traces; @@ -1021,7 +1057,7 @@ namespace ppu_recompiler_llvm { void UpdateControlFlowGraph(ControlFlowGraph & cfg, const ExecutionTraceEntry & this_entry, const ExecutionTraceEntry * next_entry); /// Compile a block - void CompileBlock(BlockEntry & block_entry, bool inline_referenced_blocks); + void CompileBlock(BlockEntry & block_entry); /// Mutex used to prevent multiple creation static std::mutex s_mutex;