SPU/Savestates: Remove reservation hack, allow its saving

This commit is contained in:
Eladash 2023-12-29 08:30:15 +02:00 committed by Elad Ashkenazi
parent e209dc1229
commit 9f6c5381a1
2 changed files with 52 additions and 16 deletions

View file

@ -4521,6 +4521,18 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
std::array<usz, s_reg_max> store_context_last_id = fill_array<usz>(0); // Protects against illegal forward ordering std::array<usz, s_reg_max> store_context_last_id = fill_array<usz>(0); // Protects against illegal forward ordering
std::array<usz, s_reg_max> store_context_first_id = fill_array<usz>(usz{umax}); // Protects against illegal past store elimination (backwards ordering is not implemented) std::array<usz, s_reg_max> store_context_first_id = fill_array<usz>(usz{umax}); // Protects against illegal past store elimination (backwards ordering is not implemented)
std::array<usz, s_reg_max> store_context_ctr = fill_array<usz>(1); // Store barrier cointer std::array<usz, s_reg_max> store_context_ctr = fill_array<usz>(1); // Store barrier cointer
bool does_gpr_barrier_proceed_last_store(u32 i) const noexcept
{
const usz counter = store_context_ctr[i];
return counter != 1 && counter > store_context_last_id[i];
}
bool does_gpr_barrier_preceed_first_store(u32 i) const noexcept
{
const usz counter = store_context_ctr[i];
return counter != 1 && counter < store_context_first_id[i];
}
}; };
struct function_info struct function_info
@ -6019,7 +6031,7 @@ public:
for (u32 i = 0; i < 128; i++) for (u32 i = 0; i < 128; i++)
{ {
// Check if the store is beyond the last barrier // Check if the store is beyond the last barrier
if (auto& bs = bqbi->store[i]; bs && bqbi->store_context_last_id[i] == bqbi->store_context_ctr[i]) if (auto& bs = bqbi->store[i]; bs && !bqbi->does_gpr_barrier_proceed_last_store(i))
{ {
for (auto& [a, b] : m_blocks) for (auto& [a, b] : m_blocks)
{ {
@ -6107,7 +6119,7 @@ public:
auto* cur = work_list[wi]; auto* cur = work_list[wi];
if (std::count(killers.begin(), killers.end(), cur)) if (std::count(killers.begin(), killers.end(), cur))
{ {
work2_list.emplace_back(cur, bb_to_info[cur] && bb_to_info[cur]->store_context_first_id[i] > 1); work2_list.emplace_back(cur, bb_to_info[cur] && bb_to_info[cur]->does_gpr_barrier_preceed_first_store(i));
continue; continue;
} }
@ -6145,17 +6157,7 @@ public:
{ {
auto [cur, found_user] = work2_list[wi]; auto [cur, found_user] = work2_list[wi];
if (cur == bs->getParent()) ensure(cur != bs->getParent());
{
if (found_user)
{
// Reset: store is being used and preserved by ensure_gpr_stores()
killers.clear();
break;
}
continue;
}
if (!found_user && wi >= work_list_tail_blocks_max_index) if (!found_user && wi >= work_list_tail_blocks_max_index)
{ {
@ -6170,6 +6172,18 @@ public:
for (auto* p : llvm::predecessors(cur)) for (auto* p : llvm::predecessors(cur))
{ {
if (p == bs->getParent())
{
if (found_user)
{
// Reset: store is being used and preserved by ensure_gpr_stores()
killers.clear();
break;
}
continue;
}
if (!worked_on[p]) if (!worked_on[p])
{ {
worked_on[p] = true; worked_on[p] = true;
@ -6181,6 +6195,11 @@ public:
work2_list.push_back(std::make_pair(p, true)); work2_list.push_back(std::make_pair(p, true));
} }
} }
if (killers.empty())
{
break;
}
} }
// Finally erase the dead store // Finally erase the dead store
@ -6207,7 +6226,7 @@ public:
for (u32 i = 0; i < 128; i++) for (u32 i = 0; i < 128; i++)
{ {
// If store isn't erased, try to sink it // If store isn't erased, try to sink it
if (auto& bs = block_q[bi]->store[i]; bs && block_q[bi]->bb->targets.size() > 1 && block_q[bi]->store_context_last_id[i] == block_q[bi]->store_context_ctr[i]) if (auto& bs = block_q[bi]->store[i]; bs && block_q[bi]->bb->targets.size() > 1 && !block_q[bi]->does_gpr_barrier_proceed_last_store(i))
{ {
std::map<u32, block_info*, std::greater<>> sucs; std::map<u32, block_info*, std::greater<>> sucs;

View file

@ -2022,6 +2022,20 @@ spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
serialize_common(ar); serialize_common(ar);
raddr = ::narrow<u32>(ar.pop<u64>());
if (raddr)
{
// Acquire reservation
if (!vm::check_addr(raddr))
{
fmt::throw_exception("SPU Serialization: Reservation address is not accessible! (addr=0x%x)", raddr);
}
rtime = vm::reservation_acquire(raddr);
mov_rdata(rdata, *vm::get_super_ptr<spu_rdata_t>(raddr));
}
status_npc.raw().npc = pc | u8{interrupts_enabled}; status_npc.raw().npc = pc | u8{interrupts_enabled};
if (get_type() == spu_type::threaded) if (get_type() == spu_type::threaded)
@ -2058,8 +2072,8 @@ void spu_thread::save(utils::serial& ar)
if (raddr) if (raddr)
{ {
// Lose reservation at savestate load with an event if one existed at savestate save // Last check for reservation-lost event
set_events(SPU_EVENT_LR); get_events(SPU_EVENT_LR);
} }
ar(index); ar(index);
@ -2073,6 +2087,9 @@ void spu_thread::save(utils::serial& ar)
serialize_common(ar); serialize_common(ar);
// Let's save it as u64 for future proofing
ar(u64{raddr});
if (get_type() == spu_type::threaded) if (get_type() == spu_type::threaded)
{ {
for (const auto& [key, q] : spuq) for (const auto& [key, q] : spuq)