Made changes so that there is a single LLVM context instead of one per PPU. If separate LLVM contexts are used per PPU and if different PPUs execute the same address then the address will have to compiled once per PPU.

This commit is contained in:
S Gopal Rajagopal 2014-09-10 03:00:53 +05:30
parent a4bb9eaa55
commit 1be5222e66
3 changed files with 442 additions and 356 deletions

File diff suppressed because it is too large Load Diff

View File

@ -437,65 +437,14 @@ private:
/// PPU instruction decoder
PPUDecoder m_decoder;
/// PPU Interpreter
PPUInterpreter m_interpreter;
/// A flag used to detect branch instructions.
/// This is set to false at the start of compilation of a block.
/// When a branch instruction is encountered, this is set to true by the decode function.
bool m_hit_branch_instruction;
/// LLVM context
llvm::LLVMContext m_llvm_context;
/// LLVM IR builder
llvm::IRBuilder<> m_ir_builder;
/// Module to which all generated code is output to
llvm::Module * m_module;
/// Function in m_module that corresponds to ExecuteThisCall
llvm::Function * m_execute_this_call_fn;
/// A comment metadata node for m_execute_this_call_fn
llvm::MDNode * m_execute_this_call_fn_comment_md_node;
/// Global variable in m_module that corresponds to m_ppu.GPR
llvm::GlobalVariable * m_pc;
/// Global variable in m_module that corresponds to m_ppu.GPR
llvm::GlobalVariable * m_gpr;
/// Global variable in m_module that corresponds to m_ppu.CR
llvm::GlobalVariable * m_cr;
/// Global variable in m_module that corresponds to m_ppu.XER
llvm::GlobalVariable * m_xer;
/// Global variable in m_module that corresponds to m_ppu.VPR
llvm::GlobalVariable * m_vpr;
/// Global variable in m_module that corresponds to m_ppu.VSCR
llvm::GlobalVariable * m_vscr;
/// JIT execution engine
llvm::ExecutionEngine * m_execution_engine;
/// Disassembler
LLVMDisasmContextRef m_disassembler;
/// PPU Interpreter
PPUInterpreter m_interpreter;
/// Time spent compiling
std::chrono::duration<double> m_compilation_time;
/// Time spent executing
std::chrono::duration<double> m_execution_time;
/// Contains the number of times the interpreter was invoked for an instruction
std::map<std::string, u64> m_interpreter_invocation_stats;
/// List of std::function pointers created by ThisCall()
std::list<std::function<void()> *> m_this_call_ptrs_list;
/// Get a bit
llvm::Value * GetBit(llvm::Value * val, u32 n);
@ -517,13 +466,19 @@ private:
/// Set a nibble
llvm::Value * SetNibble(llvm::Value * val, u32 n, llvm::Value * b0, llvm::Value * b1, llvm::Value * b2, llvm::Value * b3, bool doClear = true);
/// Load GPR and convert it to an i64
/// Load PC
llvm::Value * GetPc();
/// Set PC
void SetPc(llvm::Value * val_i64);
/// Load GPR
llvm::Value * GetGpr(u32 r);
/// Set GPR to specified value
/// Set GPR
void SetGpr(u32 r, llvm::Value * val_x64);
/// Load CR and convert it to an i32
/// Load CR
llvm::Value * GetCr();
/// Load CR and get field CRn
@ -565,6 +520,12 @@ private:
/// Set the SO bit of XER
void SetXerSo(llvm::Value * so);
/// Load VSCR
llvm::Value * GetVscr();
/// Set VSCR
void SetVscr(llvm::Value * val_x32);
/// Load VR and convert it to an integer vector
llvm::Value * GetVrAsIntVec(u32 vr, u32 vec_elt_num_bits);
@ -577,10 +538,68 @@ private:
/// Set VR to the specified value
void SetVr(u32 vr, llvm::Value * val_x128);
/// Test an instruction against the interpreter
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
void VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args);
/// Excute a test
void RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result);
/// Execute all tests
void RunAllTests();
/// Call a member function
template<class F, class C, class... Args>
void ThisCall(const char * name, F function, C * this_ptr, Args... args);
/// Number of instances
static u32 s_num_instances;
/// Map from address to compiled code
static std::map<u64, void *> s_address_to_code_map;
/// Mutex for s_address_to_code_map
static std::mutex s_address_to_code_map_mutex;
/// LLVM mutex
static std::mutex s_llvm_mutex;
/// LLVM context
static llvm::LLVMContext * s_llvm_context;
/// LLVM IR builder
static llvm::IRBuilder<> * s_ir_builder;
/// Module to which all generated code is output to
static llvm::Module * s_module;
/// Function in m_module that corresponds to ExecuteThisCall
static llvm::Function * s_execute_this_call_fn;
/// A metadata node for s_execute_this_call_fn that records the function name and args
static llvm::MDNode * s_execute_this_call_fn_name_and_args_md_node;
/// JIT execution engine
static llvm::ExecutionEngine * s_execution_engine;
/// Disassembler
static LLVMDisasmContextRef s_disassembler;
/// The pointer to the PPU state
static llvm::Value * s_state_ptr;
/// Time spent compiling
static std::chrono::duration<double> s_compilation_time;
/// Time spent executing
static std::chrono::duration<double> s_execution_time;
/// Contains the number of times the interpreter was invoked for an instruction
static std::map<std::string, u64> s_interpreter_invocation_stats;
/// List of std::function pointers created by ThisCall()
static std::list<std::function<void()> *> s_this_call_ptrs_list;
/// Execute a this call
static void ExecuteThisCall(std::function<void()> * function);
@ -590,16 +609,6 @@ private:
/// Terminator for ArgsToString(T arg1, Args... args);
static std::string ArgsToString();
/// Test an instruction against the interpreter
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
void VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args);
/// Excute a test
void RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result);
/// Execute all tests
void RunAllTests();
};
#endif // PPU_LLVM_RECOMPILER_H

