Print disassembly to log

This commit is contained in:
S Gopal Rajagopal 2014-09-17 15:27:45 +05:30
parent a029e70863
commit ccc37b5dc5
2 changed files with 102 additions and 68 deletions

View file

@ -6,6 +6,7 @@
#include "llvm/Support/Host.h" #include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
#include "llvm/CodeGen/MachineCodeInfo.h"
#include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Filesystem.h" #include "llvm/Support/Filesystem.h"
@ -83,8 +84,27 @@ PPULLVMRecompiler::~PPULLVMRecompiler() {
log_file << i->first << " = " << i->second << "\n"; log_file << i->first << " = " << i->second << "\n";
} }
log_file << "\nLLVM IR:\n"; std::set<std::pair<u64, u32>> sorted_block_info;
log_file << *m_module; 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); LLVMDisasmDispose(m_disassembler);
delete m_execution_engine; delete m_execution_engine;
@ -93,18 +113,20 @@ PPULLVMRecompiler::~PPULLVMRecompiler() {
delete m_llvm_context; delete m_llvm_context;
} }
PPULLVMRecompiler::CompiledBlock PPULLVMRecompiler::GetCompiledBlock(u64 address) { PPULLVMRecompiler::CompiledBlock PPULLVMRecompiler::GetCompiledBlock(u32 address) {
m_address_to_compiled_block_map_mutex.lock(); {
auto i = m_address_to_compiled_block_map.find(address); std::lock_guard<std::mutex> lock(m_address_to_compiled_block_map_mutex);
m_address_to_compiled_block_map_mutex.unlock(); auto i = m_address_to_compiled_block_map.find(address);
if (i != m_address_to_compiled_block_map.end()) {
if (i != m_address_to_compiled_block_map.end()) { i->second.request_count++;
return i->second; return i->second.block;
}
} }
m_pending_blocks_set_mutex.lock(); {
m_pending_blocks_set.insert(address); std::lock_guard<std::mutex> lock(m_pending_blocks_set_mutex);
m_pending_blocks_set_mutex.unlock(); m_pending_blocks_set.insert(address);
}
if (!IsAlive()) { if (!IsAlive()) {
Start(); Start();
@ -121,17 +143,18 @@ void PPULLVMRecompiler::Task() {
WaitForAnySignal(); WaitForAnySignal();
while (!TestDestroy() && !Emu.IsStopped()) { while (!TestDestroy() && !Emu.IsStopped()) {
u64 address; u32 address;
m_pending_blocks_set_mutex.lock(); {
auto i = m_pending_blocks_set.begin(); std::lock_guard<std::mutex> lock(m_pending_blocks_set_mutex);
m_pending_blocks_set_mutex.unlock();
if (i != m_pending_blocks_set.end()) { auto i = m_pending_blocks_set.begin();
address = *i; if (i != m_pending_blocks_set.end()) {
m_pending_blocks_set.erase(i); address = *i;
} else { m_pending_blocks_set.erase(i);
break; } else {
break;
}
} }
Compile(address); Compile(address);
@ -140,6 +163,8 @@ void PPULLVMRecompiler::Task() {
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now(); std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
m_idling_time = std::chrono::duration_cast<std::chrono::duration<double>>(end - start - m_compilation_time); m_idling_time = std::chrono::duration_cast<std::chrono::duration<double>>(end - start - m_compilation_time);
LOG_NOTICE(PPU, "Compilation thread exiting.");
} }
void PPULLVMRecompiler::Decode(const u32 code) { 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); //InterpreterCall("UNK", &PPUInterpreter::UNK, code, opcode, gcode);
} }
void PPULLVMRecompiler::Compile(const u64 address) { void PPULLVMRecompiler::Compile(u32 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;
}
std::chrono::high_resolution_clock::time_point compilation_start = std::chrono::high_resolution_clock::now(); 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); m_function = m_module->getFunction(function_name);
if (!m_function) { if (!m_function) {
@ -2994,24 +3011,32 @@ void PPULLVMRecompiler::Compile(const u64 address) {
auto block = BasicBlock::Create(*m_llvm_context, "start", m_function); auto block = BasicBlock::Create(*m_llvm_context, "start", m_function);
m_ir_builder->SetInsertPoint(block); m_ir_builder->SetInsertPoint(block);
u64 offset = 0; u32 offset = 0;
m_hit_branch_instruction = false; m_hit_branch_instruction = false;
while (!m_hit_branch_instruction) { while (!m_hit_branch_instruction) {
u32 instr = Memory.Read32(address + offset); u32 instr = vm::read32(address + offset);
Decode(instr); Decode(instr);
offset += 4; offset += 4;
SetPc(m_ir_builder->getInt64(address + offset)); SetPc(m_ir_builder->getInt32(address + offset));
} }
m_ir_builder->CreateRetVoid(); m_ir_builder->CreateRetVoid();
m_fpm->run(*m_function); m_fpm->run(*m_function);
}
CompiledBlock block = (CompiledBlock)m_execution_engine->getPointerToFunction(m_function); MachineCodeInfo mci;
m_address_to_compiled_block_map_mutex.lock(); m_execution_engine->runJITOnFunction(m_function, &mci);
m_address_to_compiled_block_map[address] = block;
m_address_to_compiled_block_map_mutex.unlock(); 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<std::mutex> 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(); std::chrono::high_resolution_clock::time_point compilation_end = std::chrono::high_resolution_clock::now();
m_compilation_time += std::chrono::duration_cast<std::chrono::duration<double>>(compilation_end - compilation_start); m_compilation_time += std::chrono::duration_cast<std::chrono::duration<double>>(compilation_end - compilation_start);
@ -3140,14 +3165,14 @@ Value * PPULLVMRecompiler::SetNibble(Value * val, u32 n, Value * b0, Value * b1,
Value * PPULLVMRecompiler::GetPc() { Value * PPULLVMRecompiler::GetPc() {
auto pc_i8_ptr = m_ir_builder->CreateConstGEP1_32(GetPPUState(), (unsigned int)offsetof(PPUThread, PC)); 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()); auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
return m_ir_builder->CreateLoad(pc_i64_ptr); 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_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()); auto pc_i32_ptr = m_ir_builder->CreateBitCast(pc_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo());
m_ir_builder->CreateStore(val_i64, pc_i64_ptr); m_ir_builder->CreateStore(val_i32, pc_i32_ptr);
} }
Value * PPULLVMRecompiler::GetGpr(u32 r, u32 num_bits) { 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->GetInsertBlock()->getParent()->getBasicBlockList().push_back(else_bb);
m_ir_builder->SetInsertPoint(else_bb); m_ir_builder->SetInsertPoint(else_bb);
auto this_ptr = (Value *)m_ir_builder->getInt64((u64)&Memory); auto val_else_i32 = Call<u32>("vm_read32", (u32(*)(u64))vm::read32, addr_i64);
this_ptr = m_ir_builder->CreateIntToPtr(this_ptr, this_ptr->getType()->getPointerTo());
auto val_else_i32 = Call("Read32", &MemoryBase::Read32<u64>, this_ptr, addr_i64);
if (!bswap) { if (!bswap) {
val_else_i32 = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {m_ir_builder->getInt32Ty()}), val_else_i32); 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) { 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() != 32) {
if (val_ix->getType()->getIntegerBitWidth() > 8 && bswap) { if (val_ix->getType()->getIntegerBitWidth() > 8 && bswap) {
val_ix = m_ir_builder->CreateCall(Intrinsic::getDeclaration(m_module, Intrinsic::bswap, {val_ix->getType()}), val_ix); 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->CreateCondBr(cmp_i1, then_bb, else_bb);
m_ir_builder->SetInsertPoint(then_bb); m_ir_builder->SetInsertPoint(then_bb);
Value * val_then_ix = val_ix; Value * val_then_i32 = val_ix;
if (bswap) { 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_i64 = m_ir_builder->CreateAdd(addr_i64, GetBaseAddress());
auto eaddr_i32_ptr = m_ir_builder->CreateIntToPtr(eaddr_i64, m_ir_builder->getInt32Ty()->getPointerTo()); 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->CreateBr(merge_bb);
m_ir_builder->GetInsertBlock()->getParent()->getBasicBlockList().push_back(else_bb); m_ir_builder->GetInsertBlock()->getParent()->getBasicBlockList().push_back(else_bb);
m_ir_builder->SetInsertPoint(else_bb); m_ir_builder->SetInsertPoint(else_bb);
Value * val_else_ix = val_ix; Value * val_else_i32 = val_ix;
if (!bswap) { 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); Call<void>("vm_write32", (void(*)(u64, u32))vm::write32, addr_i64, val_else_i32);
this_ptr = m_ir_builder->CreateIntToPtr(this_ptr, this_ptr->getType()->getPointerTo());
Call("Write32", &MemoryBase::Write32<u64>, this_ptr, addr_i64, val_else_ix);
m_ir_builder->CreateBr(merge_bb); m_ir_builder->CreateBr(merge_bb);
m_ir_builder->GetInsertBlock()->getParent()->getBasicBlockList().push_back(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++; i->second++;
return Call(name, function, GetInterpreter(), m_ir_builder->getInt32(args)...); return Call<void>(name, function, GetInterpreter(), m_ir_builder->getInt32(args)...);
} }
template<class T> template<class T>
@ -3484,10 +3506,8 @@ Type * PPULLVMRecompiler::CppToLlvmType() {
return nullptr; return nullptr;
} }
template<class Func, class... Args> template<class ReturnType, class Func, class... Args>
Value * PPULLVMRecompiler::Call(const char * name, Func function, Args... args) { Value * PPULLVMRecompiler::Call(const char * name, Func function, Args... args) {
typedef std::result_of<Func(Args...)>::type ReturnType;
auto fn = m_module->getFunction(name); auto fn = m_module->getFunction(name);
if (!fn) { if (!fn) {
std::vector<Type *> fn_args_type = {args->getType()...}; std::vector<Type *> fn_args_type = {args->getType()...};
@ -3537,8 +3557,8 @@ PPULLVMEmulator::~PPULLVMEmulator() {
} }
} }
u8 PPULLVMEmulator::DecodeMemory(const u64 address) { u8 PPULLVMEmulator::DecodeMemory(const u32 address) {
static u64 last_instr_address = 0; static u32 last_instr_address = 0;
PPULLVMRecompiler::CompiledBlock compiled_block = nullptr; PPULLVMRecompiler::CompiledBlock compiled_block = nullptr;
if (address != (last_instr_address + 4)) { if (address != (last_instr_address + 4)) {

View file

@ -30,7 +30,7 @@ public:
PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete; PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete;
/// Get a pointer to a compiled block /// Get a pointer to a compiled block
CompiledBlock GetCompiledBlock(u64 address); CompiledBlock GetCompiledBlock(u32 address);
/// Execute all tests /// Execute all tests
void RunAllTests(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter); 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; void UNK(const u32 code, const u32 opcode, const u32 gcode) override;
private: 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 /// Mutex for accessing m_address_to_compiled_block_map
/// TODO: Use a RW lock instead of mutex /// TODO: Use a RW lock instead of mutex
std::mutex m_address_to_compiled_block_map_mutex; std::mutex m_address_to_compiled_block_map_mutex;
/// Map from address to compiled block /// Map from address to compiled block
std::map<u64, CompiledBlock> m_address_to_compiled_block_map; std::map<u32, CompiledBlockInfo> m_address_to_compiled_block_map;
/// Mutex for accessing m_pending_blocks_set; /// Mutex for accessing m_pending_blocks_set;
std::mutex m_pending_blocks_set_mutex; std::mutex m_pending_blocks_set_mutex;
/// Set of blocks pending compilation /// Set of blocks pending compilation
std::set<u64> m_pending_blocks_set; std::set<u32> m_pending_blocks_set;
/// LLVM context /// LLVM context
llvm::LLVMContext * m_llvm_context; llvm::LLVMContext * m_llvm_context;
@ -490,7 +504,7 @@ private:
std::map<std::string, u64> m_interpreter_fallback_stats; std::map<std::string, u64> m_interpreter_fallback_stats;
/// Compile a block of code /// Compile a block of code
void Compile(u64 address); void Compile(u32 address);
/// Get PPU state pointer /// Get PPU state pointer
llvm::Value * GetPPUState(); llvm::Value * GetPPUState();
@ -526,7 +540,7 @@ private:
llvm::Value * GetPc(); llvm::Value * GetPc();
/// Set PC /// Set PC
void SetPc(llvm::Value * val_i64); void SetPc(llvm::Value * val_i32);
/// Load GPR /// Load GPR
llvm::Value * GetGpr(u32 r, u32 num_bits = 64); llvm::Value * GetGpr(u32 r, u32 num_bits = 64);
@ -633,7 +647,7 @@ private:
llvm::Type * CppToLlvmType(); llvm::Type * CppToLlvmType();
/// Call a function /// Call a function
template<class Func, class... Args> template<class ReturnType, class Func, class... Args>
llvm::Value * Call(const char * name, Func function, Args... args); llvm::Value * Call(const char * name, Func function, Args... args);
/// Test an instruction against the interpreter /// Test an instruction against the interpreter
@ -667,7 +681,7 @@ public:
PPULLVMEmulator & operator = (const PPULLVMEmulator & other) = delete; PPULLVMEmulator & operator = (const PPULLVMEmulator & other) = delete;
PPULLVMEmulator & operator = (PPULLVMEmulator && other) = delete; PPULLVMEmulator & operator = (PPULLVMEmulator && other) = delete;
u8 DecodeMemory(const u64 address); u8 DecodeMemory(const u32 address) override;
private: private:
/// PPU processor context /// PPU processor context