Run recompilation in the background

This commit is contained in:
S Gopal Rajagopal 2014-09-15 20:05:18 +05:30
parent 1f3a117744
commit 840ae2f86b
5 changed files with 594 additions and 500 deletions

View file

@ -56,7 +56,7 @@ u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); }
class PPUInterpreter : public PPUOpcodes class PPUInterpreter : public PPUOpcodes
{ {
friend class PPULLVMRecompilerWorker; friend class PPULLVMRecompiler;
private: private:
PPUThread& CPU; PPUThread& CPU;

File diff suppressed because it is too large Load diff

View file

@ -13,31 +13,33 @@
struct PPURegState; struct PPURegState;
/// PPU recompiler /// PPU to LLVM recompiler
class PPULLVMRecompilerWorker : protected PPUOpcodes { class PPULLVMRecompiler : public ThreadBase, protected PPUOpcodes {
public: public:
typedef void(*CompiledBlock)(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter); typedef void(*CompiledBlock)(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter);
PPULLVMRecompilerWorker(); PPULLVMRecompiler();
PPULLVMRecompilerWorker(const PPULLVMRecompilerWorker & other) = delete; PPULLVMRecompiler(const PPULLVMRecompiler & other) = delete;
PPULLVMRecompilerWorker(PPULLVMRecompilerWorker && other) = delete; PPULLVMRecompiler(PPULLVMRecompiler && other) = delete;
virtual ~PPULLVMRecompilerWorker(); virtual ~PPULLVMRecompiler();
PPULLVMRecompilerWorker & operator = (const PPULLVMRecompilerWorker & other) = delete; PPULLVMRecompiler & operator = (const PPULLVMRecompiler & other) = delete;
PPULLVMRecompilerWorker & operator = (PPULLVMRecompilerWorker && other) = delete; PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete;
/// Compile a block of code /// Get a pointer to a compiled block
void Compile(u64 address);
/// Get a function pointer to a compiled block
CompiledBlock GetCompiledBlock(u64 address); CompiledBlock GetCompiledBlock(u64 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);
void Task() override;
protected: protected:
/// Compile a block of code
void Compile(u64 address);
void NULL_OP() override; void NULL_OP() override;
void NOP() override; void NOP() override;
@ -442,9 +444,19 @@ private:
/// PPU instruction decoder /// PPU instruction decoder
PPUDecoder m_decoder; PPUDecoder m_decoder;
/// 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 /// Map from address to compiled block
std::map<u64, CompiledBlock> m_address_to_compiled_block_map; std::map<u64, CompiledBlock> 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<u64> m_pending_blocks_set;
/// LLVM context /// LLVM context
llvm::LLVMContext * m_llvm_context; llvm::LLVMContext * m_llvm_context;
@ -605,19 +617,19 @@ private:
void RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result); void RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result);
}; };
/// A dynarec PPU emulator that uses LLVM as the backend /// PPU emulator that uses LLVM to convert PPU instructions to host CPU instructions
class PPULLVMRecompiler : public CPUDecoder { class PPULLVMEmulator : public CPUDecoder {
public: public:
PPULLVMRecompiler(PPUThread & ppu); PPULLVMEmulator(PPUThread & ppu);
PPULLVMRecompiler() = delete; PPULLVMEmulator() = delete;
PPULLVMRecompiler(const PPULLVMRecompilerWorker & other) = delete; PPULLVMEmulator(const PPULLVMEmulator & other) = delete;
PPULLVMRecompiler(PPULLVMRecompilerWorker && other) = delete; PPULLVMEmulator(PPULLVMEmulator && other) = delete;
virtual ~PPULLVMRecompiler(); virtual ~PPULLVMEmulator();
PPULLVMRecompiler & operator = (const PPULLVMRecompiler & other) = delete; PPULLVMEmulator & operator = (const PPULLVMEmulator & other) = delete;
PPULLVMRecompiler & operator = (PPULLVMRecompiler && other) = delete; PPULLVMEmulator & operator = (PPULLVMEmulator && other) = delete;
u8 DecodeMemory(const u64 address); u8 DecodeMemory(const u64 address);
@ -626,10 +638,19 @@ private:
PPUThread & m_ppu; PPUThread & m_ppu;
/// PPU Interpreter /// PPU Interpreter
PPUInterpreter m_interpreter; PPUInterpreter * m_interpreter;
/// The actual compiler /// PPU instruction Decoder
PPULLVMRecompilerWorker m_worker; PPUDecoder m_decoder;
/// Number of instances of this class
static u32 s_num_instances;
/// Mutex used prevent multiple instances of the recompiler from being created
static std::mutex s_recompiler_mutex;
/// PPU to LLVM recompiler
static PPULLVMRecompiler * s_recompiler;
}; };
#endif // PPU_LLVM_RECOMPILER_H #endif // PPU_LLVM_RECOMPILER_H

View file

@ -9,7 +9,7 @@
using namespace llvm; using namespace llvm;
#define VERIFY_INSTRUCTION_AGAINST_INTERPRETER(fn, tc, input, ...) \ #define VERIFY_INSTRUCTION_AGAINST_INTERPRETER(fn, tc, input, ...) \
VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &PPULLVMRecompilerWorker::fn, &PPUInterpreter::fn, input, __VA_ARGS__) VerifyInstructionAgainstInterpreter(fmt::Format("%s.%d", #fn, tc).c_str(), &PPULLVMRecompiler::fn, &PPUInterpreter::fn, input, __VA_ARGS__)
#define VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(fn, s, n, ...) { \ #define VERIFY_INSTRUCTION_AGAINST_INTERPRETER_USING_RANDOM_INPUT(fn, s, n, ...) { \
PPURegState input; \ PPURegState input; \
@ -160,7 +160,7 @@ static u64 s_base_address = 0;
static PPUInterpreter * s_interpreter = nullptr; static PPUInterpreter * s_interpreter = nullptr;
template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args> template <class PPULLVMRecompilerFn, class PPUInterpreterFn, class... Args>
void PPULLVMRecompilerWorker::VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args) { void PPULLVMRecompiler::VerifyInstructionAgainstInterpreter(const char * name, PPULLVMRecompilerFn recomp_fn, PPUInterpreterFn interp_fn, PPURegState & input_reg_state, Args... args) {
auto test_case = [&]() { auto test_case = [&]() {
(this->*recomp_fn)(args...); (this->*recomp_fn)(args...);
}; };
@ -188,7 +188,7 @@ void PPULLVMRecompilerWorker::VerifyInstructionAgainstInterpreter(const char * n
RunTest(name, test_case, input, check_result); RunTest(name, test_case, input, check_result);
} }
void PPULLVMRecompilerWorker::RunTest(const char * name, std::function<void()> test_case, std::function<void()> input, std::function<bool(std::string & msg)> check_result) { 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 // Create the unit test function
m_function = (Function *)m_module->getOrInsertFunction(name, m_ir_builder->getVoidTy(), m_function = (Function *)m_module->getOrInsertFunction(name, m_ir_builder->getVoidTy(),
m_ir_builder->getInt8PtrTy() /*ppu_state*/, m_ir_builder->getInt8PtrTy() /*ppu_state*/,
@ -256,7 +256,7 @@ void PPULLVMRecompilerWorker::RunTest(const char * name, std::function<void()> t
m_execution_engine->freeMachineCodeForFunction(m_function); m_execution_engine->freeMachineCodeForFunction(m_function);
} }
void PPULLVMRecompilerWorker::RunAllTests(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter) { void PPULLVMRecompiler::RunAllTests(PPUThread * ppu_state, u64 base_address, PPUInterpreter * interpreter) {
s_ppu_state = ppu_state; s_ppu_state = ppu_state;
s_base_address = base_address; s_base_address = base_address;
s_interpreter = interpreter; s_interpreter = interpreter;

View file

@ -112,7 +112,7 @@ void PPUThread::DoRun()
break; break;
case 3: case 3:
m_dec = new PPULLVMRecompiler(*this); m_dec = new PPULLVMEmulator(*this);
break; break;
default: default: