Skip to content

Commit

Permalink
SPU LLVM: upgrade custom DSE pass
Browse files Browse the repository at this point in the history
  • Loading branch information
Nekotekina committed Apr 20, 2023
1 parent 6981cbb commit 183bea3
Showing 1 changed file with 112 additions and 8 deletions.
120 changes: 112 additions & 8 deletions rpcs3/Emu/Cell/SPURecompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3921,6 +3921,8 @@ void spu_recompiler_base::dump(const spu_program& result, std::string& out)
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/ADT/PostOrderIterator.h"
#ifdef _MSC_VER
#pragma warning(pop)
#else
Expand Down Expand Up @@ -5453,26 +5455,34 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
}

// Work on register stores.
// 1. Remove stores which are post-dominated.
// 1. Remove stores which are overwritten later.
// 2. Sink stores to post-dominating blocks.
llvm::PostDominatorTree pdt(*m_function);
llvm::DominatorTree dt(*m_function);

// Post-order indices
std::unordered_map<llvm::BasicBlock*, usz> pois;
{
usz i = 0;
for (auto* bb : llvm::post_order(m_function))
pois[bb] = i++;
}

std::vector<block_info*> block_q;
block_q.reserve(m_blocks.size());
for (auto& [a, b] : m_blocks)
{
block_q.emplace_back(&b);
}

for (usz bi = 0; bi < block_q.size(); bi++)
for (usz bi = 0; bi < block_q.size();)
{
auto bqbi = block_q[bi++];

// TODO: process all registers up to s_reg_max
for (u32 i = 0; i < 128; i++)
{
auto& bs = block_q[bi]->store[i];

if (bs)
if (auto& bs = bqbi->store[i])
{
for (auto& [a, b] : m_blocks)
{
Expand All @@ -5482,17 +5492,111 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
{
bs->eraseFromParent();
bs = nullptr;
break;
}
}
}

if (!bs)
continue;

// Set of store instructions which overwrite bs
std::vector<llvm::BasicBlock*> killers;

for (auto& [a, b] : m_blocks)
{
const auto si = b.store[i];

pdt.recalculate(*m_function);
dt.recalculate(*m_function);
if (si && si != bs)
{
if (pois[bs->getParent()] > pois[si->getParent()])
{
killers.emplace_back(si->getParent());
}
else
{
// Reset: store is not the first in the set
killers.clear();
break;
}
}
}

if (killers.empty())
continue;

// Find nearest common post-dominator
llvm::BasicBlock* common_pdom = killers[0];
for (auto* bbb : llvm::drop_begin(killers))
{
if (!common_pdom)
break;
common_pdom = pdt.findNearestCommonDominator(common_pdom, bbb);
}

// Shortcut
if (!pdt.dominates(common_pdom, bs->getParent()))
common_pdom = nullptr;

// Look for possibly-dead store in CFG starting from the exit nodes
llvm::SetVector<llvm::BasicBlock*> work_list;
if (std::count(killers.begin(), killers.end(), common_pdom) == 0)
{
if (common_pdom)
{
// Shortcut
work_list.insert(common_pdom);
}
else
{
// Check all exits
for (auto* r : pdt.roots())
work_list.insert(r);
}
}

for (usz wi = 0; wi < work_list.size(); wi++)
{
auto* cur = work_list[wi];
if (std::count(killers.begin(), killers.end(), cur))
continue;

if (cur == bs->getParent())
{
// Reset: store is not dead
killers.clear();
break;
}

for (auto* p : llvm::predecessors(cur))
work_list.insert(p);
}

// Finally erase the dead store
if (!killers.empty())
{
bs->eraseFromParent();
bs = nullptr;

// Run the loop from the start
bi = 0;
}
}
}
}

block_q.clear();
for (auto& [a, b] : m_blocks)
{
block_q.emplace_back(&b);
}

for (usz bi = 0; bi < block_q.size(); bi++)
{
for (u32 i = 0; i < 128; i++)
{
// If store isn't erased, try to sink it
if (bs)
if (auto& bs = block_q[bi]->store[i])
{
std::map<u32, block_info*, std::greater<>> sucs;

Expand Down

0 comments on commit 183bea3

Please sign in to comment.