123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- GenericDomTreeConstruction.h - Dominator Calculation ------*- C++ -*-==//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- /// \file
- ///
- /// Generic dominator tree construction - this file provides routines to
- /// construct immediate dominator information for a flow-graph based on the
- /// Semi-NCA algorithm described in this dissertation:
- ///
- /// [1] Linear-Time Algorithms for Dominators and Related Problems
- /// Loukas Georgiadis, Princeton University, November 2005, pp. 21-23:
- /// ftp://ftp.cs.princeton.edu/reports/2005/737.pdf
- ///
- /// Semi-NCA algorithm runs in O(n^2) worst-case time but usually slightly
- /// faster than Simple Lengauer-Tarjan in practice.
- ///
- /// O(n^2) worst cases happen when the computation of nearest common ancestors
- /// requires O(n) average time, which is very unlikely in real world. If this
- /// ever turns out to be an issue, consider implementing a hybrid algorithm
- /// that uses SLT to perform full constructions and SemiNCA for incremental
- /// updates.
- ///
- /// The file uses the Depth Based Search algorithm to perform incremental
- /// updates (insertion and deletions). The implemented algorithm is based on
- /// this publication:
- ///
- /// [2] An Experimental Study of Dynamic Dominators
- /// Loukas Georgiadis, et al., April 12 2016, pp. 5-7, 9-10:
- /// https://arxiv.org/pdf/1604.02711.pdf
- ///
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
- #define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/DenseSet.h"
- #include "llvm/ADT/DepthFirstIterator.h"
- #include "llvm/ADT/PointerIntPair.h"
- #include "llvm/ADT/SmallPtrSet.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/GenericDomTree.h"
- #include <optional>
- #include <queue>
- #define DEBUG_TYPE "dom-tree-builder"
- namespace llvm {
- namespace DomTreeBuilder {
- template <typename DomTreeT>
- struct SemiNCAInfo {
- using NodePtr = typename DomTreeT::NodePtr;
- using NodeT = typename DomTreeT::NodeType;
- using TreeNodePtr = DomTreeNodeBase<NodeT> *;
- using RootsT = decltype(DomTreeT::Roots);
- static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
- using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
- // Information record used by Semi-NCA during tree construction.
- struct InfoRec {
- unsigned DFSNum = 0;
- unsigned Parent = 0;
- unsigned Semi = 0;
- NodePtr Label = nullptr;
- NodePtr IDom = nullptr;
- SmallVector<NodePtr, 2> ReverseChildren;
- };
- // Number to node mapping is 1-based. Initialize the mapping to start with
- // a dummy element.
- std::vector<NodePtr> NumToNode = {nullptr};
- DenseMap<NodePtr, InfoRec> NodeToInfo;
- using UpdateT = typename DomTreeT::UpdateType;
- using UpdateKind = typename DomTreeT::UpdateKind;
- struct BatchUpdateInfo {
- // Note: Updates inside PreViewCFG are already legalized.
- BatchUpdateInfo(GraphDiffT &PreViewCFG, GraphDiffT *PostViewCFG = nullptr)
- : PreViewCFG(PreViewCFG), PostViewCFG(PostViewCFG),
- NumLegalized(PreViewCFG.getNumLegalizedUpdates()) {}
- // Remembers if the whole tree was recalculated at some point during the
- // current batch update.
- bool IsRecalculated = false;
- GraphDiffT &PreViewCFG;
- GraphDiffT *PostViewCFG;
- const size_t NumLegalized;
- };
- BatchUpdateInfo *BatchUpdates;
- using BatchUpdatePtr = BatchUpdateInfo *;
- // If BUI is a nullptr, then there's no batch update in progress.
- SemiNCAInfo(BatchUpdatePtr BUI) : BatchUpdates(BUI) {}
- void clear() {
- NumToNode = {nullptr}; // Restore to initial state with a dummy start node.
- NodeToInfo.clear();
- // Don't reset the pointer to BatchUpdateInfo here -- if there's an update
- // in progress, we need this information to continue it.
- }
- template <bool Inversed>
- static SmallVector<NodePtr, 8> getChildren(NodePtr N, BatchUpdatePtr BUI) {
- if (BUI)
- return BUI->PreViewCFG.template getChildren<Inversed>(N);
- return getChildren<Inversed>(N);
- }
- template <bool Inversed>
- static SmallVector<NodePtr, 8> getChildren(NodePtr N) {
- using DirectedNodeT =
- std::conditional_t<Inversed, Inverse<NodePtr>, NodePtr>;
- auto R = children<DirectedNodeT>(N);
- SmallVector<NodePtr, 8> Res(detail::reverse_if<!Inversed>(R));
- // Remove nullptr children for clang.
- llvm::erase_value(Res, nullptr);
- return Res;
- }
- NodePtr getIDom(NodePtr BB) const {
- auto InfoIt = NodeToInfo.find(BB);
- if (InfoIt == NodeToInfo.end()) return nullptr;
- return InfoIt->second.IDom;
- }
- TreeNodePtr getNodeForBlock(NodePtr BB, DomTreeT &DT) {
- if (TreeNodePtr Node = DT.getNode(BB)) return Node;
- // Haven't calculated this node yet? Get or calculate the node for the
- // immediate dominator.
- NodePtr IDom = getIDom(BB);
- assert(IDom || DT.DomTreeNodes[nullptr]);
- TreeNodePtr IDomNode = getNodeForBlock(IDom, DT);
- // Add a new tree node for this NodeT, and link it as a child of
- // IDomNode
- return DT.createChild(BB, IDomNode);
- }
- static bool AlwaysDescend(NodePtr, NodePtr) { return true; }
- struct BlockNamePrinter {
- NodePtr N;
- BlockNamePrinter(NodePtr Block) : N(Block) {}
- BlockNamePrinter(TreeNodePtr TN) : N(TN ? TN->getBlock() : nullptr) {}
- friend raw_ostream &operator<<(raw_ostream &O, const BlockNamePrinter &BP) {
- if (!BP.N)
- O << "nullptr";
- else
- BP.N->printAsOperand(O, false);
- return O;
- }
- };
- using NodeOrderMap = DenseMap<NodePtr, unsigned>;
- // Custom DFS implementation which can skip nodes based on a provided
- // predicate. It also collects ReverseChildren so that we don't have to spend
- // time getting predecessors in SemiNCA.
- //
- // If IsReverse is set to true, the DFS walk will be performed backwards
- // relative to IsPostDom -- using reverse edges for dominators and forward
- // edges for postdominators.
- //
- // If SuccOrder is specified then in this order the DFS traverses the children
- // otherwise the order is implied by the results of getChildren().
- template <bool IsReverse = false, typename DescendCondition>
- unsigned runDFS(NodePtr V, unsigned LastNum, DescendCondition Condition,
- unsigned AttachToNum,
- const NodeOrderMap *SuccOrder = nullptr) {
- assert(V);
- SmallVector<NodePtr, 64> WorkList = {V};
- if (NodeToInfo.count(V) != 0) NodeToInfo[V].Parent = AttachToNum;
- while (!WorkList.empty()) {
- const NodePtr BB = WorkList.pop_back_val();
- auto &BBInfo = NodeToInfo[BB];
- // Visited nodes always have positive DFS numbers.
- if (BBInfo.DFSNum != 0) continue;
- BBInfo.DFSNum = BBInfo.Semi = ++LastNum;
- BBInfo.Label = BB;
- NumToNode.push_back(BB);
- constexpr bool Direction = IsReverse != IsPostDom; // XOR.
- auto Successors = getChildren<Direction>(BB, BatchUpdates);
- if (SuccOrder && Successors.size() > 1)
- llvm::sort(
- Successors.begin(), Successors.end(), [=](NodePtr A, NodePtr B) {
- return SuccOrder->find(A)->second < SuccOrder->find(B)->second;
- });
- for (const NodePtr Succ : Successors) {
- const auto SIT = NodeToInfo.find(Succ);
- // Don't visit nodes more than once but remember to collect
- // ReverseChildren.
- if (SIT != NodeToInfo.end() && SIT->second.DFSNum != 0) {
- if (Succ != BB) SIT->second.ReverseChildren.push_back(BB);
- continue;
- }
- if (!Condition(BB, Succ)) continue;
- // It's fine to add Succ to the map, because we know that it will be
- // visited later.
- auto &SuccInfo = NodeToInfo[Succ];
- WorkList.push_back(Succ);
- SuccInfo.Parent = LastNum;
- SuccInfo.ReverseChildren.push_back(BB);
- }
- }
- return LastNum;
- }
- // V is a predecessor of W. eval() returns V if V < W, otherwise the minimum
- // of sdom(U), where U > W and there is a virtual forest path from U to V. The
- // virtual forest consists of linked edges of processed vertices.
- //
- // We can follow Parent pointers (virtual forest edges) to determine the
- // ancestor U with minimum sdom(U). But it is slow and thus we employ the path
- // compression technique to speed up to O(m*log(n)). Theoretically the virtual
- // forest can be organized as balanced trees to achieve almost linear
- // O(m*alpha(m,n)) running time. But it requires two auxiliary arrays (Size
- // and Child) and is unlikely to be faster than the simple implementation.
- //
- // For each vertex V, its Label points to the vertex with the minimal sdom(U)
- // (Semi) in its path from V (included) to NodeToInfo[V].Parent (excluded).
- NodePtr eval(NodePtr V, unsigned LastLinked,
- SmallVectorImpl<InfoRec *> &Stack) {
- InfoRec *VInfo = &NodeToInfo[V];
- if (VInfo->Parent < LastLinked)
- return VInfo->Label;
- // Store ancestors except the last (root of a virtual tree) into a stack.
- assert(Stack.empty());
- do {
- Stack.push_back(VInfo);
- VInfo = &NodeToInfo[NumToNode[VInfo->Parent]];
- } while (VInfo->Parent >= LastLinked);
- // Path compression. Point each vertex's Parent to the root and update its
- // Label if any of its ancestors (PInfo->Label) has a smaller Semi.
- const InfoRec *PInfo = VInfo;
- const InfoRec *PLabelInfo = &NodeToInfo[PInfo->Label];
- do {
- VInfo = Stack.pop_back_val();
- VInfo->Parent = PInfo->Parent;
- const InfoRec *VLabelInfo = &NodeToInfo[VInfo->Label];
- if (PLabelInfo->Semi < VLabelInfo->Semi)
- VInfo->Label = PInfo->Label;
- else
- PLabelInfo = VLabelInfo;
- PInfo = VInfo;
- } while (!Stack.empty());
- return VInfo->Label;
- }
- // This function requires DFS to be run before calling it.
- void runSemiNCA(DomTreeT &DT, const unsigned MinLevel = 0) {
- const unsigned NextDFSNum(NumToNode.size());
- // Initialize IDoms to spanning tree parents.
- for (unsigned i = 1; i < NextDFSNum; ++i) {
- const NodePtr V = NumToNode[i];
- auto &VInfo = NodeToInfo[V];
- VInfo.IDom = NumToNode[VInfo.Parent];
- }
- // Step #1: Calculate the semidominators of all vertices.
- SmallVector<InfoRec *, 32> EvalStack;
- for (unsigned i = NextDFSNum - 1; i >= 2; --i) {
- NodePtr W = NumToNode[i];
- auto &WInfo = NodeToInfo[W];
- // Initialize the semi dominator to point to the parent node.
- WInfo.Semi = WInfo.Parent;
- for (const auto &N : WInfo.ReverseChildren) {
- if (NodeToInfo.count(N) == 0) // Skip unreachable predecessors.
- continue;
- const TreeNodePtr TN = DT.getNode(N);
- // Skip predecessors whose level is above the subtree we are processing.
- if (TN && TN->getLevel() < MinLevel)
- continue;
- unsigned SemiU = NodeToInfo[eval(N, i + 1, EvalStack)].Semi;
- if (SemiU < WInfo.Semi) WInfo.Semi = SemiU;
- }
- }
- // Step #2: Explicitly define the immediate dominator of each vertex.
- // IDom[i] = NCA(SDom[i], SpanningTreeParent(i)).
- // Note that the parents were stored in IDoms and later got invalidated
- // during path compression in Eval.
- for (unsigned i = 2; i < NextDFSNum; ++i) {
- const NodePtr W = NumToNode[i];
- auto &WInfo = NodeToInfo[W];
- const unsigned SDomNum = NodeToInfo[NumToNode[WInfo.Semi]].DFSNum;
- NodePtr WIDomCandidate = WInfo.IDom;
- while (NodeToInfo[WIDomCandidate].DFSNum > SDomNum)
- WIDomCandidate = NodeToInfo[WIDomCandidate].IDom;
- WInfo.IDom = WIDomCandidate;
- }
- }
- // PostDominatorTree always has a virtual root that represents a virtual CFG
- // node that serves as a single exit from the function. All the other exits
- // (CFG nodes with terminators and nodes in infinite loops are logically
- // connected to this virtual CFG exit node).
- // This functions maps a nullptr CFG node to the virtual root tree node.
- void addVirtualRoot() {
- assert(IsPostDom && "Only postdominators have a virtual root");
- assert(NumToNode.size() == 1 && "SNCAInfo must be freshly constructed");
- auto &BBInfo = NodeToInfo[nullptr];
- BBInfo.DFSNum = BBInfo.Semi = 1;
- BBInfo.Label = nullptr;
- NumToNode.push_back(nullptr); // NumToNode[1] = nullptr;
- }
- // For postdominators, nodes with no forward successors are trivial roots that
- // are always selected as tree roots. Roots with forward successors correspond
- // to CFG nodes within infinite loops.
- static bool HasForwardSuccessors(const NodePtr N, BatchUpdatePtr BUI) {
- assert(N && "N must be a valid node");
- return !getChildren<false>(N, BUI).empty();
- }
- static NodePtr GetEntryNode(const DomTreeT &DT) {
- assert(DT.Parent && "Parent not set");
- return GraphTraits<typename DomTreeT::ParentPtr>::getEntryNode(DT.Parent);
- }
- // Finds all roots without relaying on the set of roots already stored in the
- // tree.
- // We define roots to be some non-redundant set of the CFG nodes
- static RootsT FindRoots(const DomTreeT &DT, BatchUpdatePtr BUI) {
- assert(DT.Parent && "Parent pointer is not set");
- RootsT Roots;
- // For dominators, function entry CFG node is always a tree root node.
- if (!IsPostDom) {
- Roots.push_back(GetEntryNode(DT));
- return Roots;
- }
- SemiNCAInfo SNCA(BUI);
- // PostDominatorTree always has a virtual root.
- SNCA.addVirtualRoot();
- unsigned Num = 1;
- LLVM_DEBUG(dbgs() << "\t\tLooking for trivial roots\n");
- // Step #1: Find all the trivial roots that are going to will definitely
- // remain tree roots.
- unsigned Total = 0;
- // It may happen that there are some new nodes in the CFG that are result of
- // the ongoing batch update, but we cannot really pretend that they don't
- // exist -- we won't see any outgoing or incoming edges to them, so it's
- // fine to discover them here, as they would end up appearing in the CFG at
- // some point anyway.
- for (const NodePtr N : nodes(DT.Parent)) {
- ++Total;
- // If it has no *successors*, it is definitely a root.
- if (!HasForwardSuccessors(N, BUI)) {
- Roots.push_back(N);
- // Run DFS not to walk this part of CFG later.
- Num = SNCA.runDFS(N, Num, AlwaysDescend, 1);
- LLVM_DEBUG(dbgs() << "Found a new trivial root: " << BlockNamePrinter(N)
- << "\n");
- LLVM_DEBUG(dbgs() << "Last visited node: "
- << BlockNamePrinter(SNCA.NumToNode[Num]) << "\n");
- }
- }
- LLVM_DEBUG(dbgs() << "\t\tLooking for non-trivial roots\n");
- // Step #2: Find all non-trivial root candidates. Those are CFG nodes that
- // are reverse-unreachable were not visited by previous DFS walks (i.e. CFG
- // nodes in infinite loops).
- bool HasNonTrivialRoots = false;
- // Accounting for the virtual exit, see if we had any reverse-unreachable
- // nodes.
- if (Total + 1 != Num) {
- HasNonTrivialRoots = true;
- // SuccOrder is the order of blocks in the function. It is needed to make
- // the calculation of the FurthestAway node and the whole PostDomTree
- // immune to swap successors transformation (e.g. canonicalizing branch
- // predicates). SuccOrder is initialized lazily only for successors of
- // reverse unreachable nodes.
- std::optional<NodeOrderMap> SuccOrder;
- auto InitSuccOrderOnce = [&]() {
- SuccOrder = NodeOrderMap();
- for (const auto Node : nodes(DT.Parent))
- if (SNCA.NodeToInfo.count(Node) == 0)
- for (const auto Succ : getChildren<false>(Node, SNCA.BatchUpdates))
- SuccOrder->try_emplace(Succ, 0);
- // Add mapping for all entries of SuccOrder.
- unsigned NodeNum = 0;
- for (const auto Node : nodes(DT.Parent)) {
- ++NodeNum;
- auto Order = SuccOrder->find(Node);
- if (Order != SuccOrder->end()) {
- assert(Order->second == 0);
- Order->second = NodeNum;
- }
- }
- };
- // Make another DFS pass over all other nodes to find the
- // reverse-unreachable blocks, and find the furthest paths we'll be able
- // to make.
- // Note that this looks N^2, but it's really 2N worst case, if every node
- // is unreachable. This is because we are still going to only visit each
- // unreachable node once, we may just visit it in two directions,
- // depending on how lucky we get.
- for (const NodePtr I : nodes(DT.Parent)) {
- if (SNCA.NodeToInfo.count(I) == 0) {
- LLVM_DEBUG(dbgs()
- << "\t\t\tVisiting node " << BlockNamePrinter(I) << "\n");
- // Find the furthest away we can get by following successors, then
- // follow them in reverse. This gives us some reasonable answer about
- // the post-dom tree inside any infinite loop. In particular, it
- // guarantees we get to the farthest away point along *some*
- // path. This also matches the GCC's behavior.
- // If we really wanted a totally complete picture of dominance inside
- // this infinite loop, we could do it with SCC-like algorithms to find
- // the lowest and highest points in the infinite loop. In theory, it
- // would be nice to give the canonical backedge for the loop, but it's
- // expensive and does not always lead to a minimal set of roots.
- LLVM_DEBUG(dbgs() << "\t\t\tRunning forward DFS\n");
- if (!SuccOrder)
- InitSuccOrderOnce();
- assert(SuccOrder);
- const unsigned NewNum =
- SNCA.runDFS<true>(I, Num, AlwaysDescend, Num, &*SuccOrder);
- const NodePtr FurthestAway = SNCA.NumToNode[NewNum];
- LLVM_DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
- << "(non-trivial root): "
- << BlockNamePrinter(FurthestAway) << "\n");
- Roots.push_back(FurthestAway);
- LLVM_DEBUG(dbgs() << "\t\t\tPrev DFSNum: " << Num << ", new DFSNum: "
- << NewNum << "\n\t\t\tRemoving DFS info\n");
- for (unsigned i = NewNum; i > Num; --i) {
- const NodePtr N = SNCA.NumToNode[i];
- LLVM_DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
- << BlockNamePrinter(N) << "\n");
- SNCA.NodeToInfo.erase(N);
- SNCA.NumToNode.pop_back();
- }
- const unsigned PrevNum = Num;
- LLVM_DEBUG(dbgs() << "\t\t\tRunning reverse DFS\n");
- Num = SNCA.runDFS(FurthestAway, Num, AlwaysDescend, 1);
- for (unsigned i = PrevNum + 1; i <= Num; ++i)
- LLVM_DEBUG(dbgs() << "\t\t\t\tfound node "
- << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
- }
- }
- }
- LLVM_DEBUG(dbgs() << "Total: " << Total << ", Num: " << Num << "\n");
- LLVM_DEBUG(dbgs() << "Discovered CFG nodes:\n");
- LLVM_DEBUG(for (size_t i = 0; i <= Num; ++i) dbgs()
- << i << ": " << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
- assert((Total + 1 == Num) && "Everything should have been visited");
- // Step #3: If we found some non-trivial roots, make them non-redundant.
- if (HasNonTrivialRoots) RemoveRedundantRoots(DT, BUI, Roots);
- LLVM_DEBUG(dbgs() << "Found roots: ");
- LLVM_DEBUG(for (auto *Root
- : Roots) dbgs()
- << BlockNamePrinter(Root) << " ");
- LLVM_DEBUG(dbgs() << "\n");
- return Roots;
- }
- // This function only makes sense for postdominators.
- // We define roots to be some set of CFG nodes where (reverse) DFS walks have
- // to start in order to visit all the CFG nodes (including the
- // reverse-unreachable ones).
- // When the search for non-trivial roots is done it may happen that some of
- // the non-trivial roots are reverse-reachable from other non-trivial roots,
- // which makes them redundant. This function removes them from the set of
- // input roots.
- static void RemoveRedundantRoots(const DomTreeT &DT, BatchUpdatePtr BUI,
- RootsT &Roots) {
- assert(IsPostDom && "This function is for postdominators only");
- LLVM_DEBUG(dbgs() << "Removing redundant roots\n");
- SemiNCAInfo SNCA(BUI);
- for (unsigned i = 0; i < Roots.size(); ++i) {
- auto &Root = Roots[i];
- // Trivial roots are always non-redundant.
- if (!HasForwardSuccessors(Root, BUI)) continue;
- LLVM_DEBUG(dbgs() << "\tChecking if " << BlockNamePrinter(Root)
- << " remains a root\n");
- SNCA.clear();
- // Do a forward walk looking for the other roots.
- const unsigned Num = SNCA.runDFS<true>(Root, 0, AlwaysDescend, 0);
- // Skip the start node and begin from the second one (note that DFS uses
- // 1-based indexing).
- for (unsigned x = 2; x <= Num; ++x) {
- const NodePtr N = SNCA.NumToNode[x];
- // If we wound another root in a (forward) DFS walk, remove the current
- // root from the set of roots, as it is reverse-reachable from the other
- // one.
- if (llvm::is_contained(Roots, N)) {
- LLVM_DEBUG(dbgs() << "\tForward DFS walk found another root "
- << BlockNamePrinter(N) << "\n\tRemoving root "
- << BlockNamePrinter(Root) << "\n");
- std::swap(Root, Roots.back());
- Roots.pop_back();
- // Root at the back takes the current root's place.
- // Start the next loop iteration with the same index.
- --i;
- break;
- }
- }
- }
- }
- template <typename DescendCondition>
- void doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
- if (!IsPostDom) {
- assert(DT.Roots.size() == 1 && "Dominators should have a singe root");
- runDFS(DT.Roots[0], 0, DC, 0);
- return;
- }
- addVirtualRoot();
- unsigned Num = 1;
- for (const NodePtr Root : DT.Roots) Num = runDFS(Root, Num, DC, 0);
- }
- static void CalculateFromScratch(DomTreeT &DT, BatchUpdatePtr BUI) {
- auto *Parent = DT.Parent;
- DT.reset();
- DT.Parent = Parent;
- // If the update is using the actual CFG, BUI is null. If it's using a view,
- // BUI is non-null and the PreCFGView is used. When calculating from
- // scratch, make the PreViewCFG equal to the PostCFGView, so Post is used.
- BatchUpdatePtr PostViewBUI = nullptr;
- if (BUI && BUI->PostViewCFG) {
- BUI->PreViewCFG = *BUI->PostViewCFG;
- PostViewBUI = BUI;
- }
- // This is rebuilding the whole tree, not incrementally, but PostViewBUI is
- // used in case the caller needs a DT update with a CFGView.
- SemiNCAInfo SNCA(PostViewBUI);
- // Step #0: Number blocks in depth-first order and initialize variables used
- // in later stages of the algorithm.
- DT.Roots = FindRoots(DT, PostViewBUI);
- SNCA.doFullDFSWalk(DT, AlwaysDescend);
- SNCA.runSemiNCA(DT);
- if (BUI) {
- BUI->IsRecalculated = true;
- LLVM_DEBUG(
- dbgs() << "DomTree recalculated, skipping future batch updates\n");
- }
- if (DT.Roots.empty()) return;
- // Add a node for the root. If the tree is a PostDominatorTree it will be
- // the virtual exit (denoted by (BasicBlock *) nullptr) which postdominates
- // all real exits (including multiple exit blocks, infinite loops).
- NodePtr Root = IsPostDom ? nullptr : DT.Roots[0];
- DT.RootNode = DT.createNode(Root);
- SNCA.attachNewSubtree(DT, DT.RootNode);
- }
- void attachNewSubtree(DomTreeT& DT, const TreeNodePtr AttachTo) {
- // Attach the first unreachable block to AttachTo.
- NodeToInfo[NumToNode[1]].IDom = AttachTo->getBlock();
- // Loop over all of the discovered blocks in the function...
- for (size_t i = 1, e = NumToNode.size(); i != e; ++i) {
- NodePtr W = NumToNode[i];
- // Don't replace this with 'count', the insertion side effect is important
- if (DT.DomTreeNodes[W]) continue; // Haven't calculated this node yet?
- NodePtr ImmDom = getIDom(W);
- // Get or calculate the node for the immediate dominator.
- TreeNodePtr IDomNode = getNodeForBlock(ImmDom, DT);
- // Add a new tree node for this BasicBlock, and link it as a child of
- // IDomNode.
- DT.createChild(W, IDomNode);
- }
- }
- void reattachExistingSubtree(DomTreeT &DT, const TreeNodePtr AttachTo) {
- NodeToInfo[NumToNode[1]].IDom = AttachTo->getBlock();
- for (size_t i = 1, e = NumToNode.size(); i != e; ++i) {
- const NodePtr N = NumToNode[i];
- const TreeNodePtr TN = DT.getNode(N);
- assert(TN);
- const TreeNodePtr NewIDom = DT.getNode(NodeToInfo[N].IDom);
- TN->setIDom(NewIDom);
- }
- }
- // Helper struct used during edge insertions.
- struct InsertionInfo {
- struct Compare {
- bool operator()(TreeNodePtr LHS, TreeNodePtr RHS) const {
- return LHS->getLevel() < RHS->getLevel();
- }
- };
- // Bucket queue of tree nodes ordered by descending level. For simplicity,
- // we use a priority_queue here.
- std::priority_queue<TreeNodePtr, SmallVector<TreeNodePtr, 8>,
- Compare>
- Bucket;
- SmallDenseSet<TreeNodePtr, 8> Visited;
- SmallVector<TreeNodePtr, 8> Affected;
- #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
- SmallVector<TreeNodePtr, 8> VisitedUnaffected;
- #endif
- };
- static void InsertEdge(DomTreeT &DT, const BatchUpdatePtr BUI,
- const NodePtr From, const NodePtr To) {
- assert((From || IsPostDom) &&
- "From has to be a valid CFG node or a virtual root");
- assert(To && "Cannot be a nullptr");
- LLVM_DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
- << BlockNamePrinter(To) << "\n");
- TreeNodePtr FromTN = DT.getNode(From);
- if (!FromTN) {
- // Ignore edges from unreachable nodes for (forward) dominators.
- if (!IsPostDom) return;
- // The unreachable node becomes a new root -- a tree node for it.
- TreeNodePtr VirtualRoot = DT.getNode(nullptr);
- FromTN = DT.createChild(From, VirtualRoot);
- DT.Roots.push_back(From);
- }
- DT.DFSInfoValid = false;
- const TreeNodePtr ToTN = DT.getNode(To);
- if (!ToTN)
- InsertUnreachable(DT, BUI, FromTN, To);
- else
- InsertReachable(DT, BUI, FromTN, ToTN);
- }
- // Determines if some existing root becomes reverse-reachable after the
- // insertion. Rebuilds the whole tree if that situation happens.
- static bool UpdateRootsBeforeInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
- const TreeNodePtr From,
- const TreeNodePtr To) {
- assert(IsPostDom && "This function is only for postdominators");
- // Destination node is not attached to the virtual root, so it cannot be a
- // root.
- if (!DT.isVirtualRoot(To->getIDom())) return false;
- if (!llvm::is_contained(DT.Roots, To->getBlock()))
- return false; // To is not a root, nothing to update.
- LLVM_DEBUG(dbgs() << "\t\tAfter the insertion, " << BlockNamePrinter(To)
- << " is no longer a root\n\t\tRebuilding the tree!!!\n");
- CalculateFromScratch(DT, BUI);
- return true;
- }
- static bool isPermutation(const SmallVectorImpl<NodePtr> &A,
- const SmallVectorImpl<NodePtr> &B) {
- if (A.size() != B.size())
- return false;
- SmallPtrSet<NodePtr, 4> Set(A.begin(), A.end());
- for (NodePtr N : B)
- if (Set.count(N) == 0)
- return false;
- return true;
- }
- // Updates the set of roots after insertion or deletion. This ensures that
- // roots are the same when after a series of updates and when the tree would
- // be built from scratch.
- static void UpdateRootsAfterUpdate(DomTreeT &DT, const BatchUpdatePtr BUI) {
- assert(IsPostDom && "This function is only for postdominators");
- // The tree has only trivial roots -- nothing to update.
- if (llvm::none_of(DT.Roots, [BUI](const NodePtr N) {
- return HasForwardSuccessors(N, BUI);
- }))
- return;
- // Recalculate the set of roots.
- RootsT Roots = FindRoots(DT, BUI);
- if (!isPermutation(DT.Roots, Roots)) {
- // The roots chosen in the CFG have changed. This is because the
- // incremental algorithm does not really know or use the set of roots and
- // can make a different (implicit) decision about which node within an
- // infinite loop becomes a root.
- LLVM_DEBUG(dbgs() << "Roots are different in updated trees\n"
- << "The entire tree needs to be rebuilt\n");
- // It may be possible to update the tree without recalculating it, but
- // we do not know yet how to do it, and it happens rarely in practice.
- CalculateFromScratch(DT, BUI);
- }
- }
- // Handles insertion to a node already in the dominator tree.
- static void InsertReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
- const TreeNodePtr From, const TreeNodePtr To) {
- LLVM_DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
- << " -> " << BlockNamePrinter(To->getBlock()) << "\n");
- if (IsPostDom && UpdateRootsBeforeInsertion(DT, BUI, From, To)) return;
- // DT.findNCD expects both pointers to be valid. When From is a virtual
- // root, then its CFG block pointer is a nullptr, so we have to 'compute'
- // the NCD manually.
- const NodePtr NCDBlock =
- (From->getBlock() && To->getBlock())
- ? DT.findNearestCommonDominator(From->getBlock(), To->getBlock())
- : nullptr;
- assert(NCDBlock || DT.isPostDominator());
- const TreeNodePtr NCD = DT.getNode(NCDBlock);
- assert(NCD);
- LLVM_DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n");
- const unsigned NCDLevel = NCD->getLevel();
- // Based on Lemma 2.5 from [2], after insertion of (From,To), v is affected
- // iff depth(NCD)+1 < depth(v) && a path P from To to v exists where every
- // w on P s.t. depth(v) <= depth(w)
- //
- // This reduces to a widest path problem (maximizing the depth of the
- // minimum vertex in the path) which can be solved by a modified version of
- // Dijkstra with a bucket queue (named depth-based search in [2]).
- // To is in the path, so depth(NCD)+1 < depth(v) <= depth(To). Nothing
- // affected if this does not hold.
- if (NCDLevel + 1 >= To->getLevel())
- return;
- InsertionInfo II;
- SmallVector<TreeNodePtr, 8> UnaffectedOnCurrentLevel;
- II.Bucket.push(To);
- II.Visited.insert(To);
- while (!II.Bucket.empty()) {
- TreeNodePtr TN = II.Bucket.top();
- II.Bucket.pop();
- II.Affected.push_back(TN);
- const unsigned CurrentLevel = TN->getLevel();
- LLVM_DEBUG(dbgs() << "Mark " << BlockNamePrinter(TN) <<
- "as affected, CurrentLevel " << CurrentLevel << "\n");
- assert(TN->getBlock() && II.Visited.count(TN) && "Preconditions!");
- while (true) {
- // Unlike regular Dijkstra, we have an inner loop to expand more
- // vertices. The first iteration is for the (affected) vertex popped
- // from II.Bucket and the rest are for vertices in
- // UnaffectedOnCurrentLevel, which may eventually expand to affected
- // vertices.
- //
- // Invariant: there is an optimal path from `To` to TN with the minimum
- // depth being CurrentLevel.
- for (const NodePtr Succ : getChildren<IsPostDom>(TN->getBlock(), BUI)) {
- const TreeNodePtr SuccTN = DT.getNode(Succ);
- assert(SuccTN &&
- "Unreachable successor found at reachable insertion");
- const unsigned SuccLevel = SuccTN->getLevel();
- LLVM_DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
- << ", level = " << SuccLevel << "\n");
- // There is an optimal path from `To` to Succ with the minimum depth
- // being min(CurrentLevel, SuccLevel).
- //
- // If depth(NCD)+1 < depth(Succ) is not satisfied, Succ is unaffected
- // and no affected vertex may be reached by a path passing through it.
- // Stop here. Also, Succ may be visited by other predecessors but the
- // first visit has the optimal path. Stop if Succ has been visited.
- if (SuccLevel <= NCDLevel + 1 || !II.Visited.insert(SuccTN).second)
- continue;
- if (SuccLevel > CurrentLevel) {
- // Succ is unaffected but it may (transitively) expand to affected
- // vertices. Store it in UnaffectedOnCurrentLevel.
- LLVM_DEBUG(dbgs() << "\t\tMarking visited not affected "
- << BlockNamePrinter(Succ) << "\n");
- UnaffectedOnCurrentLevel.push_back(SuccTN);
- #ifndef NDEBUG
- II.VisitedUnaffected.push_back(SuccTN);
- #endif
- } else {
- // The condition is satisfied (Succ is affected). Add Succ to the
- // bucket queue.
- LLVM_DEBUG(dbgs() << "\t\tAdd " << BlockNamePrinter(Succ)
- << " to a Bucket\n");
- II.Bucket.push(SuccTN);
- }
- }
- if (UnaffectedOnCurrentLevel.empty())
- break;
- TN = UnaffectedOnCurrentLevel.pop_back_val();
- LLVM_DEBUG(dbgs() << " Next: " << BlockNamePrinter(TN) << "\n");
- }
- }
- // Finish by updating immediate dominators and levels.
- UpdateInsertion(DT, BUI, NCD, II);
- }
- // Updates immediate dominators and levels after insertion.
- static void UpdateInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
- const TreeNodePtr NCD, InsertionInfo &II) {
- LLVM_DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n");
- for (const TreeNodePtr TN : II.Affected) {
- LLVM_DEBUG(dbgs() << "\tIDom(" << BlockNamePrinter(TN)
- << ") = " << BlockNamePrinter(NCD) << "\n");
- TN->setIDom(NCD);
- }
- #if defined(LLVM_ENABLE_ABI_BREAKING_CHECKS) && !defined(NDEBUG)
- for (const TreeNodePtr TN : II.VisitedUnaffected)
- assert(TN->getLevel() == TN->getIDom()->getLevel() + 1 &&
- "TN should have been updated by an affected ancestor");
- #endif
- if (IsPostDom) UpdateRootsAfterUpdate(DT, BUI);
- }
- // Handles insertion to previously unreachable nodes.
- static void InsertUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
- const TreeNodePtr From, const NodePtr To) {
- LLVM_DEBUG(dbgs() << "Inserting " << BlockNamePrinter(From)
- << " -> (unreachable) " << BlockNamePrinter(To) << "\n");
- // Collect discovered edges to already reachable nodes.
- SmallVector<std::pair<NodePtr, TreeNodePtr>, 8> DiscoveredEdgesToReachable;
- // Discover and connect nodes that became reachable with the insertion.
- ComputeUnreachableDominators(DT, BUI, To, From, DiscoveredEdgesToReachable);
- LLVM_DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From)
- << " -> (prev unreachable) " << BlockNamePrinter(To)
- << "\n");
- // Used the discovered edges and inset discovered connecting (incoming)
- // edges.
- for (const auto &Edge : DiscoveredEdgesToReachable) {
- LLVM_DEBUG(dbgs() << "\tInserting discovered connecting edge "
- << BlockNamePrinter(Edge.first) << " -> "
- << BlockNamePrinter(Edge.second) << "\n");
- InsertReachable(DT, BUI, DT.getNode(Edge.first), Edge.second);
- }
- }
- // Connects nodes that become reachable with an insertion.
- static void ComputeUnreachableDominators(
- DomTreeT &DT, const BatchUpdatePtr BUI, const NodePtr Root,
- const TreeNodePtr Incoming,
- SmallVectorImpl<std::pair<NodePtr, TreeNodePtr>>
- &DiscoveredConnectingEdges) {
- assert(!DT.getNode(Root) && "Root must not be reachable");
- // Visit only previously unreachable nodes.
- auto UnreachableDescender = [&DT, &DiscoveredConnectingEdges](NodePtr From,
- NodePtr To) {
- const TreeNodePtr ToTN = DT.getNode(To);
- if (!ToTN) return true;
- DiscoveredConnectingEdges.push_back({From, ToTN});
- return false;
- };
- SemiNCAInfo SNCA(BUI);
- SNCA.runDFS(Root, 0, UnreachableDescender, 0);
- SNCA.runSemiNCA(DT);
- SNCA.attachNewSubtree(DT, Incoming);
- LLVM_DEBUG(dbgs() << "After adding unreachable nodes\n");
- }
- static void DeleteEdge(DomTreeT &DT, const BatchUpdatePtr BUI,
- const NodePtr From, const NodePtr To) {
- assert(From && To && "Cannot disconnect nullptrs");
- LLVM_DEBUG(dbgs() << "Deleting edge " << BlockNamePrinter(From) << " -> "
- << BlockNamePrinter(To) << "\n");
- #ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
- // Ensure that the edge was in fact deleted from the CFG before informing
- // the DomTree about it.
- // The check is O(N), so run it only in debug configuration.
- auto IsSuccessor = [BUI](const NodePtr SuccCandidate, const NodePtr Of) {
- auto Successors = getChildren<IsPostDom>(Of, BUI);
- return llvm::is_contained(Successors, SuccCandidate);
- };
- (void)IsSuccessor;
- assert(!IsSuccessor(To, From) && "Deleted edge still exists in the CFG!");
- #endif
- const TreeNodePtr FromTN = DT.getNode(From);
- // Deletion in an unreachable subtree -- nothing to do.
- if (!FromTN) return;
- const TreeNodePtr ToTN = DT.getNode(To);
- if (!ToTN) {
- LLVM_DEBUG(
- dbgs() << "\tTo (" << BlockNamePrinter(To)
- << ") already unreachable -- there is no edge to delete\n");
- return;
- }
- const NodePtr NCDBlock = DT.findNearestCommonDominator(From, To);
- const TreeNodePtr NCD = DT.getNode(NCDBlock);
- // If To dominates From -- nothing to do.
- if (ToTN != NCD) {
- DT.DFSInfoValid = false;
- const TreeNodePtr ToIDom = ToTN->getIDom();
- LLVM_DEBUG(dbgs() << "\tNCD " << BlockNamePrinter(NCD) << ", ToIDom "
- << BlockNamePrinter(ToIDom) << "\n");
- // To remains reachable after deletion.
- // (Based on the caption under Figure 4. from [2].)
- if (FromTN != ToIDom || HasProperSupport(DT, BUI, ToTN))
- DeleteReachable(DT, BUI, FromTN, ToTN);
- else
- DeleteUnreachable(DT, BUI, ToTN);
- }
- if (IsPostDom) UpdateRootsAfterUpdate(DT, BUI);
- }
- // Handles deletions that leave destination nodes reachable.
- static void DeleteReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
- const TreeNodePtr FromTN,
- const TreeNodePtr ToTN) {
- LLVM_DEBUG(dbgs() << "Deleting reachable " << BlockNamePrinter(FromTN)
- << " -> " << BlockNamePrinter(ToTN) << "\n");
- LLVM_DEBUG(dbgs() << "\tRebuilding subtree\n");
- // Find the top of the subtree that needs to be rebuilt.
- // (Based on the lemma 2.6 from [2].)
- const NodePtr ToIDom =
- DT.findNearestCommonDominator(FromTN->getBlock(), ToTN->getBlock());
- assert(ToIDom || DT.isPostDominator());
- const TreeNodePtr ToIDomTN = DT.getNode(ToIDom);
- assert(ToIDomTN);
- const TreeNodePtr PrevIDomSubTree = ToIDomTN->getIDom();
- // Top of the subtree to rebuild is the root node. Rebuild the tree from
- // scratch.
- if (!PrevIDomSubTree) {
- LLVM_DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
- CalculateFromScratch(DT, BUI);
- return;
- }
- // Only visit nodes in the subtree starting at To.
- const unsigned Level = ToIDomTN->getLevel();
- auto DescendBelow = [Level, &DT](NodePtr, NodePtr To) {
- return DT.getNode(To)->getLevel() > Level;
- };
- LLVM_DEBUG(dbgs() << "\tTop of subtree: " << BlockNamePrinter(ToIDomTN)
- << "\n");
- SemiNCAInfo SNCA(BUI);
- SNCA.runDFS(ToIDom, 0, DescendBelow, 0);
- LLVM_DEBUG(dbgs() << "\tRunning Semi-NCA\n");
- SNCA.runSemiNCA(DT, Level);
- SNCA.reattachExistingSubtree(DT, PrevIDomSubTree);
- }
- // Checks if a node has proper support, as defined on the page 3 and later
- // explained on the page 7 of [2].
- static bool HasProperSupport(DomTreeT &DT, const BatchUpdatePtr BUI,
- const TreeNodePtr TN) {
- LLVM_DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN)
- << "\n");
- auto TNB = TN->getBlock();
- for (const NodePtr Pred : getChildren<!IsPostDom>(TNB, BUI)) {
- LLVM_DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n");
- if (!DT.getNode(Pred)) continue;
- const NodePtr Support = DT.findNearestCommonDominator(TNB, Pred);
- LLVM_DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n");
- if (Support != TNB) {
- LLVM_DEBUG(dbgs() << "\t" << BlockNamePrinter(TN)
- << " is reachable from support "
- << BlockNamePrinter(Support) << "\n");
- return true;
- }
- }
- return false;
- }
- // Handle deletions that make destination node unreachable.
- // (Based on the lemma 2.7 from the [2].)
- static void DeleteUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
- const TreeNodePtr ToTN) {
- LLVM_DEBUG(dbgs() << "Deleting unreachable subtree "
- << BlockNamePrinter(ToTN) << "\n");
- assert(ToTN);
- assert(ToTN->getBlock());
- if (IsPostDom) {
- // Deletion makes a region reverse-unreachable and creates a new root.
- // Simulate that by inserting an edge from the virtual root to ToTN and
- // adding it as a new root.
- LLVM_DEBUG(dbgs() << "\tDeletion made a region reverse-unreachable\n");
- LLVM_DEBUG(dbgs() << "\tAdding new root " << BlockNamePrinter(ToTN)
- << "\n");
- DT.Roots.push_back(ToTN->getBlock());
- InsertReachable(DT, BUI, DT.getNode(nullptr), ToTN);
- return;
- }
- SmallVector<NodePtr, 16> AffectedQueue;
- const unsigned Level = ToTN->getLevel();
- // Traverse destination node's descendants with greater level in the tree
- // and collect visited nodes.
- auto DescendAndCollect = [Level, &AffectedQueue, &DT](NodePtr, NodePtr To) {
- const TreeNodePtr TN = DT.getNode(To);
- assert(TN);
- if (TN->getLevel() > Level) return true;
- if (!llvm::is_contained(AffectedQueue, To))
- AffectedQueue.push_back(To);
- return false;
- };
- SemiNCAInfo SNCA(BUI);
- unsigned LastDFSNum =
- SNCA.runDFS(ToTN->getBlock(), 0, DescendAndCollect, 0);
- TreeNodePtr MinNode = ToTN;
- // Identify the top of the subtree to rebuild by finding the NCD of all
- // the affected nodes.
- for (const NodePtr N : AffectedQueue) {
- const TreeNodePtr TN = DT.getNode(N);
- const NodePtr NCDBlock =
- DT.findNearestCommonDominator(TN->getBlock(), ToTN->getBlock());
- assert(NCDBlock || DT.isPostDominator());
- const TreeNodePtr NCD = DT.getNode(NCDBlock);
- assert(NCD);
- LLVM_DEBUG(dbgs() << "Processing affected node " << BlockNamePrinter(TN)
- << " with NCD = " << BlockNamePrinter(NCD)
- << ", MinNode =" << BlockNamePrinter(MinNode) << "\n");
- if (NCD != TN && NCD->getLevel() < MinNode->getLevel()) MinNode = NCD;
- }
- // Root reached, rebuild the whole tree from scratch.
- if (!MinNode->getIDom()) {
- LLVM_DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
- CalculateFromScratch(DT, BUI);
- return;
- }
- // Erase the unreachable subtree in reverse preorder to process all children
- // before deleting their parent.
- for (unsigned i = LastDFSNum; i > 0; --i) {
- const NodePtr N = SNCA.NumToNode[i];
- const TreeNodePtr TN = DT.getNode(N);
- LLVM_DEBUG(dbgs() << "Erasing node " << BlockNamePrinter(TN) << "\n");
- EraseNode(DT, TN);
- }
- // The affected subtree start at the To node -- there's no extra work to do.
- if (MinNode == ToTN) return;
- LLVM_DEBUG(dbgs() << "DeleteUnreachable: running DFS with MinNode = "
- << BlockNamePrinter(MinNode) << "\n");
- const unsigned MinLevel = MinNode->getLevel();
- const TreeNodePtr PrevIDom = MinNode->getIDom();
- assert(PrevIDom);
- SNCA.clear();
- // Identify nodes that remain in the affected subtree.
- auto DescendBelow = [MinLevel, &DT](NodePtr, NodePtr To) {
- const TreeNodePtr ToTN = DT.getNode(To);
- return ToTN && ToTN->getLevel() > MinLevel;
- };
- SNCA.runDFS(MinNode->getBlock(), 0, DescendBelow, 0);
- LLVM_DEBUG(dbgs() << "Previous IDom(MinNode) = "
- << BlockNamePrinter(PrevIDom) << "\nRunning Semi-NCA\n");
- // Rebuild the remaining part of affected subtree.
- SNCA.runSemiNCA(DT, MinLevel);
- SNCA.reattachExistingSubtree(DT, PrevIDom);
- }
- // Removes leaf tree nodes from the dominator tree.
- static void EraseNode(DomTreeT &DT, const TreeNodePtr TN) {
- assert(TN);
- assert(TN->getNumChildren() == 0 && "Not a tree leaf");
- const TreeNodePtr IDom = TN->getIDom();
- assert(IDom);
- auto ChIt = llvm::find(IDom->Children, TN);
- assert(ChIt != IDom->Children.end());
- std::swap(*ChIt, IDom->Children.back());
- IDom->Children.pop_back();
- DT.DomTreeNodes.erase(TN->getBlock());
- }
- //~~
- //===--------------------- DomTree Batch Updater --------------------------===
- //~~
- static void ApplyUpdates(DomTreeT &DT, GraphDiffT &PreViewCFG,
- GraphDiffT *PostViewCFG) {
- // Note: the PostViewCFG is only used when computing from scratch. It's data
- // should already included in the PreViewCFG for incremental updates.
- const size_t NumUpdates = PreViewCFG.getNumLegalizedUpdates();
- if (NumUpdates == 0)
- return;
- // Take the fast path for a single update and avoid running the batch update
- // machinery.
- if (NumUpdates == 1) {
- UpdateT Update = PreViewCFG.popUpdateForIncrementalUpdates();
- if (!PostViewCFG) {
- if (Update.getKind() == UpdateKind::Insert)
- InsertEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
- else
- DeleteEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
- } else {
- BatchUpdateInfo BUI(*PostViewCFG, PostViewCFG);
- if (Update.getKind() == UpdateKind::Insert)
- InsertEdge(DT, &BUI, Update.getFrom(), Update.getTo());
- else
- DeleteEdge(DT, &BUI, Update.getFrom(), Update.getTo());
- }
- return;
- }
- BatchUpdateInfo BUI(PreViewCFG, PostViewCFG);
- // Recalculate the DominatorTree when the number of updates
- // exceeds a threshold, which usually makes direct updating slower than
- // recalculation. We select this threshold proportional to the
- // size of the DominatorTree. The constant is selected
- // by choosing the one with an acceptable performance on some real-world
- // inputs.
- // Make unittests of the incremental algorithm work
- if (DT.DomTreeNodes.size() <= 100) {
- if (BUI.NumLegalized > DT.DomTreeNodes.size())
- CalculateFromScratch(DT, &BUI);
- } else if (BUI.NumLegalized > DT.DomTreeNodes.size() / 40)
- CalculateFromScratch(DT, &BUI);
- // If the DominatorTree was recalculated at some point, stop the batch
- // updates. Full recalculations ignore batch updates and look at the actual
- // CFG.
- for (size_t i = 0; i < BUI.NumLegalized && !BUI.IsRecalculated; ++i)
- ApplyNextUpdate(DT, BUI);
- }
- static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) {
- // Popping the next update, will move the PreViewCFG to the next snapshot.
- UpdateT CurrentUpdate = BUI.PreViewCFG.popUpdateForIncrementalUpdates();
- #if 0
- // FIXME: The LLVM_DEBUG macro only plays well with a modular
- // build of LLVM when the header is marked as textual, but doing
- // so causes redefinition errors.
- LLVM_DEBUG(dbgs() << "Applying update: ");
- LLVM_DEBUG(CurrentUpdate.dump(); dbgs() << "\n");
- #endif
- if (CurrentUpdate.getKind() == UpdateKind::Insert)
- InsertEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
- else
- DeleteEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
- }
- //~~
- //===--------------- DomTree correctness verification ---------------------===
- //~~
- // Check if the tree has correct roots. A DominatorTree always has a single
- // root which is the function's entry node. A PostDominatorTree can have
- // multiple roots - one for each node with no successors and for infinite
- // loops.
- // Running time: O(N).
- bool verifyRoots(const DomTreeT &DT) {
- if (!DT.Parent && !DT.Roots.empty()) {
- errs() << "Tree has no parent but has roots!\n";
- errs().flush();
- return false;
- }
- if (!IsPostDom) {
- if (DT.Roots.empty()) {
- errs() << "Tree doesn't have a root!\n";
- errs().flush();
- return false;
- }
- if (DT.getRoot() != GetEntryNode(DT)) {
- errs() << "Tree's root is not its parent's entry node!\n";
- errs().flush();
- return false;
- }
- }
- RootsT ComputedRoots = FindRoots(DT, nullptr);
- if (!isPermutation(DT.Roots, ComputedRoots)) {
- errs() << "Tree has different roots than freshly computed ones!\n";
- errs() << "\tPDT roots: ";
- for (const NodePtr N : DT.Roots) errs() << BlockNamePrinter(N) << ", ";
- errs() << "\n\tComputed roots: ";
- for (const NodePtr N : ComputedRoots)
- errs() << BlockNamePrinter(N) << ", ";
- errs() << "\n";
- errs().flush();
- return false;
- }
- return true;
- }
- // Checks if the tree contains all reachable nodes in the input graph.
- // Running time: O(N).
- bool verifyReachability(const DomTreeT &DT) {
- clear();
- doFullDFSWalk(DT, AlwaysDescend);
- for (auto &NodeToTN : DT.DomTreeNodes) {
- const TreeNodePtr TN = NodeToTN.second.get();
- const NodePtr BB = TN->getBlock();
- // Virtual root has a corresponding virtual CFG node.
- if (DT.isVirtualRoot(TN)) continue;
- if (NodeToInfo.count(BB) == 0) {
- errs() << "DomTree node " << BlockNamePrinter(BB)
- << " not found by DFS walk!\n";
- errs().flush();
- return false;
- }
- }
- for (const NodePtr N : NumToNode) {
- if (N && !DT.getNode(N)) {
- errs() << "CFG node " << BlockNamePrinter(N)
- << " not found in the DomTree!\n";
- errs().flush();
- return false;
- }
- }
- return true;
- }
- // Check if for every parent with a level L in the tree all of its children
- // have level L + 1.
- // Running time: O(N).
- static bool VerifyLevels(const DomTreeT &DT) {
- for (auto &NodeToTN : DT.DomTreeNodes) {
- const TreeNodePtr TN = NodeToTN.second.get();
- const NodePtr BB = TN->getBlock();
- if (!BB) continue;
- const TreeNodePtr IDom = TN->getIDom();
- if (!IDom && TN->getLevel() != 0) {
- errs() << "Node without an IDom " << BlockNamePrinter(BB)
- << " has a nonzero level " << TN->getLevel() << "!\n";
- errs().flush();
- return false;
- }
- if (IDom && TN->getLevel() != IDom->getLevel() + 1) {
- errs() << "Node " << BlockNamePrinter(BB) << " has level "
- << TN->getLevel() << " while its IDom "
- << BlockNamePrinter(IDom->getBlock()) << " has level "
- << IDom->getLevel() << "!\n";
- errs().flush();
- return false;
- }
- }
- return true;
- }
- // Check if the computed DFS numbers are correct. Note that DFS info may not
- // be valid, and when that is the case, we don't verify the numbers.
- // Running time: O(N log(N)).
- static bool VerifyDFSNumbers(const DomTreeT &DT) {
- if (!DT.DFSInfoValid || !DT.Parent)
- return true;
- const NodePtr RootBB = IsPostDom ? nullptr : *DT.root_begin();
- const TreeNodePtr Root = DT.getNode(RootBB);
- auto PrintNodeAndDFSNums = [](const TreeNodePtr TN) {
- errs() << BlockNamePrinter(TN) << " {" << TN->getDFSNumIn() << ", "
- << TN->getDFSNumOut() << '}';
- };
- // Verify the root's DFS In number. Although DFS numbering would also work
- // if we started from some other value, we assume 0-based numbering.
- if (Root->getDFSNumIn() != 0) {
- errs() << "DFSIn number for the tree root is not:\n\t";
- PrintNodeAndDFSNums(Root);
- errs() << '\n';
- errs().flush();
- return false;
- }
- // For each tree node verify if children's DFS numbers cover their parent's
- // DFS numbers with no gaps.
- for (const auto &NodeToTN : DT.DomTreeNodes) {
- const TreeNodePtr Node = NodeToTN.second.get();
- // Handle tree leaves.
- if (Node->isLeaf()) {
- if (Node->getDFSNumIn() + 1 != Node->getDFSNumOut()) {
- errs() << "Tree leaf should have DFSOut = DFSIn + 1:\n\t";
- PrintNodeAndDFSNums(Node);
- errs() << '\n';
- errs().flush();
- return false;
- }
- continue;
- }
- // Make a copy and sort it such that it is possible to check if there are
- // no gaps between DFS numbers of adjacent children.
- SmallVector<TreeNodePtr, 8> Children(Node->begin(), Node->end());
- llvm::sort(Children, [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) {
- return Ch1->getDFSNumIn() < Ch2->getDFSNumIn();
- });
- auto PrintChildrenError = [Node, &Children, PrintNodeAndDFSNums](
- const TreeNodePtr FirstCh, const TreeNodePtr SecondCh) {
- assert(FirstCh);
- errs() << "Incorrect DFS numbers for:\n\tParent ";
- PrintNodeAndDFSNums(Node);
- errs() << "\n\tChild ";
- PrintNodeAndDFSNums(FirstCh);
- if (SecondCh) {
- errs() << "\n\tSecond child ";
- PrintNodeAndDFSNums(SecondCh);
- }
- errs() << "\nAll children: ";
- for (const TreeNodePtr Ch : Children) {
- PrintNodeAndDFSNums(Ch);
- errs() << ", ";
- }
- errs() << '\n';
- errs().flush();
- };
- if (Children.front()->getDFSNumIn() != Node->getDFSNumIn() + 1) {
- PrintChildrenError(Children.front(), nullptr);
- return false;
- }
- if (Children.back()->getDFSNumOut() + 1 != Node->getDFSNumOut()) {
- PrintChildrenError(Children.back(), nullptr);
- return false;
- }
- for (size_t i = 0, e = Children.size() - 1; i != e; ++i) {
- if (Children[i]->getDFSNumOut() + 1 != Children[i + 1]->getDFSNumIn()) {
- PrintChildrenError(Children[i], Children[i + 1]);
- return false;
- }
- }
- }
- return true;
- }
- // The below routines verify the correctness of the dominator tree relative to
- // the CFG it's coming from. A tree is a dominator tree iff it has two
- // properties, called the parent property and the sibling property. Tarjan
- // and Lengauer prove (but don't explicitly name) the properties as part of
- // the proofs in their 1972 paper, but the proofs are mostly part of proving
- // things about semidominators and idoms, and some of them are simply asserted
- // based on even earlier papers (see, e.g., lemma 2). Some papers refer to
- // these properties as "valid" and "co-valid". See, e.g., "Dominators,
- // directed bipolar orders, and independent spanning trees" by Loukas
- // Georgiadis and Robert E. Tarjan, as well as "Dominator Tree Verification
- // and Vertex-Disjoint Paths " by the same authors.
- // A very simple and direct explanation of these properties can be found in
- // "An Experimental Study of Dynamic Dominators", found at
- // https://arxiv.org/abs/1604.02711
- // The easiest way to think of the parent property is that it's a requirement
- // of being a dominator. Let's just take immediate dominators. For PARENT to
- // be an immediate dominator of CHILD, all paths in the CFG must go through
- // PARENT before they hit CHILD. This implies that if you were to cut PARENT
- // out of the CFG, there should be no paths to CHILD that are reachable. If
- // there are, then you now have a path from PARENT to CHILD that goes around
- // PARENT and still reaches CHILD, which by definition, means PARENT can't be
- // a dominator of CHILD (let alone an immediate one).
- // The sibling property is similar. It says that for each pair of sibling
- // nodes in the dominator tree (LEFT and RIGHT) , they must not dominate each
- // other. If sibling LEFT dominated sibling RIGHT, it means there are no
- // paths in the CFG from sibling LEFT to sibling RIGHT that do not go through
- // LEFT, and thus, LEFT is really an ancestor (in the dominator tree) of
- // RIGHT, not a sibling.
- // It is possible to verify the parent and sibling properties in linear time,
- // but the algorithms are complex. Instead, we do it in a straightforward
- // N^2 and N^3 way below, using direct path reachability.
- // Checks if the tree has the parent property: if for all edges from V to W in
- // the input graph, such that V is reachable, the parent of W in the tree is
- // an ancestor of V in the tree.
- // Running time: O(N^2).
- //
- // This means that if a node gets disconnected from the graph, then all of
- // the nodes it dominated previously will now become unreachable.
- bool verifyParentProperty(const DomTreeT &DT) {
- for (auto &NodeToTN : DT.DomTreeNodes) {
- const TreeNodePtr TN = NodeToTN.second.get();
- const NodePtr BB = TN->getBlock();
- if (!BB || TN->isLeaf())
- continue;
- LLVM_DEBUG(dbgs() << "Verifying parent property of node "
- << BlockNamePrinter(TN) << "\n");
- clear();
- doFullDFSWalk(DT, [BB](NodePtr From, NodePtr To) {
- return From != BB && To != BB;
- });
- for (TreeNodePtr Child : TN->children())
- if (NodeToInfo.count(Child->getBlock()) != 0) {
- errs() << "Child " << BlockNamePrinter(Child)
- << " reachable after its parent " << BlockNamePrinter(BB)
- << " is removed!\n";
- errs().flush();
- return false;
- }
- }
- return true;
- }
- // Check if the tree has sibling property: if a node V does not dominate a
- // node W for all siblings V and W in the tree.
- // Running time: O(N^3).
- //
- // This means that if a node gets disconnected from the graph, then all of its
- // siblings will now still be reachable.
- bool verifySiblingProperty(const DomTreeT &DT) {
- for (auto &NodeToTN : DT.DomTreeNodes) {
- const TreeNodePtr TN = NodeToTN.second.get();
- const NodePtr BB = TN->getBlock();
- if (!BB || TN->isLeaf())
- continue;
- for (const TreeNodePtr N : TN->children()) {
- clear();
- NodePtr BBN = N->getBlock();
- doFullDFSWalk(DT, [BBN](NodePtr From, NodePtr To) {
- return From != BBN && To != BBN;
- });
- for (const TreeNodePtr S : TN->children()) {
- if (S == N) continue;
- if (NodeToInfo.count(S->getBlock()) == 0) {
- errs() << "Node " << BlockNamePrinter(S)
- << " not reachable when its sibling " << BlockNamePrinter(N)
- << " is removed!\n";
- errs().flush();
- return false;
- }
- }
- }
- }
- return true;
- }
- // Check if the given tree is the same as a freshly computed one for the same
- // Parent.
- // Running time: O(N^2), but faster in practice (same as tree construction).
- //
- // Note that this does not check if that the tree construction algorithm is
- // correct and should be only used for fast (but possibly unsound)
- // verification.
- static bool IsSameAsFreshTree(const DomTreeT &DT) {
- DomTreeT FreshTree;
- FreshTree.recalculate(*DT.Parent);
- const bool Different = DT.compare(FreshTree);
- if (Different) {
- errs() << (DT.isPostDominator() ? "Post" : "")
- << "DominatorTree is different than a freshly computed one!\n"
- << "\tCurrent:\n";
- DT.print(errs());
- errs() << "\n\tFreshly computed tree:\n";
- FreshTree.print(errs());
- errs().flush();
- }
- return !Different;
- }
- };
- template <class DomTreeT>
- void Calculate(DomTreeT &DT) {
- SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, nullptr);
- }
- template <typename DomTreeT>
- void CalculateWithUpdates(DomTreeT &DT,
- ArrayRef<typename DomTreeT::UpdateType> Updates) {
- // FIXME: Updated to use the PreViewCFG and behave the same as until now.
- // This behavior is however incorrect; this actually needs the PostViewCFG.
- GraphDiff<typename DomTreeT::NodePtr, DomTreeT::IsPostDominator> PreViewCFG(
- Updates, /*ReverseApplyUpdates=*/true);
- typename SemiNCAInfo<DomTreeT>::BatchUpdateInfo BUI(PreViewCFG);
- SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, &BUI);
- }
- template <class DomTreeT>
- void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
- typename DomTreeT::NodePtr To) {
- if (DT.isPostDominator()) std::swap(From, To);
- SemiNCAInfo<DomTreeT>::InsertEdge(DT, nullptr, From, To);
- }
- template <class DomTreeT>
- void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
- typename DomTreeT::NodePtr To) {
- if (DT.isPostDominator()) std::swap(From, To);
- SemiNCAInfo<DomTreeT>::DeleteEdge(DT, nullptr, From, To);
- }
- template <class DomTreeT>
- void ApplyUpdates(DomTreeT &DT,
- GraphDiff<typename DomTreeT::NodePtr,
- DomTreeT::IsPostDominator> &PreViewCFG,
- GraphDiff<typename DomTreeT::NodePtr,
- DomTreeT::IsPostDominator> *PostViewCFG) {
- SemiNCAInfo<DomTreeT>::ApplyUpdates(DT, PreViewCFG, PostViewCFG);
- }
- template <class DomTreeT>
- bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL) {
- SemiNCAInfo<DomTreeT> SNCA(nullptr);
- // Simplist check is to compare against a new tree. This will also
- // usefully print the old and new trees, if they are different.
- if (!SNCA.IsSameAsFreshTree(DT))
- return false;
- // Common checks to verify the properties of the tree. O(N log N) at worst.
- if (!SNCA.verifyRoots(DT) || !SNCA.verifyReachability(DT) ||
- !SNCA.VerifyLevels(DT) || !SNCA.VerifyDFSNumbers(DT))
- return false;
- // Extra checks depending on VerificationLevel. Up to O(N^3).
- if (VL == DomTreeT::VerificationLevel::Basic ||
- VL == DomTreeT::VerificationLevel::Full)
- if (!SNCA.verifyParentProperty(DT))
- return false;
- if (VL == DomTreeT::VerificationLevel::Full)
- if (!SNCA.verifySiblingProperty(DT))
- return false;
- return true;
- }
- } // namespace DomTreeBuilder
- } // namespace llvm
- #undef DEBUG_TYPE
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|