mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-21 18:39:57 +00:00
SPU LLVM: make savestates unsavable inside the code
This commit is contained in:
parent
8153e5338f
commit
39d17a94c6
@ -3982,9 +3982,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||||||
llvm::GlobalVariable* m_scale_float_to{};
|
llvm::GlobalVariable* m_scale_float_to{};
|
||||||
llvm::GlobalVariable* m_scale_to_float{};
|
llvm::GlobalVariable* m_scale_to_float{};
|
||||||
|
|
||||||
// Helper for check_state
|
|
||||||
llvm::GlobalVariable* m_fake_global1{};
|
|
||||||
|
|
||||||
// Function for check_state execution
|
// Function for check_state execution
|
||||||
llvm::Function* m_test_state{};
|
llvm::Function* m_test_state{};
|
||||||
|
|
||||||
@ -4880,7 +4877,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call cpu_thread::check_state if necessary and return or continue (full check)
|
// Call cpu_thread::check_state if necessary and return or continue (full check)
|
||||||
void check_state(u32 addr, bool may_be_unsafe_for_savestate = true)
|
void check_state(u32 addr)
|
||||||
{
|
{
|
||||||
const auto pstate = spu_ptr<u32>(&spu_thread::state);
|
const auto pstate = spu_ptr<u32>(&spu_thread::state);
|
||||||
const auto _body = llvm::BasicBlock::Create(m_context, "", m_function);
|
const auto _body = llvm::BasicBlock::Create(m_context, "", m_function);
|
||||||
@ -4888,19 +4885,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
|||||||
m_ir->CreateCondBr(m_ir->CreateICmpEQ(m_ir->CreateLoad(get_type<u32>(), pstate, true), m_ir->getInt32(0)), _body, check, m_md_likely);
|
m_ir->CreateCondBr(m_ir->CreateICmpEQ(m_ir->CreateLoad(get_type<u32>(), pstate, true), m_ir->getInt32(0)), _body, check, m_md_likely);
|
||||||
m_ir->SetInsertPoint(check);
|
m_ir->SetInsertPoint(check);
|
||||||
update_pc(addr);
|
update_pc(addr);
|
||||||
|
m_ir->CreateCall(m_test_state, {m_thread});
|
||||||
if (may_be_unsafe_for_savestate && std::none_of(std::begin(m_block->phi), std::end(m_block->phi), FN(!!x)))
|
|
||||||
{
|
|
||||||
may_be_unsafe_for_savestate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ir->CreateStore(m_ir->getInt1(may_be_unsafe_for_savestate), m_fake_global1);
|
|
||||||
|
|
||||||
if (may_be_unsafe_for_savestate)
|
|
||||||
{
|
|
||||||
m_ir->CreateStore(m_ir->getInt8(0), spu_ptr<u8>(&spu_thread::unsavable));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ir->CreateBr(_body);
|
m_ir->CreateBr(_body);
|
||||||
m_ir->SetInsertPoint(_body);
|
m_ir->SetInsertPoint(_body);
|
||||||
}
|
}
|
||||||
@ -5013,9 +4998,6 @@ public:
|
|||||||
IRBuilder<> irb(m_context);
|
IRBuilder<> irb(m_context);
|
||||||
m_ir = &irb;
|
m_ir = &irb;
|
||||||
|
|
||||||
// Helper for check_state. Used to not interfere with LICM pass.
|
|
||||||
m_fake_global1 = new llvm::GlobalVariable(*m_module, get_type<bool>(), false, llvm::GlobalValue::InternalLinkage, m_ir->getFalse());
|
|
||||||
|
|
||||||
// Add entry function (contains only state/code check)
|
// Add entry function (contains only state/code check)
|
||||||
const auto main_func = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(m_hash, get_ftype<void, u8*, u8*, u64>()).getCallee());
|
const auto main_func = llvm::cast<llvm::Function>(m_module->getOrInsertFunction(m_hash, get_ftype<void, u8*, u8*, u64>()).getCallee());
|
||||||
const auto main_arg2 = main_func->getArg(2);
|
const auto main_arg2 = main_func->getArg(2);
|
||||||
@ -5033,6 +5015,7 @@ public:
|
|||||||
|
|
||||||
// Emit state check
|
// Emit state check
|
||||||
const auto pstate = spu_ptr<u32>(&spu_thread::state);
|
const auto pstate = spu_ptr<u32>(&spu_thread::state);
|
||||||
|
m_ir->CreateStore(m_ir->getInt8(false), spu_ptr<u8>(&spu_thread::unsavable));
|
||||||
m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->CreateLoad(get_type<u32>(), pstate), m_ir->getInt32(0)), label_stop, label_test, m_md_unlikely);
|
m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->CreateLoad(get_type<u32>(), pstate), m_ir->getInt32(0)), label_stop, label_test, m_md_unlikely);
|
||||||
|
|
||||||
// Emit code check
|
// Emit code check
|
||||||
@ -5200,6 +5183,7 @@ public:
|
|||||||
m_ir->SetInsertPoint(label_body);
|
m_ir->SetInsertPoint(label_body);
|
||||||
const auto pbcount = spu_ptr<u64>(&spu_thread::block_counter);
|
const auto pbcount = spu_ptr<u64>(&spu_thread::block_counter);
|
||||||
m_ir->CreateStore(m_ir->CreateAdd(m_ir->CreateLoad(get_type<u64>(), pbcount), m_ir->getInt64(check_iterations)), pbcount);
|
m_ir->CreateStore(m_ir->CreateAdd(m_ir->CreateLoad(get_type<u64>(), pbcount), m_ir->getInt64(check_iterations)), pbcount);
|
||||||
|
m_ir->CreateStore(m_ir->getInt8(true), spu_ptr<u8>(&spu_thread::unsavable));
|
||||||
|
|
||||||
// Call the entry function chunk
|
// Call the entry function chunk
|
||||||
const auto entry_chunk = add_function(m_pos);
|
const auto entry_chunk = add_function(m_pos);
|
||||||
@ -5634,38 +5618,6 @@ public:
|
|||||||
{
|
{
|
||||||
const auto f = func.second.fn ? func.second.fn : func.second.chunk;
|
const auto f = func.second.fn ? func.second.fn : func.second.chunk;
|
||||||
pm.run(*f);
|
pm.run(*f);
|
||||||
|
|
||||||
for (auto& bb : *f)
|
|
||||||
{
|
|
||||||
for (auto& i : bb)
|
|
||||||
{
|
|
||||||
// Replace fake store with spu_test_state call
|
|
||||||
if (auto si = dyn_cast<StoreInst>(&i); si && si->getOperand(1) == m_fake_global1)
|
|
||||||
{
|
|
||||||
m_ir->SetInsertPoint(si);
|
|
||||||
|
|
||||||
if (si->getOperand(0) == m_ir->getTrue())
|
|
||||||
{
|
|
||||||
m_ir->CreateStore(m_ir->getInt8(1), _ptr<u8>(f->getArg(0), ::offset32(&spu_thread::unsavable)));
|
|
||||||
}
|
|
||||||
|
|
||||||
CallInst* ci{};
|
|
||||||
if (si->getOperand(0) == m_ir->getTrue() || si->getOperand(0) == m_ir->getFalse())
|
|
||||||
{
|
|
||||||
ci = m_ir->CreateCall(m_test_state, {f->getArg(0)});
|
|
||||||
ci->setCallingConv(m_test_state->getCallingConv());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
si->replaceAllUsesWith(ci);
|
|
||||||
si->eraseFromParent();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear context (TODO)
|
// Clear context (TODO)
|
||||||
@ -6321,11 +6273,6 @@ public:
|
|||||||
return exec_rdch(_spu, SPU_RdEventStat);
|
return exec_rdch(_spu, SPU_RdEventStat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ensure_gpr_stores()
|
|
||||||
{
|
|
||||||
m_block->store.fill(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Value* get_rdch(spu_opcode_t op, u32 off, bool atomic)
|
llvm::Value* get_rdch(spu_opcode_t op, u32 off, bool atomic)
|
||||||
{
|
{
|
||||||
const auto ptr = _ptr<u64>(m_thread, off);
|
const auto ptr = _ptr<u64>(m_thread, off);
|
||||||
@ -6382,7 +6329,6 @@ public:
|
|||||||
case SPU_RdInMbox:
|
case SPU_RdInMbox:
|
||||||
{
|
{
|
||||||
update_pc();
|
update_pc();
|
||||||
ensure_gpr_stores();
|
|
||||||
res.value = call("spu_read_in_mbox", &exec_read_in_mbox, m_thread);
|
res.value = call("spu_read_in_mbox", &exec_read_in_mbox, m_thread);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6398,13 +6344,11 @@ public:
|
|||||||
}
|
}
|
||||||
case SPU_RdSigNotify1:
|
case SPU_RdSigNotify1:
|
||||||
{
|
{
|
||||||
ensure_gpr_stores();
|
|
||||||
res.value = get_rdch(op, ::offset32(&spu_thread::ch_snr1), true);
|
res.value = get_rdch(op, ::offset32(&spu_thread::ch_snr1), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPU_RdSigNotify2:
|
case SPU_RdSigNotify2:
|
||||||
{
|
{
|
||||||
ensure_gpr_stores();
|
|
||||||
res.value = get_rdch(op, ::offset32(&spu_thread::ch_snr2), true);
|
res.value = get_rdch(op, ::offset32(&spu_thread::ch_snr2), true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6446,7 +6390,6 @@ public:
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
update_pc();
|
update_pc();
|
||||||
ensure_gpr_stores();
|
|
||||||
res.value = call("spu_read_channel", &exec_rdch, m_thread, m_ir->getInt32(op.ra));
|
res.value = call("spu_read_channel", &exec_rdch, m_thread, m_ir->getInt32(op.ra));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -6792,7 +6735,6 @@ public:
|
|||||||
case MFC_GETLB_CMD:
|
case MFC_GETLB_CMD:
|
||||||
case MFC_GETLF_CMD:
|
case MFC_GETLF_CMD:
|
||||||
{
|
{
|
||||||
ensure_gpr_stores();
|
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case MFC_SDCRZ_CMD:
|
case MFC_SDCRZ_CMD:
|
||||||
@ -7081,7 +7023,6 @@ public:
|
|||||||
m_ir->CreateCondBr(m_ir->CreateICmpNE(_old, _new), _mfc, next);
|
m_ir->CreateCondBr(m_ir->CreateICmpNE(_old, _new), _mfc, next);
|
||||||
m_ir->SetInsertPoint(_mfc);
|
m_ir->SetInsertPoint(_mfc);
|
||||||
update_pc();
|
update_pc();
|
||||||
ensure_gpr_stores();
|
|
||||||
call("spu_list_unstall", &exec_list_unstall, m_thread, eval(val & 0x1f).value);
|
call("spu_list_unstall", &exec_list_unstall, m_thread, eval(val & 0x1f).value);
|
||||||
m_ir->CreateBr(next);
|
m_ir->CreateBr(next);
|
||||||
m_ir->SetInsertPoint(next);
|
m_ir->SetInsertPoint(next);
|
||||||
@ -7105,7 +7046,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
update_pc();
|
update_pc();
|
||||||
ensure_gpr_stores();
|
|
||||||
call("spu_write_channel", &exec_wrch, m_thread, m_ir->getInt32(op.ra), val.value);
|
call("spu_write_channel", &exec_wrch, m_thread, m_ir->getInt32(op.ra), val.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7126,7 +7066,6 @@ public:
|
|||||||
{
|
{
|
||||||
m_block->block_end = m_ir->GetInsertBlock();
|
m_block->block_end = m_ir->GetInsertBlock();
|
||||||
update_pc(m_pos + 4);
|
update_pc(m_pos + 4);
|
||||||
ensure_gpr_stores();
|
|
||||||
tail_chunk(m_dispatch);
|
tail_chunk(m_dispatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10444,7 +10383,7 @@ public:
|
|||||||
{
|
{
|
||||||
// Can't afford external tail call in true functions
|
// Can't afford external tail call in true functions
|
||||||
m_ir->CreateStore(m_ir->getInt32("BIJT"_u32), _ptr<u32>(m_memptr, 0xffdead20));
|
m_ir->CreateStore(m_ir->getInt32("BIJT"_u32), _ptr<u32>(m_memptr, 0xffdead20));
|
||||||
m_ir->CreateStore(m_ir->getFalse(), m_fake_global1);
|
m_ir->CreateCall(m_test_state, {m_thread});
|
||||||
m_ir->CreateBr(sw->getDefaultDest());
|
m_ir->CreateBr(sw->getDefaultDest());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user