PPU/LLVM: Remove indirect call completly

This commit is contained in:
Vincent Lejeune 2015-08-29 01:12:22 +02:00 committed by Nekotekina
parent 60d5dd40f7
commit 58181c5c17
3 changed files with 5 additions and 84 deletions

View File

@ -75,7 +75,7 @@ Compiler::~Compiler() {
delete m_llvm_context; delete m_llvm_context;
} }
std::pair<Executable, llvm::ExecutionEngine *> Compiler::Compile(const std::string & name, u32 start_address, u32 instruction_count, bool generate_linkable_exits) { std::pair<Executable, llvm::ExecutionEngine *> Compiler::Compile(const std::string & name, u32 start_address, u32 instruction_count) {
auto compilation_start = std::chrono::high_resolution_clock::now(); auto compilation_start = std::chrono::high_resolution_clock::now();
m_module = new llvm::Module("Module", *m_llvm_context); m_module = new llvm::Module("Module", *m_llvm_context);
@ -118,8 +118,6 @@ std::pair<Executable, llvm::ExecutionEngine *> Compiler::Compile(const std::stri
fpm->add(createCFGSimplificationPass()); fpm->add(createCFGSimplificationPass());
fpm->doInitialization(); fpm->doInitialization();
m_state.generate_linkable_exits = generate_linkable_exits;
// Create the function // Create the function
m_state.function = (Function *)m_module->getOrInsertFunction(name, m_compiled_function_type); m_state.function = (Function *)m_module->getOrInsertFunction(name, m_compiled_function_type);
m_state.function->setCallingConv(CallingConv::X86_64_Win64); m_state.function->setCallingConv(CallingConv::X86_64_Win64);
@ -174,27 +172,7 @@ std::pair<Executable, llvm::ExecutionEngine *> Compiler::Compile(const std::stri
SetPc(m_ir_builder->getInt32(m_state.current_instruction_address)); SetPc(m_ir_builder->getInt32(m_state.current_instruction_address));
if (generate_linkable_exits) { m_ir_builder->CreateRet(exit_instr_i32);
Value *context_i64 = m_ir_builder->CreateZExt(exit_instr_i32, m_ir_builder->getInt64Ty());
context_i64 = m_ir_builder->CreateOr(context_i64, (u64)start_address << 32);
Value *ret_i32 = IndirectCall(m_state.current_instruction_address, context_i64, false);
Value *cmp_i1 = m_ir_builder->CreateICmpNE(ret_i32, m_ir_builder->getInt32(0));
BasicBlock *then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then_0");
BasicBlock *merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge_0");
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
m_ir_builder->SetInsertPoint(then_bb);
context_i64 = m_ir_builder->CreateZExt(ret_i32, m_ir_builder->getInt64Ty());
context_i64 = m_ir_builder->CreateOr(context_i64, (u64)start_address << 32);
m_ir_builder->CreateCall2(m_execute_unknown_block, m_state.args[CompileTaskState::Args::State], context_i64);
m_ir_builder->CreateBr(merge_bb);
m_ir_builder->SetInsertPoint(merge_bb);
m_ir_builder->CreateRet(m_ir_builder->getInt32(0));
}
else {
m_ir_builder->CreateRet(exit_instr_i32);
}
} }
// If the function has a default exit block then generate code for it // If the function has a default exit block then generate code for it
@ -204,24 +182,8 @@ std::pair<Executable, llvm::ExecutionEngine *> Compiler::Compile(const std::stri
PHINode *exit_instr_i32 = m_ir_builder->CreatePHI(m_ir_builder->getInt32Ty(), 0); PHINode *exit_instr_i32 = m_ir_builder->CreatePHI(m_ir_builder->getInt32Ty(), 0);
exit_instr_list.push_back(exit_instr_i32); exit_instr_list.push_back(exit_instr_i32);
if (generate_linkable_exits) { m_ir_builder->CreateRet(exit_instr_i32);
Value *cmp_i1 = m_ir_builder->CreateICmpNE(exit_instr_i32, m_ir_builder->getInt32(0));
BasicBlock *then_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "then_0");
BasicBlock *merge_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "merge_0");
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
m_ir_builder->SetInsertPoint(then_bb);
Value *context_i64 = m_ir_builder->CreateZExt(exit_instr_i32, m_ir_builder->getInt64Ty());
context_i64 = m_ir_builder->CreateOr(context_i64, (u64)start_address << 32);
m_ir_builder->CreateCall2(m_execute_unknown_block, m_state.args[CompileTaskState::Args::State], context_i64);
m_ir_builder->CreateBr(merge_bb);
m_ir_builder->SetInsertPoint(merge_bb);
m_ir_builder->CreateRet(m_ir_builder->getInt32(0));
}
else {
m_ir_builder->CreateRet(exit_instr_i32);
}
} }
// Add incoming values for all exit instr PHI nodes // Add incoming values for all exit instr PHI nodes
@ -308,13 +270,6 @@ RecompilationEngine::~RecompilationEngine() {
free(FunctionCachePagesCommited); free(FunctionCachePagesCommited);
} }
Executable executeFunc;
Executable executeUntilReturn;
const Executable *RecompilationEngine::GetExecutable(u32 address, bool isFunction) {
return isFunction ? &executeFunc : &executeUntilReturn;
}
bool RecompilationEngine::isAddressCommited(u32 address) const bool RecompilationEngine::isAddressCommited(u32 address) const
{ {
size_t offset = address * sizeof(Executable); size_t offset = address * sizeof(Executable);
@ -511,7 +466,7 @@ void RecompilationEngine::CompileBlock(BlockEntry & block_entry) {
return; return;
Log() << "Compile: " << block_entry.ToString() << "\n"; Log() << "Compile: " << block_entry.ToString() << "\n";
const std::pair<Executable, llvm::ExecutionEngine *> &compileResult = const std::pair<Executable, llvm::ExecutionEngine *> &compileResult =
m_compiler.Compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount, false /*generate_linkable_exits*/); m_compiler.Compile(fmt::format("fn_0x%08X", block_entry.address), block_entry.address, block_entry.instructionCount);
// If entry doesn't exist, create it (using lock) // If entry doesn't exist, create it (using lock)
std::unordered_map<u32, ExecutableStorage>::iterator It = m_address_to_function.find(block_entry.address); std::unordered_map<u32, ExecutableStorage>::iterator It = m_address_to_function.find(block_entry.address);
@ -547,8 +502,6 @@ ppu_recompiler_llvm::CPUHybridDecoderRecompiler::CPUHybridDecoderRecompiler(PPUT
, m_interpreter(new PPUInterpreter(ppu)) , m_interpreter(new PPUInterpreter(ppu))
, m_decoder(m_interpreter) , m_decoder(m_interpreter)
, m_recompilation_engine(RecompilationEngine::GetInstance()) { , m_recompilation_engine(RecompilationEngine::GetInstance()) {
executeFunc = CPUHybridDecoderRecompiler::ExecuteFunction;
executeUntilReturn = CPUHybridDecoderRecompiler::ExecuteTillReturn;
} }
ppu_recompiler_llvm::CPUHybridDecoderRecompiler::~CPUHybridDecoderRecompiler() { ppu_recompiler_llvm::CPUHybridDecoderRecompiler::~CPUHybridDecoderRecompiler() {

View File

@ -71,7 +71,7 @@ namespace ppu_recompiler_llvm {
* Compile a code fragment described by a cfg and return an executable and the ExecutionEngine storing it * Compile a code fragment described by a cfg and return an executable and the ExecutionEngine storing it
* Pointer to function can be retrieved with getPointerToFunction * Pointer to function can be retrieved with getPointerToFunction
*/ */
std::pair<Executable, llvm::ExecutionEngine *> Compile(const std::string & name, u32 start_address, u32 instruction_count, bool generate_linkable_exits); std::pair<Executable, llvm::ExecutionEngine *> Compile(const std::string & name, u32 start_address, u32 instruction_count);
/// Retrieve compiler stats /// Retrieve compiler stats
Stats GetStats(); Stats GetStats();
@ -506,9 +506,6 @@ namespace ppu_recompiler_llvm {
/// This is set to false at the start of compilation of an instruction. /// This is set to false at the start of compilation of an instruction.
/// If a branch instruction is encountered, this is set to true by the decode function. /// If a branch instruction is encountered, this is set to true by the decode function.
bool hit_branch_instruction; bool hit_branch_instruction;
/// Create code such that exit points can be linked to other blocks
bool generate_linkable_exits;
}; };
/// Recompilation engine /// Recompilation engine
@ -745,9 +742,6 @@ namespace ppu_recompiler_llvm {
return m_ir_builder->CreateCall(fn, fn_args); return m_ir_builder->CreateCall(fn, fn_args);
} }
/// Indirect call
llvm::Value * IndirectCall(u32 address, llvm::Value * context_i64, bool is_function);
/// Test an instruction against the interpreter /// Test an instruction against the interpreter
template <class... Args> template <class... Args>
void VerifyInstructionAgainstInterpreter(const char * name, void (Compiler::*recomp_fn)(Args...), void (PPUInterpreter::*interp_fn)(Args...), PPUState & input_state, Args... args); void VerifyInstructionAgainstInterpreter(const char * name, void (Compiler::*recomp_fn)(Args...), void (PPUInterpreter::*interp_fn)(Args...), PPUState & input_state, Args... args);
@ -781,13 +775,6 @@ namespace ppu_recompiler_llvm {
public: public:
virtual ~RecompilationEngine() override; virtual ~RecompilationEngine() override;
/**
* Get the executable for the specified address
* The pointer is always valid during the lifetime of RecompilationEngine
* but the function pointed to can be updated.
**/
const Executable *GetExecutable(u32 address, bool isFunction);
/** /**
* Get the executable for the specified address if a compiled version is * Get the executable for the specified address if a compiled version is
* available, otherwise returns nullptr. * available, otherwise returns nullptr.

View File

@ -5273,25 +5273,6 @@ void Compiler::WriteMemory(Value * addr_i64, Value * val_ix, u32 alignment, bool
m_ir_builder->CreateAlignedStore(val_ix, eaddr_ix_ptr, alignment); m_ir_builder->CreateAlignedStore(val_ix, eaddr_ix_ptr, alignment);
} }
llvm::Value * Compiler::IndirectCall(u32 address, Value * context_i64, bool is_function) {
const Executable *functionPtr = m_recompilation_engine.GetExecutable(address, is_function);
auto location_i64 = m_ir_builder->getInt64((uint64_t)functionPtr);
auto location_i64_ptr = m_ir_builder->CreateIntToPtr(location_i64, m_ir_builder->getInt64Ty()->getPointerTo());
auto executable_i64 = m_ir_builder->CreateLoad(location_i64_ptr);
auto executable_ptr = m_ir_builder->CreateIntToPtr(executable_i64, m_compiled_function_type->getPointerTo());
auto ret_i32 = m_ir_builder->CreateCall2(executable_ptr, m_state.args[CompileTaskState::Args::State], context_i64);
auto cmp_i1 = m_ir_builder->CreateICmpEQ(ret_i32, m_ir_builder->getInt32(0xFFFFFFFF));
auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then_all_fs");
auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge_all_fs");
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
m_ir_builder->SetInsertPoint(then_bb);
m_ir_builder->CreateRet(m_ir_builder->getInt32(0));
m_ir_builder->SetInsertPoint(merge_bb);
return ret_i32;
}
void Compiler::CompilationError(const std::string & error) { void Compiler::CompilationError(const std::string & error) {
LOG_ERROR(PPU, "[0x%08X] %s", m_state.current_instruction_address, error.c_str()); LOG_ERROR(PPU, "[0x%08X] %s", m_state.current_instruction_address, error.c_str());
Emu.Pause(); Emu.Pause();