mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-16 16:21:02 +00:00
PPUJIT: Support stopping/pausing threads (does not always work)
This commit is contained in:
parent
1365c830b2
commit
681fb1eeaa
@ -26,8 +26,10 @@ using namespace ppu_recompiler_llvm;
|
|||||||
u64 Compiler::s_rotate_mask[64][64];
|
u64 Compiler::s_rotate_mask[64][64];
|
||||||
bool Compiler::s_rotate_mask_inited = false;
|
bool Compiler::s_rotate_mask_inited = false;
|
||||||
|
|
||||||
Compiler::Compiler(RecompilationEngine & recompilation_engine, const Executable execute_unknown_function, const Executable execute_unknown_block)
|
Compiler::Compiler(RecompilationEngine & recompilation_engine, const Executable execute_unknown_function,
|
||||||
: m_recompilation_engine(recompilation_engine) {
|
const Executable execute_unknown_block, bool (*poll_status_function)(PPUThread * ppu_state))
|
||||||
|
: m_recompilation_engine(recompilation_engine)
|
||||||
|
, m_poll_status_function(poll_status_function) {
|
||||||
InitializeNativeTarget();
|
InitializeNativeTarget();
|
||||||
InitializeNativeTargetAsmPrinter();
|
InitializeNativeTargetAsmPrinter();
|
||||||
InitializeNativeTargetDisassembler();
|
InitializeNativeTargetDisassembler();
|
||||||
@ -157,20 +159,21 @@ Executable Compiler::Compile(const std::string & name, const ControlFlowGraph &
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Found an empty block
|
// Found an empty block
|
||||||
|
m_state.current_instruction_address = GetAddressFromBasicBlockName(block_i->getName());
|
||||||
|
|
||||||
m_ir_builder->SetInsertPoint(block_i);
|
m_ir_builder->SetInsertPoint(block_i);
|
||||||
auto exit_instr_i32 = m_ir_builder->CreatePHI(m_ir_builder->getInt32Ty(), 0);
|
auto 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);
|
||||||
|
|
||||||
auto instr_address = GetAddressFromBasicBlockName(block_i->getName());
|
SetPc(m_ir_builder->getInt32(m_state.current_instruction_address));
|
||||||
SetPc(m_ir_builder->getInt32(instr_address));
|
|
||||||
|
|
||||||
if (generate_linkable_exits) {
|
if (generate_linkable_exits) {
|
||||||
auto context_i64 = m_ir_builder->CreateZExt(exit_instr_i32, m_ir_builder->getInt64Ty());
|
auto context_i64 = m_ir_builder->CreateZExt(exit_instr_i32, m_ir_builder->getInt64Ty());
|
||||||
context_i64 = m_ir_builder->CreateOr(context_i64, (u64)cfg.function_address << 32);
|
context_i64 = m_ir_builder->CreateOr(context_i64, (u64)cfg.function_address << 32);
|
||||||
auto ret_i32 = IndirectCall(instr_address, context_i64, false);
|
auto ret_i32 = IndirectCall(m_state.current_instruction_address, context_i64, false);
|
||||||
auto cmp_i1 = m_ir_builder->CreateICmpNE(ret_i32, m_ir_builder->getInt32(0));
|
auto cmp_i1 = m_ir_builder->CreateICmpNE(ret_i32, m_ir_builder->getInt32(0));
|
||||||
auto then_bb = GetBasicBlockFromAddress(instr_address, "then");
|
auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then_0");
|
||||||
auto merge_bb = GetBasicBlockFromAddress(instr_address, "merge");
|
auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge_0");
|
||||||
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
|
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
|
||||||
|
|
||||||
m_ir_builder->SetInsertPoint(then_bb);
|
m_ir_builder->SetInsertPoint(then_bb);
|
||||||
@ -195,8 +198,8 @@ Executable Compiler::Compile(const std::string & name, const ControlFlowGraph &
|
|||||||
|
|
||||||
if (generate_linkable_exits) {
|
if (generate_linkable_exits) {
|
||||||
auto cmp_i1 = m_ir_builder->CreateICmpNE(exit_instr_i32, m_ir_builder->getInt32(0));
|
auto cmp_i1 = m_ir_builder->CreateICmpNE(exit_instr_i32, m_ir_builder->getInt32(0));
|
||||||
auto then_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "then");
|
auto then_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "then_0");
|
||||||
auto merge_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "merge");
|
auto merge_bb = GetBasicBlockFromAddress(0xFFFFFFFF, "merge_0");
|
||||||
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
|
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
|
||||||
|
|
||||||
m_ir_builder->SetInsertPoint(then_bb);
|
m_ir_builder->SetInsertPoint(then_bb);
|
||||||
@ -2011,6 +2014,15 @@ void Compiler::SC(u32 lev) {
|
|||||||
CompilationError(fmt::Format("SC %u", lev));
|
CompilationError(fmt::Format("SC %u", lev));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ret_i1 = Call<bool>("PollStatus", m_poll_status_function, m_state.args[CompileTaskState::Args::State]);
|
||||||
|
auto cmp_i1 = m_ir_builder->CreateICmpEQ(ret_i1, m_ir_builder->getInt1(true));
|
||||||
|
auto then_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "then_true");
|
||||||
|
auto merge_bb = GetBasicBlockFromAddress(m_state.current_instruction_address, "merge_true");
|
||||||
|
m_ir_builder->CreateCondBr(cmp_i1, then_bb, merge_bb);
|
||||||
|
m_ir_builder->SetInsertPoint(then_bb);
|
||||||
|
m_ir_builder->CreateRet(m_ir_builder->getInt32(0xFFFFFFFF));
|
||||||
|
m_ir_builder->SetInsertPoint(merge_bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::B(s32 ll, u32 aa, u32 lk) {
|
void Compiler::B(s32 ll, u32 aa, u32 lk) {
|
||||||
@ -5535,7 +5547,17 @@ llvm::Value * Compiler::IndirectCall(u32 address, Value * context_i64, bool is_f
|
|||||||
auto location_i64_ptr = m_ir_builder->CreateIntToPtr(location_i64, m_ir_builder->getInt64Ty()->getPointerTo());
|
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_i64 = m_ir_builder->CreateLoad(location_i64_ptr);
|
||||||
auto executable_ptr = m_ir_builder->CreateIntToPtr(executable_i64, m_compiled_function_type->getPointerTo());
|
auto executable_ptr = m_ir_builder->CreateIntToPtr(executable_i64, m_compiled_function_type->getPointerTo());
|
||||||
return m_ir_builder->CreateCall2(executable_ptr, m_state.args[CompileTaskState::Args::State], context_i64);
|
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) {
|
||||||
@ -5559,7 +5581,7 @@ RecompilationEngine::RecompilationEngine()
|
|||||||
: ThreadBase("PPU Recompilation Engine")
|
: ThreadBase("PPU Recompilation Engine")
|
||||||
, m_log(nullptr)
|
, m_log(nullptr)
|
||||||
, m_next_ordinal(0)
|
, m_next_ordinal(0)
|
||||||
, m_compiler(*this, ExecutionEngine::ExecuteFunction, ExecutionEngine::ExecuteTillReturn) {
|
, m_compiler(*this, ExecutionEngine::ExecuteFunction, ExecutionEngine::ExecuteTillReturn, ExecutionEngine::PollStatus) {
|
||||||
m_compiler.RunAllTests();
|
m_compiler.RunAllTests();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5972,12 +5994,7 @@ u32 ppu_recompiler_llvm::ExecutionEngine::ExecuteTillReturn(PPUThread * ppu_stat
|
|||||||
execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledFunction, context >> 32, context & 0xFFFFFFFF);
|
execution_engine->m_tracer.Trace(Tracer::TraceType::ExitFromCompiledFunction, context >> 32, context & 0xFFFFFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!terminate && !Emu.IsStopped()) {
|
while (terminate == false && PollStatus(ppu_state) == false) {
|
||||||
if (Emu.IsPaused()) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto executable = execution_engine->GetExecutable(ppu_state->PC, ExecuteTillReturn);
|
auto executable = execution_engine->GetExecutable(ppu_state->PC, ExecuteTillReturn);
|
||||||
if (executable != ExecuteTillReturn && executable != ExecuteFunction) {
|
if (executable != ExecuteTillReturn && executable != ExecuteFunction) {
|
||||||
auto entry = ppu_state->PC;
|
auto entry = ppu_state->PC;
|
||||||
@ -6017,6 +6034,18 @@ u32 ppu_recompiler_llvm::ExecutionEngine::ExecuteTillReturn(PPUThread * ppu_stat
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ppu_recompiler_llvm::ExecutionEngine::PollStatus(PPUThread * ppu_state) {
|
||||||
|
while (Emu.IsPaused() || ppu_state->IsPaused()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Emu.IsStopped() || ppu_state->IsStopped()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BranchType ppu_recompiler_llvm::GetBranchTypeFromInstruction(u32 instruction) {
|
BranchType ppu_recompiler_llvm::GetBranchTypeFromInstruction(u32 instruction) {
|
||||||
auto type = BranchType::NonBranch;
|
auto type = BranchType::NonBranch;
|
||||||
auto field1 = instruction >> 26;
|
auto field1 = instruction >> 26;
|
||||||
|
@ -272,7 +272,8 @@ namespace ppu_recompiler_llvm {
|
|||||||
std::chrono::nanoseconds total_time;
|
std::chrono::nanoseconds total_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
Compiler(RecompilationEngine & recompilation_engine, const Executable execute_unknown_function, const Executable execute_unknown_block);
|
Compiler(RecompilationEngine & recompilation_engine, const Executable execute_unknown_function,
|
||||||
|
const Executable execute_unknown_block, bool (*poll_status_function)(PPUThread * ppu_state));
|
||||||
|
|
||||||
Compiler(const Compiler & other) = delete;
|
Compiler(const Compiler & other) = delete;
|
||||||
Compiler(Compiler && other) = delete;
|
Compiler(Compiler && other) = delete;
|
||||||
@ -734,6 +735,9 @@ namespace ppu_recompiler_llvm {
|
|||||||
/// Recompilation engine
|
/// Recompilation engine
|
||||||
RecompilationEngine & m_recompilation_engine;
|
RecompilationEngine & m_recompilation_engine;
|
||||||
|
|
||||||
|
/// The function that should be called to check the status of the thread
|
||||||
|
bool (*m_poll_status_function)(PPUThread * ppu_state);
|
||||||
|
|
||||||
/// The function that will be called to execute unknown functions
|
/// The function that will be called to execute unknown functions
|
||||||
llvm::Function * m_execute_unknown_function;
|
llvm::Function * m_execute_unknown_function;
|
||||||
|
|
||||||
@ -1163,6 +1167,9 @@ namespace ppu_recompiler_llvm {
|
|||||||
|
|
||||||
/// Execute till the current function returns
|
/// Execute till the current function returns
|
||||||
static u32 ExecuteTillReturn(PPUThread * ppu_state, u64 context);
|
static u32 ExecuteTillReturn(PPUThread * ppu_state, u64 context);
|
||||||
|
|
||||||
|
/// Check thread status. Returns true if the thread must exit.
|
||||||
|
static bool PollStatus(PPUThread * ppu_state);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Get the branch type from a branch instruction
|
/// Get the branch type from a branch instruction
|
||||||
|
Loading…
x
Reference in New Issue
Block a user