mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-06 06:51:26 +12:00
Run recompilation in the background
This commit is contained in:
parent
1f3a117744
commit
840ae2f86b
5 changed files with 594 additions and 500 deletions
|
@ -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
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue