Savestates/SPU LLVM: Fix sinking store finally

This commit is contained in:
Elad Ashkenazi 2024-05-22 11:54:27 +03:00
parent 5d6d42d15d
commit b3c9f7647f
2 changed files with 39 additions and 19 deletions

View File

@ -1984,9 +1984,9 @@ public:
has_gpr_memory_barriers |= b.has_gpr_memory_barriers;
}
for (usz bi = 0; bi < block_q.size();)
for (usz bi = 0; bi < block_q.size(); bi++)
{
auto bqbi = block_q[bi++].second;
auto bqbi = block_q[bi].second;
// TODO: process all registers up to s_reg_max
for (u32 i = 0; i <= s_reg_127; i++)
@ -2001,6 +2001,8 @@ public:
{
if (pdt.dominates(b.store[i], bs))
{
spu_log.trace("Erased r%u store from block 0x%x (simple)", i, block_q[bi].first);
bs->eraseFromParent();
bs = nullptr;
break;
@ -2178,6 +2180,8 @@ public:
// Finally erase the dead store
if (!killers.empty())
{
spu_log.trace("Erased r%u store from block 0x%x (reversed)", i, block_q[bi].first);
bs->eraseFromParent();
bs = nullptr;
@ -2199,26 +2203,34 @@ public:
auto bqbi = block_q[bi].second;
std::vector<std::pair<u32, bool>> work_list;
std::map<u32, block_info*, std::greater<>> sucs;
std::unordered_map<u32, bool> worked_on;
for (u32 i = 0; i <= s_reg_127; i++)
{
// If store isn't erased, try to sink it
if (auto& bs = bqbi->store[i]; bs && bqbi->bb->targets.size() > 1 && !bqbi->does_gpr_barrier_proceed_last_store(i))
{
std::map<u32, block_info*, std::greater<>> sucs;
for (u32 tj : bqbi->bb->targets)
if (sucs.empty())
{
auto b2it = m_blocks.find(tj);
if (b2it != m_blocks.end())
for (u32 tj : bqbi->bb->targets)
{
sucs.emplace(tj, &b2it->second);
auto b2it = m_blocks.find(tj);
if (b2it != m_blocks.end())
{
sucs.emplace(tj, &b2it->second);
}
}
}
// Reset
work_list.clear();
std::unordered_map<u32, bool> worked_on;
for (auto& [_, worked] : worked_on)
{
worked = false;
}
bool has_gpr_barriers_in_the_way = false;
@ -2235,8 +2247,11 @@ public:
continue;
}
work_list.emplace_back(a2, false);
worked_on[a2] = true;
if (!worked_on[a2])
{
work_list.emplace_back(a2, b2->store_context_ctr[i] != 1);
worked_on[a2] = true;
}
}
if (has_gpr_barriers_in_the_way)
@ -2245,14 +2260,11 @@ public:
continue;
}
// Need to treat tails differently: do not require checking barrier (checked before in a suitable manner)
const usz work_list_start_blocks_max_index = work_list.size();
for (usz wi = 0; wi < work_list.size(); wi++)
{
auto [cur, found_barrier] = work_list[wi];
if (!found_barrier && wi >= work_list_start_blocks_max_index)
if (!found_barrier)
{
if (const auto it = m_blocks.find(cur); it != m_blocks.cend())
{
@ -2263,7 +2275,7 @@ public:
}
}
if (cur == block_q[bi].first && wi >= work_list_start_blocks_max_index)
if (cur == block_q[bi].first)
{
if (found_barrier)
{
@ -2333,6 +2345,8 @@ public:
block_q.emplace_back(a2, b2);
}
}
spu_log.trace("Postoned r%u store from block 0x%x (single)", i, block_q[bi].first);
}
else
{
@ -2372,6 +2386,8 @@ public:
edge = llvm::SplitEdge(bqbi->block_end, succ);
pdt.recalculate(*m_function);
dt.recalculate(*m_function);
spu_log.trace("Postoned r%u store from block 0x%x (multiple)", i, block_q[bi].first);
}
ins = edge->getTerminator();

View File

@ -3147,12 +3147,16 @@ void Emulator::Kill(bool allow_autoexit, bool savestate, savestate_stage* save_s
for (const auto& spu : save_stage.paused_spus)
{
if (spu.first->pc != spu.second)
if (spu.first->pc != spu.second || spu.first->unsavable)
{
sys_log.error("SPU thread continued after being paused. (old_pc=0x%x, pc=0x%x, unsavable=%d)", spu.second, spu.first->pc, spu.first->unsavable);
std::string dump;
spu.first->dump_all(dump);
sys_log.error("SPU thread continued after being paused. (old_pc=0x%x, pc=0x%x, unsavable=%d)", spu.second, spu.first->pc, spu.first->unsavable);
spu_log.notice("SPU thread context:\n%s", dump);
}
}
// Save it first for maximum timing accuracy
const u64 timestamp = get_timebased_time();
const u64 start_time = get_system_time();