SPU LLVM: make savestates unsavable inside the code

This commit is contained in:
Ivan Chikish 2023-04-16 19:36:54 +03:00 committed by Ivan
parent 8153e5338f
commit 39d17a94c6

View File

@ -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_to_float{};
// Helper for check_state
llvm::GlobalVariable* m_fake_global1{};
// Function for check_state execution
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)
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 _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->SetInsertPoint(check);
update_pc(addr);
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->CreateCall(m_test_state, {m_thread});
m_ir->CreateBr(_body);
m_ir->SetInsertPoint(_body);
}
@ -5013,9 +4998,6 @@ public:
IRBuilder<> irb(m_context);
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)
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);
@ -5033,6 +5015,7 @@ public:
// Emit state check
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);
// Emit code check
@ -5200,6 +5183,7 @@ public:
m_ir->SetInsertPoint(label_body);
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->getInt8(true), spu_ptr<u8>(&spu_thread::unsavable));
// Call the entry function chunk
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;
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)
@ -6321,11 +6273,6 @@ public:
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)
{
const auto ptr = _ptr<u64>(m_thread, off);
@ -6382,7 +6329,6 @@ public:
case SPU_RdInMbox:
{
update_pc();
ensure_gpr_stores();
res.value = call("spu_read_in_mbox", &exec_read_in_mbox, m_thread);
break;
}
@ -6398,13 +6344,11 @@ public:
}
case SPU_RdSigNotify1:
{
ensure_gpr_stores();
res.value = get_rdch(op, ::offset32(&spu_thread::ch_snr1), true);
break;
}
case SPU_RdSigNotify2:
{
ensure_gpr_stores();
res.value = get_rdch(op, ::offset32(&spu_thread::ch_snr2), true);
break;
}
@ -6446,7 +6390,6 @@ public:
default:
{
update_pc();
ensure_gpr_stores();
res.value = call("spu_read_channel", &exec_rdch, m_thread, m_ir->getInt32(op.ra));
break;
}
@ -6792,7 +6735,6 @@ public:
case MFC_GETLB_CMD:
case MFC_GETLF_CMD:
{
ensure_gpr_stores();
[[fallthrough]];
}
case MFC_SDCRZ_CMD:
@ -7081,7 +7023,6 @@ public:
m_ir->CreateCondBr(m_ir->CreateICmpNE(_old, _new), _mfc, next);
m_ir->SetInsertPoint(_mfc);
update_pc();
ensure_gpr_stores();
call("spu_list_unstall", &exec_list_unstall, m_thread, eval(val & 0x1f).value);
m_ir->CreateBr(next);
m_ir->SetInsertPoint(next);
@ -7105,7 +7046,6 @@ public:
}
update_pc();
ensure_gpr_stores();
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();
update_pc(m_pos + 4);
ensure_gpr_stores();
tail_chunk(m_dispatch);
}
}
@ -10444,7 +10383,7 @@ public:
{
// 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->getFalse(), m_fake_global1);
m_ir->CreateCall(m_test_state, {m_thread});
m_ir->CreateBr(sw->getDefaultDest());
}
else