mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-03 21:41:26 +12:00
SPU LLVM: Fix store elimination within common blocks
GPR register barriers were ignored in that case.
This commit is contained in:
parent
d37b9497a2
commit
3c46388be5
1 changed files with 22 additions and 4 deletions
|
@ -160,7 +160,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||||
// Store reordering/elimination protection
|
// Store reordering/elimination protection
|
||||||
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 counter
|
||||||
|
bool has_gpr_memory_barriers = false; // Summarizes whether GPR barriers exist this block (as if checking all store_context_ctr entries)
|
||||||
|
|
||||||
bool does_gpr_barrier_proceed_last_store(u32 i) const noexcept
|
bool does_gpr_barrier_proceed_last_store(u32 i) const noexcept
|
||||||
{
|
{
|
||||||
|
@ -1672,10 +1673,14 @@ public:
|
||||||
|
|
||||||
std::vector<block_info*> block_q;
|
std::vector<block_info*> block_q;
|
||||||
block_q.reserve(m_blocks.size());
|
block_q.reserve(m_blocks.size());
|
||||||
|
|
||||||
|
bool has_gpr_memory_barriers = false;
|
||||||
|
|
||||||
for (auto& [a, b] : m_blocks)
|
for (auto& [a, b] : m_blocks)
|
||||||
{
|
{
|
||||||
block_q.emplace_back(&b);
|
block_q.emplace_back(&b);
|
||||||
bb_to_info[b.block] = &b;
|
bb_to_info[b.block] = &b;
|
||||||
|
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();)
|
||||||
|
@ -1683,7 +1688,7 @@ public:
|
||||||
auto bqbi = block_q[bi++];
|
auto bqbi = block_q[bi++];
|
||||||
|
|
||||||
// TODO: process all registers up to s_reg_max
|
// TODO: process all registers up to s_reg_max
|
||||||
for (u32 i = 0; i < 128; i++)
|
for (u32 i = 0; i <= s_reg_127; 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->does_gpr_barrier_proceed_last_store(i))
|
if (auto& bs = bqbi->store[i]; bs && !bqbi->does_gpr_barrier_proceed_last_store(i))
|
||||||
|
@ -1732,16 +1737,28 @@ public:
|
||||||
|
|
||||||
// Find nearest common post-dominator
|
// Find nearest common post-dominator
|
||||||
llvm::BasicBlock* common_pdom = killers[0];
|
llvm::BasicBlock* common_pdom = killers[0];
|
||||||
|
|
||||||
|
if (has_gpr_memory_barriers)
|
||||||
|
{
|
||||||
|
// Cannot optimize block walk-through, need to inspect all possible memory barriers in the way
|
||||||
|
common_pdom = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto* bbb : llvm::drop_begin(killers))
|
for (auto* bbb : llvm::drop_begin(killers))
|
||||||
{
|
{
|
||||||
if (!common_pdom)
|
if (!common_pdom)
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
common_pdom = pdt.findNearestCommonDominator(common_pdom, bbb);
|
common_pdom = pdt.findNearestCommonDominator(common_pdom, bbb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shortcut
|
// Shortcut
|
||||||
if (!pdt.dominates(common_pdom, bs->getParent()))
|
if (common_pdom && !pdt.dominates(common_pdom, bs->getParent()))
|
||||||
|
{
|
||||||
common_pdom = nullptr;
|
common_pdom = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Look for possibly-dead store in CFG starting from the exit nodes
|
// Look for possibly-dead store in CFG starting from the exit nodes
|
||||||
llvm::SetVector<llvm::BasicBlock*> work_list;
|
llvm::SetVector<llvm::BasicBlock*> work_list;
|
||||||
|
@ -1878,7 +1895,7 @@ public:
|
||||||
|
|
||||||
for (usz bi = 0; bi < block_q.size(); bi++)
|
for (usz bi = 0; bi < block_q.size(); bi++)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < 128; i++)
|
for (u32 i = 0; i <= s_reg_127; 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]->does_gpr_barrier_proceed_last_store(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))
|
||||||
|
@ -2749,6 +2766,7 @@ public:
|
||||||
{
|
{
|
||||||
// Make previous stores not able to be reordered beyond this point or be deleted
|
// Make previous stores not able to be reordered beyond this point or be deleted
|
||||||
std::for_each(m_block->store_context_ctr.begin(), m_block->store_context_ctr.end(), FN(x++));
|
std::for_each(m_block->store_context_ctr.begin(), m_block->store_context_ctr.end(), FN(x++));
|
||||||
|
m_block->has_gpr_memory_barriers = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue