From ccc37b5dc52a34fa7293396f8c008aba72bc5ba7 Mon Sep 17 00:00:00 2001 From: S Gopal Rajagopal Date: Wed, 17 Sep 2014 15:27:45 +0530 Subject: [PATCH] Print disassembly to log --- rpcs3/Emu/Cell/PPULLVMRecompiler.cpp | 142 +++++++++++++++------------ rpcs3/Emu/Cell/PPULLVMRecompiler.h | 28 ++++-- 2 files changed, 102 insertions(+), 68 deletions(-) diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 3f0d94df6a..dd71d63677 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -6,6 +6,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/CodeGen/MachineCodeInfo.h" #include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Support/Filesystem.h" @@ -83,8 +84,27 @@ PPULLVMRecompiler::~PPULLVMRecompiler() { log_file << i->first << " = " << i->second << "\n"; } - log_file << "\nLLVM IR:\n"; - log_file << *m_module; + std::set> sorted_block_info; + for (auto i = m_address_to_compiled_block_map.begin(); i != m_address_to_compiled_block_map.end(); i++) { + sorted_block_info.insert(std::make_pair(~i->second.request_count, i->first)); + } + + log_file << "\nBlock Information:\n"; + for (auto i = sorted_block_info.begin(); i != sorted_block_info.end(); i++) { + auto j = m_address_to_compiled_block_map.find(i->second); + log_file << fmt::Format("%s: Size = %u bytes, Times requested = %llu\n", j->second.llvm_function->getName().str().c_str(), j->second.size, j->second.request_count); + + log_file << "\nDisassembly:\n"; + for (size_t pc = 0; pc < j->second.size;) { + char str[1024]; + + auto size = LLVMDisasmInstruction(m_disassembler, (uint8_t *)j->second.block + pc, j->second.size - pc, (uint64_t)((uint8_t *)j->second.block + pc), str, sizeof(str)); + log_file << str << '\n'; + pc += size; + } + } + + log_file << "\nLLVM IR:\n" << *m_module; LLVMDisasmDispose(m_disassembler); delete m_execution_engine; @@ -93,18 +113,20 @@ PPULLVMRecompiler::~PPULLVMRecompiler() { delete m_llvm_context; } -PPULLVMRecompiler::CompiledBlock PPULLVMRecompiler::GetCompiledBlock(u64 address) { - m_address_to_compiled_block_map_mutex.lock(); - auto i = m_address_to_compiled_block_map.find(address); - m_address_to_compiled_block_map_mutex.unlock(); - - if (i != m_address_to_compiled_block_map.end()) { - return i->second; +PPULLVMRecompiler::CompiledBlock PPULLVMRecompiler::GetCompiledBlock(u32 address) { + { + std::lock_guard lock(m_address_to_compiled_block_map_mutex); + auto i = m_address_to_compiled_block_map.find(address); + if (i != m_address_to_compiled_block_map.end()) { + i->second.request_count++; + return i->second.block; + } } - m_pending_blocks_set_mutex.lock(); - m_pending_blocks_set.insert(address); - m_pending_blocks_set_mutex.unlock(); + { + std::lock_guard lock(m_pending_blocks_set_mutex); + m_pending_blocks_set.insert(address); + } if (!IsAlive()) { Start(); @@ -121,17 +143,18 @@ void PPULLVMRecompiler::Task() { WaitForAnySignal(); while (!TestDestroy() && !Emu.IsStopped()) { - u64 address; + u32 address; - m_pending_blocks_set_mutex.lock(); - auto i = m_pending_blocks_set.begin(); - m_pending_blocks_set_mutex.unlock(); + { + std::lock_guard lock(m_pending_blocks_set_mutex); - if (i != m_pending_blocks_set.end()) { - address = *i; - m_pending_blocks_set.erase(i); - } else { - break; + auto i = m_pending_blocks_set.begin(); + if (i != m_pending_blocks_set.end()) { + address = *i; + m_pending_blocks_set.erase(i); + } else { + break; + } } Compile(address); @@ -140,6 +163,8 @@ void PPULLVMRecompiler::Task() { std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); m_idling_time = std::chrono::duration_cast>(end - start - m_compilation_time); + + LOG_NOTICE(PPU, "Compilation thread exiting."); } void PPULLVMRecompiler::Decode(const u32 code) { @@ -2966,18 +2991,10 @@ void PPULLVMRecompiler::UNK(const u32 code, const u32 opcode, const u32 gcode) { //InterpreterCall("UNK", &PPUInterpreter::UNK, code, opcode, gcode); } -void PPULLVMRecompiler::Compile(const u64 address) { - m_address_to_compiled_block_map_mutex.lock(); - auto i = m_address_to_compiled_block_map.find(address); - m_address_to_compiled_block_map_mutex.unlock(); - - if (i != m_address_to_compiled_block_map.end()) { - return; - } - +void PPULLVMRecompiler::Compile(u32 address) { std::chrono::high_resolution_clock::time_point compilation_start = std::chrono::high_resolution_clock::now(); - auto function_name = fmt::Format("fn_0x%llX", address); + auto function_name = fmt::Format("fn_0x%X", address); m_function = m_module->getFunction(function_name); if (!m_function) { @@ -2994,24 +3011,32 @@ void PPULLVMRecompiler::Compile(const u64 address) { auto block = BasicBlock::Create(*m_llvm_context, "start", m_function); m_ir_builder->SetInsertPoint(block); - u64 offset = 0; + u32 offset = 0; m_hit_branch_instruction = false; while (!m_hit_branch_instruction) { - u32 instr = Memory.Read32(address + offset); + u32 instr = vm::read32(address + offset); Decode(instr); offset += 4; - SetPc(m_ir_builder->getInt64(address + offset)); + SetPc(m_ir_builder->getInt32(address + offset)); } m_ir_builder->CreateRetVoid(); m_fpm->run(*m_function); - } - CompiledBlock block = (CompiledBlock)m_execution_engine->getPointerToFunction(m_function); - m_address_to_compiled_block_map_mutex.lock(); - m_address_to_compiled_block_map[address] = block; - m_address_to_compiled_block_map_mutex.unlock(); + MachineCodeInfo mci; + m_execution_engine->runJITOnFunction(m_function, &mci); + + CompiledBlockInfo block_info; + block_info.block = (CompiledBlock)mci.address(); + block_info.request_count = 0; + block_info.size = mci.size(); + block_info.llvm_function = m_function; + { + std::lock_guard lock(m_address_to_compiled_block_map_mutex); + m_address_to_compiled_block_map[address] = block_info; + } + } std::chrono::high_resolution_clock::time_point compilation_end = std::chrono::high_resolution_clock::now(); m_compilation_time += std::chrono::duration_cast>(compilation_end - compilation_start); @@ -3140,14 +3165,14 @@ Value * PPULLVMRecompiler::SetNibble(Value * val, u32 n, Value * b0, Value * b1, Value * PPULLVMRecompiler::GetPc() { auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(GetPPUState(), (unsigned int)offsetof(PPUThread, PC)); - auto pc_i64_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateLoad(pc_i64_ptr); + auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); + return m_ir_builder->CreateLoad(pc_i32_ptr); } -void PPULLVMRecompiler::SetPc(Value * val_i64) { +void PPULLVMRecompiler::SetPc(Value * val_i32) { auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(GetPPUState(), (unsigned int)offsetof(PPUThread, PC)); - auto pc_i64_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateStore(val_i64, pc_i64_ptr); + auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); + m_ir_builder->CreateStore(val_i32, pc_i32_ptr); } Value * PPULLVMRecompiler::GetGpr(u32 r, u32 num_bits) { @@ -3386,9 +3411,7 @@ Value * PPULLVMRecompiler::ReadMemory(Value * addr_i64, u32 bits, bool bswap) { m_ir_builder->GetInsertBlock()->getParent()->getBasicBlockList().push_back(else_bb); m_ir_builder->SetInsertPoint(else_bb); - auto this_ptr = (Value *)m_ir_builder->getInt64((u64)&Memory); - this_ptr = m_ir_builder->CreateIntToPtr(this_ptr, this_ptr->getType()->getPointerTo()); - auto val_else_i32 = Call("Read32", &MemoryBase::Read32, this_ptr, addr_i64); + auto val_else_i32 = Call("vm_read32", (u32(*)(u64))vm::read32, addr_i64); if (!bswap) { val_else_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {m_ir_builder->getInt32Ty()}), val_else_i32); } @@ -3404,6 +3427,7 @@ Value * PPULLVMRecompiler::ReadMemory(Value * addr_i64, u32 bits, bool bswap) { } void PPULLVMRecompiler::WriteMemory(Value * addr_i64, Value * val_ix, bool bswap) { + addr_i64 = m_ir_builder->CreateAnd(addr_i64, 0xFFFFFFFF); if (val_ix->getType()->getIntegerBitWidth() != 32) { if (val_ix->getType()->getIntegerBitWidth() > 8 && bswap) { val_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {val_ix->getType()}), val_ix); @@ -3420,26 +3444,24 @@ void PPULLVMRecompiler::WriteMemory(Value * addr_i64, Value * val_ix, bool bswap m_ir_builder->CreateCondBr(cmp_i1, then_bb, else_bb); m_ir_builder->SetInsertPoint(then_bb); - Value * val_then_ix = val_ix; + Value * val_then_i32 = val_ix; if (bswap) { - val_then_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {m_ir_builder->getInt32Ty()}), val_then_ix); + val_then_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {m_ir_builder->getInt32Ty()}), val_then_i32); } auto eaddr_i64 = m_ir_builder->CreateAdd(addr_i64, GetBaseAddress()); auto eaddr_i32_ptr = m_ir_builder->CreateIntToPtr(eaddr_i64, m_ir_builder->getInt32Ty()->getPointerTo()); - m_ir_builder->CreateStore(val_then_ix, eaddr_i32_ptr); + m_ir_builder->CreateStore(val_then_i32, eaddr_i32_ptr); m_ir_builder->CreateBr(merge_bb); m_ir_builder->GetInsertBlock()->getParent()->getBasicBlockList().push_back(else_bb); m_ir_builder->SetInsertPoint(else_bb); - Value * val_else_ix = val_ix; + Value * val_else_i32 = val_ix; if (!bswap) { - val_else_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {m_ir_builder->getInt32Ty()}), val_else_ix); + val_else_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {m_ir_builder->getInt32Ty()}), val_else_i32); } - auto this_ptr = (Value *)m_ir_builder->getInt64((u64)&Memory); - this_ptr = m_ir_builder->CreateIntToPtr(this_ptr, this_ptr->getType()->getPointerTo()); - Call("Write32", &MemoryBase::Write32, this_ptr, addr_i64, val_else_ix); + Call("vm_write32", (void(*)(u64, u32))vm::write32, addr_i64, val_else_i32); m_ir_builder->CreateBr(merge_bb); m_ir_builder->GetInsertBlock()->getParent()->getBasicBlockList().push_back(merge_bb); @@ -3456,7 +3478,7 @@ Value * PPULLVMRecompiler::InterpreterCall(const char * name, Func function, Arg i->second++; - return Call(name, function, GetInterpreter(), m_ir_builder->getInt32(args)...); + return Call(name, function, GetInterpreter(), m_ir_builder->getInt32(args)...); } template @@ -3484,10 +3506,8 @@ Type * PPULLVMRecompiler::CppToLlvmType() { return nullptr; } -template +template Value * PPULLVMRecompiler::Call(const char * name, Func function, Args... args) { - typedef std::result_of::type ReturnType; - auto fn = m_module->getFunction(name); if (!fn) { std::vector fn_args_type = {args->getType()...}; @@ -3537,8 +3557,8 @@ PPULLVMEmulator::~PPULLVMEmulator() { } } -u8 PPULLVMEmulator::DecodeMemory(const u64 address) { - static u64 last_instr_address = 0; +u8 PPULLVMEmulator::DecodeMemory(const u32 address) { + static u32 last_instr_address = 0; PPULLVMRecompiler::CompiledBlock compiled_block = nullptr; if (address != (last_instr_address + 4)) { diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index c8d067b3a7..eb056476cc 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -30,7 +30,7 @@ public: PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete; /// Get a pointer to a compiled block - CompiledBlock GetCompiledBlock(u64 address); + CompiledBlock GetCompiledBlock(u32 address); /// Execute all tests void RunAllTests(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter); @@ -441,18 +441,32 @@ protected: void UNK(const u32 code, const u32 opcode, const u32 gcode) override; private: + struct CompiledBlockInfo { + /// Pointer to the block + CompiledBlock block; + + /// Size of the compiled block + size_t size; + + /// Number of times this block was requested + u64 request_count; + + /// LLVM function for this block + llvm::Function * llvm_function; + }; + /// Mutex for accessing m_address_to_compiled_block_map /// TODO: Use a RW lock instead of mutex std::mutex m_address_to_compiled_block_map_mutex; /// Map from address to compiled block - std::map m_address_to_compiled_block_map; + std::map m_address_to_compiled_block_map; /// Mutex for accessing m_pending_blocks_set; std::mutex m_pending_blocks_set_mutex; /// Set of blocks pending compilation - std::set m_pending_blocks_set; + std::set m_pending_blocks_set; /// LLVM context llvm::LLVMContext * m_llvm_context; @@ -490,7 +504,7 @@ private: std::map m_interpreter_fallback_stats; /// Compile a block of code - void Compile(u64 address); + void Compile(u32 address); /// Get PPU state pointer llvm::Value * GetPPUState(); @@ -526,7 +540,7 @@ private: llvm::Value * GetPc(); /// Set PC - void SetPc(llvm::Value * val_i64); + void SetPc(llvm::Value * val_i32); /// Load GPR llvm::Value * GetGpr(u32 r, u32 num_bits = 64); @@ -633,7 +647,7 @@ private: llvm::Type * CppToLlvmType(); /// Call a function - template + template llvm::Value * Call(const char * name, Func function, Args... args); /// Test an instruction against the interpreter @@ -667,7 +681,7 @@ public: PPULLVMEmulator & operator = (const PPULLVMEmulator & other) = delete; PPULLVMEmulator & operator = (PPULLVMEmulator && other) = delete; - u8 DecodeMemory(const u64 address); + u8 DecodeMemory(const u32 address) override; private: /// PPU processor context