View File

@ -186,11 +186,16 @@ void PPULLVMRecompiler::VerifyInstructionAgainstInterpreter(const char * name, P
void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result) {
// Create the unit test function
auto function = cast<Function>(m_module->getOrInsertFunction(name, Type::getVoidTy(m_llvm_context), (Type *)nullptr));
auto block = BasicBlock::Create(m_llvm_context, "start", function);
m_ir_builder.SetInsertPoint(block);
auto function = cast<Function>(s_module->getOrInsertFunction(name, s_ir_builder->getVoidTy(), s_ir_builder->getInt8Ty()->getPointerTo(), nullptr));
s_state_ptr = function->arg_begin();
s_state_ptr->setName("state");
auto block = BasicBlock::Create(*s_llvm_context, "start", function);
s_ir_builder->SetInsertPoint(block);
test_case();
m_ir_builder.CreateRetVoid();
s_ir_builder->CreateRetVoid();
verifyFunction(*function);
// Print the IR
@ -201,14 +206,14 @@ void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_ca
// Generate the function
MachineCodeInfo mci;
m_execution_engine->runJITOnFunction(function, &mci);
s_execution_engine->runJITOnFunction(function, &mci);
// Disassember the generated function
LOG_NOTICE(PPU, "[UT %s] Disassembly:", name);
for (uint64_t pc = 0; pc < mci.size();) {
char str[1024];
auto size = LLVMDisasmInstruction(m_disassembler, (uint8_t *)mci.address() + pc, mci.size() - pc, (uint64_t)((uint8_t *)mci.address() + pc), str, sizeof(str));
auto size = LLVMDisasmInstruction(s_disassembler, (uint8_t *)mci.address() + pc, mci.size() - pc, (uint64_t)((uint8_t *)mci.address() + pc), str, sizeof(str));
LOG_NOTICE(PPU, "[UT %s] %p: %s.", name, (uint8_t *)mci.address() + pc, str);
pc += size;
}
@ -216,7 +221,8 @@ void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_ca
// Run the test
input();
std::vector<GenericValue> args;
m_execution_engine->runFunction(function, args);
args.push_back(GenericValue(&m_ppu));
s_execution_engine->runFunction(function, args);
// Verify results
std::string msg;
@ -227,7 +233,7 @@ void PPULLVMRecompiler::RunTest(const char * name, std::function<void()> test_ca
LOG_ERROR(PPU, "[UT %s] Test failed. %s", name, msg.c_str());
}
m_execution_engine->freeMachineCodeForFunction(function);
s_execution_engine->freeMachineCodeForFunction(function);
}
void PPULLVMRecompiler::RunAllTests() {