mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
321 lines
7.9 KiB
C++
321 lines
7.9 KiB
C++
#pragma once
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
namespace graph {
|
|
template <typename BasicBlockPtrT> class DomTree {
|
|
public:
|
|
struct Node {
|
|
BasicBlockPtrT block = nullptr;
|
|
Node *immDom = nullptr;
|
|
unsigned dfsNumIn = ~0;
|
|
unsigned dfsNumOut = ~0;
|
|
unsigned level = 0;
|
|
std::vector<Node *> children;
|
|
|
|
bool isLeaf() const { return children.empty(); }
|
|
|
|
bool dominatedBy(const Node *other) const {
|
|
return this->dfsNumIn >= other->dfsNumIn &&
|
|
this->dfsNumOut <= other->dfsNumOut;
|
|
}
|
|
};
|
|
|
|
private:
|
|
std::map<BasicBlockPtrT, Node> bbToNodes;
|
|
Node *rootNode = nullptr;
|
|
|
|
public:
|
|
Node *getNode(BasicBlockPtrT bb) {
|
|
auto it = bbToNodes.find(bb);
|
|
if (it != bbToNodes.end()) {
|
|
return &it->second;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
Node *createChild(BasicBlockPtrT bb, Node *parent) {
|
|
auto &child = bbToNodes[bb];
|
|
child.block = bb;
|
|
child.immDom = parent;
|
|
child.level = parent->level + 1;
|
|
parent->children.push_back(&child);
|
|
return &child;
|
|
}
|
|
|
|
Node *createRoot(BasicBlockPtrT bb) {
|
|
auto &root = bbToNodes[bb];
|
|
rootNode = &root;
|
|
root.block = bb;
|
|
return rootNode;
|
|
}
|
|
|
|
Node *getRootNode() { return rootNode; }
|
|
|
|
void updateDFSNumbers() {
|
|
std::vector<std::pair<Node *, typename std::vector<Node *>::iterator>>
|
|
workStack;
|
|
|
|
auto root = getRootNode();
|
|
if (!root)
|
|
return;
|
|
|
|
workStack.push_back({root, root->children.begin()});
|
|
|
|
unsigned dfsNum = 0;
|
|
root->dfsNumIn = dfsNum++;
|
|
|
|
while (!workStack.empty()) {
|
|
auto node = workStack.back().first;
|
|
const auto childIt = workStack.back().second;
|
|
|
|
if (childIt == node->children.end()) {
|
|
node->dfsNumOut = dfsNum++;
|
|
workStack.pop_back();
|
|
} else {
|
|
auto child = *childIt;
|
|
++workStack.back().second;
|
|
|
|
workStack.push_back({child, child->children.begin()});
|
|
child->dfsNumIn = dfsNum++;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool dominates(Node *a, Node *b) {
|
|
if (a == b || b->immDom == a) {
|
|
return true;
|
|
}
|
|
|
|
if (a->immDom == b || a->level >= b->level) {
|
|
return false;
|
|
}
|
|
|
|
return b->dominatedBy(a);
|
|
}
|
|
|
|
bool dominates(BasicBlockPtrT a, BasicBlockPtrT b) {
|
|
return dominates(getNode(a), getNode(b));
|
|
}
|
|
|
|
BasicBlockPtrT getImmediateDominator(BasicBlockPtrT a) {
|
|
auto immDom = getNode(a)->immDom;
|
|
if (immDom) {
|
|
return immDom->block;
|
|
}
|
|
return{};
|
|
}
|
|
|
|
bool isImmediateDominator(BasicBlockPtrT block, BasicBlockPtrT immDomBlock) {
|
|
if (immDomBlock == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return getImmediateDominator(immDomBlock) == block;
|
|
}
|
|
|
|
BasicBlockPtrT findNearestCommonDominator(BasicBlockPtrT a,
|
|
BasicBlockPtrT b) {
|
|
auto aNode = getNode(a);
|
|
auto bNode = getNode(b);
|
|
|
|
if (aNode == rootNode || bNode == rootNode) {
|
|
return rootNode->block;
|
|
}
|
|
|
|
while (aNode != bNode) {
|
|
if (aNode->level < bNode->level) {
|
|
std::swap(aNode, bNode);
|
|
}
|
|
|
|
aNode = aNode->immDom;
|
|
}
|
|
|
|
return aNode->block;
|
|
}
|
|
};
|
|
|
|
template <typename BasicBlockPtrT> class DomTreeBuilder {
|
|
using DomTreeNode = typename DomTree<BasicBlockPtrT>::Node;
|
|
|
|
struct NodeInfo {
|
|
unsigned dfsNum = 0;
|
|
unsigned parent = 0;
|
|
unsigned semi = 0;
|
|
BasicBlockPtrT label = nullptr;
|
|
BasicBlockPtrT immDom = nullptr;
|
|
std::vector<BasicBlockPtrT> revChildren;
|
|
};
|
|
|
|
std::vector<BasicBlockPtrT> indexToNode = {nullptr};
|
|
std::map<BasicBlockPtrT, NodeInfo> nodeToInfo;
|
|
|
|
template <typename WalkFn>
|
|
void runDFS(BasicBlockPtrT root, const WalkFn &walk) {
|
|
std::vector<BasicBlockPtrT> workList;
|
|
workList.reserve(10);
|
|
workList.push_back(root);
|
|
unsigned index = 0;
|
|
|
|
while (!workList.empty()) {
|
|
auto bb = workList.back();
|
|
workList.pop_back();
|
|
|
|
auto &bbInfo = nodeToInfo[bb];
|
|
|
|
if (bbInfo.dfsNum != 0) {
|
|
continue;
|
|
}
|
|
|
|
bbInfo.dfsNum = bbInfo.semi = ++index;
|
|
bbInfo.label = bb;
|
|
indexToNode.push_back(bb);
|
|
|
|
walk(bb, [&](BasicBlockPtrT successor) {
|
|
auto it = nodeToInfo.find(successor);
|
|
if (it != nodeToInfo.end() && it->second.dfsNum != 0) {
|
|
if (successor != bb) {
|
|
it->second.revChildren.push_back(bb);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
auto &succInfo = nodeToInfo[successor];
|
|
workList.push_back(successor);
|
|
succInfo.parent = index;
|
|
succInfo.revChildren.push_back(bb);
|
|
});
|
|
}
|
|
}
|
|
|
|
void runSemiNCA() {
|
|
const unsigned nextDFS = indexToNode.size();
|
|
|
|
for (unsigned i = 1; i < nextDFS; ++i) {
|
|
const BasicBlockPtrT node = indexToNode[i];
|
|
auto &NodeInfo = nodeToInfo[node];
|
|
NodeInfo.immDom = indexToNode[NodeInfo.parent];
|
|
}
|
|
|
|
std::vector<NodeInfo *> evalStack;
|
|
evalStack.reserve(10);
|
|
|
|
for (unsigned i = nextDFS - 1; i >= 2; --i) {
|
|
BasicBlockPtrT node = indexToNode[i];
|
|
auto &nodeInfo = nodeToInfo[node];
|
|
|
|
nodeInfo.semi = nodeInfo.parent;
|
|
for (const auto &child : nodeInfo.revChildren) {
|
|
if (!nodeToInfo.contains(child)) {
|
|
continue;
|
|
}
|
|
|
|
unsigned childSemi = nodeToInfo[eval(child, i + 1, evalStack)].semi;
|
|
if (childSemi < nodeInfo.semi) {
|
|
nodeInfo.semi = childSemi;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (unsigned i = 2; i < nextDFS; ++i) {
|
|
const BasicBlockPtrT node = indexToNode[i];
|
|
auto &nodeInfo = nodeToInfo[node];
|
|
const unsigned sDomNum = nodeToInfo[indexToNode[nodeInfo.semi]].dfsNum;
|
|
BasicBlockPtrT immDom = nodeInfo.immDom;
|
|
|
|
while (nodeToInfo[immDom].dfsNum > sDomNum) {
|
|
immDom = nodeToInfo[immDom].immDom;
|
|
}
|
|
|
|
nodeInfo.immDom = immDom;
|
|
}
|
|
}
|
|
|
|
BasicBlockPtrT eval(BasicBlockPtrT block, unsigned LastLinked,
|
|
std::vector<NodeInfo *> &stack) {
|
|
NodeInfo *blockInfo = &nodeToInfo[block];
|
|
if (blockInfo->parent < LastLinked)
|
|
return blockInfo->label;
|
|
|
|
do {
|
|
stack.push_back(blockInfo);
|
|
blockInfo = &nodeToInfo[indexToNode[blockInfo->parent]];
|
|
} while (blockInfo->parent >= LastLinked);
|
|
|
|
const NodeInfo *pInfo = blockInfo;
|
|
const NodeInfo *pLabelInfo = &nodeToInfo[pInfo->label];
|
|
do {
|
|
blockInfo = stack.back();
|
|
stack.pop_back();
|
|
|
|
blockInfo->parent = pInfo->parent;
|
|
const NodeInfo *labelInfo = &nodeToInfo[blockInfo->label];
|
|
if (pLabelInfo->semi < labelInfo->semi) {
|
|
blockInfo->label = pInfo->label;
|
|
} else {
|
|
pLabelInfo = labelInfo;
|
|
}
|
|
|
|
pInfo = blockInfo;
|
|
} while (!stack.empty());
|
|
return blockInfo->label;
|
|
}
|
|
|
|
DomTreeNode *getNodeForBlock(BasicBlockPtrT BB, DomTree<BasicBlockPtrT> &DT) {
|
|
if (auto Node = DT.getNode(BB))
|
|
return Node;
|
|
|
|
BasicBlockPtrT IDom = getIDom(BB);
|
|
auto IDomNode = getNodeForBlock(IDom, DT);
|
|
|
|
return DT.createChild(BB, IDomNode);
|
|
}
|
|
|
|
BasicBlockPtrT getIDom(BasicBlockPtrT BB) const {
|
|
auto InfoIt = nodeToInfo.find(BB);
|
|
if (InfoIt == nodeToInfo.end())
|
|
return nullptr;
|
|
|
|
return InfoIt->second.immDom;
|
|
}
|
|
|
|
public:
|
|
template <typename WalkFn>
|
|
DomTree<BasicBlockPtrT> build(BasicBlockPtrT root,
|
|
const WalkFn &walkSuccessors) {
|
|
runDFS(root, walkSuccessors);
|
|
runSemiNCA();
|
|
|
|
DomTree<BasicBlockPtrT> domTree;
|
|
domTree.createRoot(root);
|
|
|
|
nodeToInfo[indexToNode[1]].immDom = root;
|
|
|
|
for (size_t i = 1, e = indexToNode.size(); i != e; ++i) {
|
|
BasicBlockPtrT node = indexToNode[i];
|
|
|
|
if (domTree.getNode(node))
|
|
continue;
|
|
|
|
BasicBlockPtrT immDom = getIDom(node);
|
|
|
|
auto immDomNode = getNodeForBlock(immDom, domTree);
|
|
domTree.createChild(node, immDomNode);
|
|
}
|
|
|
|
domTree.updateDFSNumbers();
|
|
return domTree;
|
|
}
|
|
};
|
|
|
|
template <typename BasicBlockPtrT>
|
|
DomTree<BasicBlockPtrT> buildDomTree(BasicBlockPtrT root, auto &&walkSuccessors)
|
|
requires requires(void (*cb)(BasicBlockPtrT)) { walkSuccessors(root, cb); }
|
|
{
|
|
return DomTreeBuilder<BasicBlockPtrT>().build(root, walkSuccessors);
|
|
}
|
|
} // namespace graph
|