#pragma once #include #include namespace graph { template class DomTree { public: struct Node { BasicBlockPtrT block = nullptr; Node *immDom = nullptr; unsigned dfsNumIn = ~0; unsigned dfsNumOut = ~0; unsigned level = 0; std::vector 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 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::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 class DomTreeBuilder { using DomTreeNode = typename DomTree::Node; struct NodeInfo { unsigned dfsNum = 0; unsigned parent = 0; unsigned semi = 0; BasicBlockPtrT label = nullptr; BasicBlockPtrT immDom = nullptr; std::vector revChildren; }; std::vector indexToNode = {nullptr}; std::map nodeToInfo; template void runDFS(BasicBlockPtrT root, const WalkFn &walk) { std::vector 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 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 &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 &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 DomTree build(BasicBlockPtrT root, const WalkFn &walkSuccessors) { runDFS(root, walkSuccessors); runSemiNCA(); DomTree 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 DomTree buildDomTree(BasicBlockPtrT root, auto &&walkSuccessors) requires requires(void (*cb)(BasicBlockPtrT)) { walkSuccessors(root, cb); } { return DomTreeBuilder().build(root, walkSuccessors); } } // namespace graph