rpcsx/rpcsx-gpu/lib/gcn-shader/include/shader/graph.hpp
2024-10-01 22:04:40 +03:00

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