diff options
Diffstat (limited to 'include/llvm/Support/GenericDomTreeConstruction.h')
| -rw-r--r-- | include/llvm/Support/GenericDomTreeConstruction.h | 670 | 
1 files changed, 565 insertions, 105 deletions
diff --git a/include/llvm/Support/GenericDomTreeConstruction.h b/include/llvm/Support/GenericDomTreeConstruction.h index a0fec668e05c..be90afa4c3c8 100644 --- a/include/llvm/Support/GenericDomTreeConstruction.h +++ b/include/llvm/Support/GenericDomTreeConstruction.h @@ -20,15 +20,28 @@  /// out that the theoretically slower O(n*log(n)) implementation is actually  /// faster than the almost-linear O(n*alpha(n)) version, even for large CFGs.  /// +/// The file uses the Depth Based Search algorithm to perform incremental +/// upates (insertion and deletions). The implemented algorithm is based on this +/// publication: +/// +///   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 <queue> +#include "llvm/ADT/DenseSet.h"  #include "llvm/ADT/DepthFirstIterator.h"  #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Debug.h"  #include "llvm/Support/GenericDomTree.h" +#define DEBUG_TYPE "dom-tree-builder" +  namespace llvm {  namespace DomTreeBuilder { @@ -46,13 +59,14 @@ struct ChildrenGetter<NodePtr, true> {    }  }; -// Information record used by Semi-NCA during tree construction. -template <typename NodeT> +template <typename DomTreeT>  struct SemiNCAInfo { -  using NodePtr = NodeT *; -  using DomTreeT = DominatorTreeBase<NodeT>; +  using NodePtr = typename DomTreeT::NodePtr; +  using NodeT = typename DomTreeT::NodeType;    using TreeNodePtr = DomTreeNodeBase<NodeT> *; +  static constexpr bool IsPostDom = DomTreeT::IsPostDominator; +  // Information record used by Semi-NCA during tree construction.    struct InfoRec {      unsigned DFSNum = 0;      unsigned Parent = 0; @@ -62,11 +76,13 @@ struct SemiNCAInfo {      SmallVector<NodePtr, 2> ReverseChildren;    }; -  std::vector<NodePtr> NumToNode; +  // 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;    void clear() { -    NumToNode.clear(); +    NumToNode = {nullptr}; // Restore to initial state with a dummy start node.      NodeToInfo.clear();    } @@ -90,12 +106,28 @@ struct SemiNCAInfo {      // Add a new tree node for this NodeT, and link it as a child of      // IDomNode      return (DT.DomTreeNodes[BB] = IDomNode->addChild( -                llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))) +        llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode)))          .get();    }    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; +    } +  }; +    // 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. @@ -177,44 +209,42 @@ struct SemiNCAInfo {      return VInInfo.Label;    } -  template <typename NodeType> -  void runSemiNCA(DomTreeT &DT, unsigned NumBlocks) { -    // Step #1: Number blocks in depth-first order and initialize variables used -    // in later stages of the algorithm. -    const unsigned N = doFullDFSWalk(DT, AlwaysDescend); - -    // It might be that some blocks did not get a DFS number (e.g., blocks of -    // infinite loops). In these cases an artificial exit node is required. -    const bool MultipleRoots = -        DT.Roots.size() > 1 || (DT.isPostDominator() && N != NumBlocks); - +  // 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 <= N; ++i) { +    for (unsigned i = 1; i < NextDFSNum; ++i) {        const NodePtr V = NumToNode[i];        auto &VInfo = NodeToInfo[V];        VInfo.IDom = NumToNode[VInfo.Parent];      } -    // Step #2: Calculate the semidominators of all vertices. -    for (unsigned i = N; i >= 2; --i) { +    // Step #1: Calculate the semidominators of all vertices. +    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)) {  // Only if this predecessor is reachable! -          unsigned SemiU = NodeToInfo[eval(N, i + 1)].Semi; -          if (SemiU < WInfo.Semi) -            WInfo.Semi = SemiU; -        } +      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)].Semi; +        if (SemiU < WInfo.Semi) WInfo.Semi = SemiU; +      }      } -    // Step #3: Explicitly define the immediate dominator of each vertex. +    // 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 <= N; ++i) { +    for (unsigned i = 2; i < NextDFSNum; ++i) {        const NodePtr W = NumToNode[i];        auto &WInfo = NodeToInfo[W];        const unsigned SDomNum = NodeToInfo[NumToNode[WInfo.Semi]].DFSNum; @@ -224,6 +254,36 @@ struct SemiNCAInfo {        WInfo.IDom = WIDomCandidate;      } +  } + +  template <typename DescendCondition> +  unsigned doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) { +    unsigned Num = 0; + +    if (DT.Roots.size() > 1) { +      auto &BBInfo = NodeToInfo[nullptr]; +      BBInfo.DFSNum = BBInfo.Semi = ++Num; +      BBInfo.Label = nullptr; + +      NumToNode.push_back(nullptr);  // NumToNode[n] = V; +    } + +    if (DT.isPostDominator()) { +      for (auto *Root : DT.Roots) Num = runDFS<true>(Root, Num, DC, 1); +    } else { +      assert(DT.Roots.size() == 1); +      Num = runDFS<false>(DT.Roots[0], Num, DC, Num); +    } + +    return Num; +  } + +  void calculateFromScratch(DomTreeT &DT, const unsigned NumBlocks) { +    // Step #0: Number blocks in depth-first order and initialize variables used +    // in later stages of the algorithm. +    const unsigned LastDFSNum = doFullDFSWalk(DT, AlwaysDescend); + +    runSemiNCA(DT);      if (DT.Roots.empty()) return; @@ -231,25 +291,32 @@ struct SemiNCAInfo {      // one exit block, or it may be the virtual exit (denoted by      // (BasicBlock *)0) which postdominates all real exits if there are multiple      // exit blocks, or an infinite loop. +    // It might be that some blocks did not get a DFS number (e.g., blocks of +    // infinite loops). In these cases an artificial exit node is required. +    const bool MultipleRoots = DT.Roots.size() > 1 || (DT.isPostDominator() && +                                                       LastDFSNum != NumBlocks);      NodePtr Root = !MultipleRoots ? DT.Roots[0] : nullptr; -    DT.RootNode = -        (DT.DomTreeNodes[Root] = -             llvm::make_unique<DomTreeNodeBase<NodeT>>(Root, nullptr)) -            .get(); +    DT.RootNode = (DT.DomTreeNodes[Root] = +                       llvm::make_unique<DomTreeNodeBase<NodeT>>(Root, nullptr)) +        .get(); +    attachNewSubtree(DT, DT.RootNode); +  } -    // Loop over all of the reachable blocks in the function... -    for (unsigned i = 2; i <= N; ++i) { +  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]; +      DEBUG(dbgs() << "\tdiscovered a new reachable node " +                   << BlockNamePrinter(W) << "\n");        // Don't replace this with 'count', the insertion side effect is important -      if (DT.DomTreeNodes[W]) -        continue; // Haven't calculated this node yet? +      if (DT.DomTreeNodes[W]) continue;  // Haven't calculated this node yet?        NodePtr ImmDom = getIDom(W); -      assert(ImmDom || DT.DomTreeNodes[nullptr]); -        // Get or calculate the node for the immediate dominator        TreeNodePtr IDomNode = getNodeForBlock(ImmDom, DT); @@ -260,34 +327,208 @@ struct SemiNCAInfo {      }    } -  template <typename DescendCondition> -  unsigned doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) { -    unsigned Num = 0; -    NumToNode.push_back(nullptr); +  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); +    } +  } -    if (DT.Roots.size() > 1) { -      auto &BBInfo = NodeToInfo[nullptr]; -      BBInfo.DFSNum = BBInfo.Semi = ++Num; -      BBInfo.Label = nullptr; +  // Helper struct used during edge insertions. +  struct InsertionInfo { +    using BucketElementTy = std::pair<unsigned, TreeNodePtr>; +    struct DecreasingLevel { +      bool operator()(const BucketElementTy &First, +                      const BucketElementTy &Second) const { +        return First.first > Second.first; +      } +    }; + +    std::priority_queue<BucketElementTy, SmallVector<BucketElementTy, 8>, +        DecreasingLevel> +        Bucket;  // Queue of tree nodes sorted by level in descending order. +    SmallDenseSet<TreeNodePtr, 8> Affected; +    SmallDenseSet<TreeNodePtr, 8> Visited; +    SmallVector<TreeNodePtr, 8> AffectedQueue; +    SmallVector<TreeNodePtr, 8> VisitedNotAffectedQueue; +  }; -      NumToNode.push_back(nullptr);  // NumToNode[n] = V; +  static void InsertEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) { +    assert(From && To && "Cannot connect nullptrs"); +    DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> " +                 << BlockNamePrinter(To) << "\n"); +    const TreeNodePtr FromTN = DT.getNode(From); + +    // Ignore edges from unreachable nodes. +    if (!FromTN) return; + +    DT.DFSInfoValid = false; + +    const TreeNodePtr ToTN = DT.getNode(To); +    if (!ToTN) +      InsertUnreachable(DT, FromTN, To); +    else +      InsertReachable(DT, FromTN, ToTN); +  } + +  // Handles insertion to a node already in the dominator tree. +  static void InsertReachable(DomTreeT &DT, const TreeNodePtr From, +                              const TreeNodePtr To) { +    DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock()) +                 << " -> " << BlockNamePrinter(To->getBlock()) << "\n"); +    const NodePtr NCDBlock = +        DT.findNearestCommonDominator(From->getBlock(), To->getBlock()); +    assert(NCDBlock || DT.isPostDominator()); +    const TreeNodePtr NCD = DT.getNode(NCDBlock); +    assert(NCD); + +    DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n"); +    const TreeNodePtr ToIDom = To->getIDom(); + +    // Nothing affected -- NCA property holds. +    // (Based on the lemma 2.5 from the second paper.) +    if (NCD == To || NCD == ToIDom) return; + +    // Identify and collect affected nodes. +    InsertionInfo II; +    DEBUG(dbgs() << "Marking " << BlockNamePrinter(To) << " as affected\n"); +    II.Affected.insert(To); +    const unsigned ToLevel = To->getLevel(); +    DEBUG(dbgs() << "Putting " << BlockNamePrinter(To) << " into a Bucket\n"); +    II.Bucket.push({ToLevel, To}); + +    while (!II.Bucket.empty()) { +      const TreeNodePtr CurrentNode = II.Bucket.top().second; +      II.Bucket.pop(); +      DEBUG(dbgs() << "\tAdding to Visited and AffectedQueue: " +                   << BlockNamePrinter(CurrentNode) << "\n"); +      II.Visited.insert(CurrentNode); +      II.AffectedQueue.push_back(CurrentNode); + +      // Discover and collect affected successors of the current node. +      VisitInsertion(DT, CurrentNode, CurrentNode->getLevel(), NCD, II);      } -    if (DT.isPostDominator()) { -      for (auto *Root : DT.Roots) Num = runDFS<true>(Root, Num, DC, 1); -    } else { -      assert(DT.Roots.size() == 1); -      Num = runDFS<false>(DT.Roots[0], Num, DC, Num); +    // Finish by updating immediate dominators and levels. +    UpdateInsertion(DT, NCD, II); +  } + +  // Visits an affected node and collect its affected successors. +  static void VisitInsertion(DomTreeT &DT, const TreeNodePtr TN, +                             const unsigned RootLevel, const TreeNodePtr NCD, +                             InsertionInfo &II) { +    const unsigned NCDLevel = NCD->getLevel(); +    DEBUG(dbgs() << "Visiting " << BlockNamePrinter(TN) << "\n"); + +    assert(TN->getBlock()); +    for (const NodePtr Succ : +        ChildrenGetter<NodePtr, IsPostDom>::Get(TN->getBlock())) { +      const TreeNodePtr SuccTN = DT.getNode(Succ); +      assert(SuccTN && "Unreachable successor found at reachable insertion"); +      const unsigned SuccLevel = SuccTN->getLevel(); + +      DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ) +                   << ", level = " << SuccLevel << "\n"); + +      // Succ dominated by subtree From -- not affected. +      // (Based on the lemma 2.5 from the second paper.) +      if (SuccLevel > RootLevel) { +        DEBUG(dbgs() << "\t\tDominated by subtree From\n"); +        if (II.Visited.count(SuccTN) != 0) continue; + +        DEBUG(dbgs() << "\t\tMarking visited not affected " +                     << BlockNamePrinter(Succ) << "\n"); +        II.Visited.insert(SuccTN); +        II.VisitedNotAffectedQueue.push_back(SuccTN); +        VisitInsertion(DT, SuccTN, RootLevel, NCD, II); +      } else if ((SuccLevel > NCDLevel + 1) && II.Affected.count(SuccTN) == 0) { +        DEBUG(dbgs() << "\t\tMarking affected and adding " +                     << BlockNamePrinter(Succ) << " to a Bucket\n"); +        II.Affected.insert(SuccTN); +        II.Bucket.push({SuccLevel, SuccTN}); +      }      } +  } -    return Num; +  // Updates immediate dominators and levels after insertion. +  static void UpdateInsertion(DomTreeT &DT, const TreeNodePtr NCD, +                              InsertionInfo &II) { +    DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n"); + +    for (const TreeNodePtr TN : II.AffectedQueue) { +      DEBUG(dbgs() << "\tIDom(" << BlockNamePrinter(TN) +                   << ") = " << BlockNamePrinter(NCD) << "\n"); +      TN->setIDom(NCD); +    } + +    UpdateLevelsAfterInsertion(II);    } -  static void PrintBlockOrNullptr(raw_ostream &O, NodePtr Obj) { -    if (!Obj) -      O << "nullptr"; -    else -      Obj->printAsOperand(O, false); +  static void UpdateLevelsAfterInsertion(InsertionInfo &II) { +    DEBUG(dbgs() << "Updating levels for visited but not affected nodes\n"); + +    for (const TreeNodePtr TN : II.VisitedNotAffectedQueue) { +      DEBUG(dbgs() << "\tlevel(" << BlockNamePrinter(TN) << ") = (" +                   << BlockNamePrinter(TN->getIDom()) << ") " +                   << TN->getIDom()->getLevel() << " + 1\n"); +      TN->UpdateLevel(); +    } +  } + +  // Handles insertion to previously unreachable nodes. +  static void InsertUnreachable(DomTreeT &DT, const TreeNodePtr From, +                                const NodePtr To) { +    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, To, From, DiscoveredEdgesToReachable); + +    DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From) +                 << " -> (prev unreachable) " << BlockNamePrinter(To) << "\n"); + +    DEBUG(DT.print(dbgs())); + +    // Used the discovered edges and inset discovered connecting (incoming) +    // edges. +    for (const auto &Edge : DiscoveredEdgesToReachable) { +      DEBUG(dbgs() << "\tInserting discovered connecting edge " +                   << BlockNamePrinter(Edge.first) << " -> " +                   << BlockNamePrinter(Edge.second) << "\n"); +      InsertReachable(DT, DT.getNode(Edge.first), Edge.second); +    } +  } + +  // Connects nodes that become reachable with an insertion. +  static void ComputeUnreachableDominators( +      DomTreeT &DT, 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; +    SNCA.runDFS<IsPostDom>(Root, 0, UnreachableDescender, 0); +    SNCA.runSemiNCA(DT); +    SNCA.attachNewSubtree(DT, Incoming); + +    DEBUG(dbgs() << "After adding unreachable nodes\n"); +    DEBUG(DT.print(dbgs()));    }    // Checks if the tree contains all reachable nodes in the input graph. @@ -298,12 +539,23 @@ struct SemiNCAInfo {      for (auto &NodeToTN : DT.DomTreeNodes) {        const TreeNodePtr TN = NodeToTN.second.get();        const NodePtr BB = TN->getBlock(); -      if (!BB) continue; + +      // Virtual root has a corresponding virtual CFG node. +      if (DT.isVirtualRoot(TN)) continue;        if (NodeToInfo.count(BB) == 0) { -        errs() << "DomTree node "; -        PrintBlockOrNullptr(errs(), BB); -        errs() << " not found by DFS walk!\n"; +        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; @@ -313,6 +565,215 @@ struct SemiNCAInfo {      return true;    } +  static void DeleteEdge(DomTreeT &DT, const NodePtr From, const NodePtr To) { +    assert(From && To && "Cannot disconnect nullptrs"); +    DEBUG(dbgs() << "Deleting edge " << BlockNamePrinter(From) << " -> " +                 << BlockNamePrinter(To) << "\n"); + +#ifndef NDEBUG +    // 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 = [](const NodePtr SuccCandidate, const NodePtr Of) { +      auto Successors = ChildrenGetter<NodePtr, IsPostDom>::Get(Of); +      return llvm::find(Successors, SuccCandidate) != Successors.end(); +    }; +    (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); +    assert(ToTN && "To already unreachable -- there is no edge to delete"); +    const NodePtr NCDBlock = DT.findNearestCommonDominator(From, To); +    const TreeNodePtr NCD = DT.getNode(NCDBlock); + +    // To dominates From -- nothing to do. +    if (ToTN == NCD) return; + +    const TreeNodePtr ToIDom = ToTN->getIDom(); +    DEBUG(dbgs() << "\tNCD " << BlockNamePrinter(NCD) << ", ToIDom " +                 << BlockNamePrinter(ToIDom) << "\n"); + +    // To remains reachable after deletion. +    // (Based on the caption under Figure 4. from the second paper.) +    if (FromTN != ToIDom || HasProperSupport(DT, ToTN)) +      DeleteReachable(DT, FromTN, ToTN); +    else +      DeleteUnreachable(DT, ToTN); +  } + +  // Handles deletions that leave destination nodes reachable. +  static void DeleteReachable(DomTreeT &DT, const TreeNodePtr FromTN, +                              const TreeNodePtr ToTN) { +    DEBUG(dbgs() << "Deleting reachable " << BlockNamePrinter(FromTN) << " -> " +                 << BlockNamePrinter(ToTN) << "\n"); +    DEBUG(dbgs() << "\tRebuilding subtree\n"); + +    // Find the top of the subtree that needs to be rebuilt. +    // (Based on the lemma 2.6 from the second paper.) +    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) { +      DEBUG(dbgs() << "The entire tree needs to be rebuilt\n"); +      DT.recalculate(*DT.Parent); +      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; +    }; + +    DEBUG(dbgs() << "\tTop of subtree: " << BlockNamePrinter(ToIDomTN) << "\n"); + +    SemiNCAInfo SNCA; +    SNCA.runDFS<IsPostDom>(ToIDom, 0, DescendBelow, 0); +    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 the second paper. +  static bool HasProperSupport(DomTreeT &DT, const TreeNodePtr TN) { +    DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN) << "\n"); +    for (const NodePtr Pred : +        ChildrenGetter<NodePtr, !IsPostDom>::Get(TN->getBlock())) { +      DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n"); +      if (!DT.getNode(Pred)) continue; + +      const NodePtr Support = +          DT.findNearestCommonDominator(TN->getBlock(), Pred); +      DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n"); +      if (Support != TN->getBlock()) { +        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 second paper.) +  static void DeleteUnreachable(DomTreeT &DT, const TreeNodePtr ToTN) { +    DEBUG(dbgs() << "Deleting unreachable subtree " << BlockNamePrinter(ToTN) +                 << "\n"); +    assert(ToTN); +    assert(ToTN->getBlock()); + +    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::find(AffectedQueue, To) == AffectedQueue.end()) +        AffectedQueue.push_back(To); + +      return false; +    }; + +    SemiNCAInfo SNCA; +    unsigned LastDFSNum = +        SNCA.runDFS<IsPostDom>(ToTN->getBlock(), 0, DescendAndCollect, 0); + +    TreeNodePtr MinNode = ToTN; + +    // Identify the top of the subtree to rebuilt 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); + +      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()) { +      DEBUG(dbgs() << "The entire tree needs to be rebuilt\n"); +      DT.recalculate(*DT.Parent); +      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); +      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; + +    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<IsPostDom>(MinNode->getBlock(), 0, DescendBelow, 0); + +    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 correctness verification ---------------------=== +  //~~ +    // Check if for every parent with a level L in the tree all of its children    // have level L + 1.    static bool VerifyLevels(const DomTreeT &DT) { @@ -323,20 +784,18 @@ struct SemiNCAInfo {        const TreeNodePtr IDom = TN->getIDom();        if (!IDom && TN->getLevel() != 0) { -        errs() << "Node without an IDom "; -        PrintBlockOrNullptr(errs(), BB); -        errs() << " has a nonzero level " << TN->getLevel() << "!\n"; +        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 "; -        PrintBlockOrNullptr(errs(), BB); -        errs() << " has level " << TN->getLevel() << " while it's IDom "; -        PrintBlockOrNullptr(errs(), IDom->getBlock()); -        errs() << " has level " << IDom->getLevel() << "!\n"; +        errs() << "Node " << BlockNamePrinter(BB) << " has level " +               << TN->getLevel() << " while its IDom " +               << BlockNamePrinter(IDom->getBlock()) << " has level " +               << IDom->getLevel() << "!\n";          errs().flush();          return false; @@ -363,18 +822,14 @@ struct SemiNCAInfo {        assert(ToTN);        const NodePtr NCD = DT.findNearestCommonDominator(From, To); -      const TreeNodePtr NCDTN = NCD ? DT.getNode(NCD) : nullptr; +      const TreeNodePtr NCDTN = DT.getNode(NCD);        const TreeNodePtr ToIDom = ToTN->getIDom();        if (NCDTN != ToTN && NCDTN != ToIDom) { -        errs() << "NearestCommonDominator verification failed:\n\tNCD(From:"; -        PrintBlockOrNullptr(errs(), From); -        errs() << ", To:"; -        PrintBlockOrNullptr(errs(), To); -        errs() << ") = "; -        PrintBlockOrNullptr(errs(), NCD); -        errs() << ",\t (should be To or IDom[To]: "; -        PrintBlockOrNullptr(errs(), ToIDom ? ToIDom->getBlock() : nullptr); -        errs() << ")\n"; +        errs() << "NearestCommonDominator verification failed:\n\tNCD(From:" +               << BlockNamePrinter(From) << ", To:" << BlockNamePrinter(To) +               << ") = " << BlockNamePrinter(NCD) +               << ",\t (should be To or IDom[To]: " << BlockNamePrinter(ToIDom) +               << ")\n";          errs().flush();          return false; @@ -440,11 +895,9 @@ struct SemiNCAInfo {        for (TreeNodePtr Child : TN->getChildren())          if (NodeToInfo.count(Child->getBlock()) != 0) { -          errs() << "Child "; -          PrintBlockOrNullptr(errs(), Child->getBlock()); -          errs() << " reachable after its parent "; -          PrintBlockOrNullptr(errs(), BB); -          errs() << " is removed!\n"; +          errs() << "Child " << BlockNamePrinter(Child) +                 << " reachable after its parent " << BlockNamePrinter(BB) +                 << " is removed!\n";            errs().flush();            return false; @@ -477,11 +930,9 @@ struct SemiNCAInfo {            if (S == N) continue;            if (NodeToInfo.count(S->getBlock()) == 0) { -            errs() << "Node "; -            PrintBlockOrNullptr(errs(), S->getBlock()); -            errs() << " not reachable when its sibling "; -            PrintBlockOrNullptr(errs(), N->getBlock()); -            errs() << " is removed!\n"; +            errs() << "Node " << BlockNamePrinter(S) +                   << " not reachable when its sibling " << BlockNamePrinter(N) +                   << " is removed!\n";              errs().flush();              return false; @@ -494,23 +945,30 @@ struct SemiNCAInfo {    }  }; -template <class FuncT, class NodeT> -void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT, -               FuncT &F) { -  using NodePtr = typename GraphTraits<NodeT>::NodeRef; -  static_assert(std::is_pointer<NodePtr>::value, -                "NodePtr should be a pointer type"); -  SemiNCAInfo<typename std::remove_pointer<NodePtr>::type> SNCA; -  SNCA.template runSemiNCA<NodeT>(DT, GraphTraits<FuncT *>::size(&F)); + +template <class DomTreeT, class FuncT> +void Calculate(DomTreeT &DT, FuncT &F) { +  SemiNCAInfo<DomTreeT> SNCA; +  SNCA.calculateFromScratch(DT, GraphTraits<FuncT *>::size(&F));  } -template <class NodeT> -bool Verify(const DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT) { -  using NodePtr = typename GraphTraits<NodeT>::NodeRef; -  static_assert(std::is_pointer<NodePtr>::value, -                "NodePtr should be a pointer type"); -  SemiNCAInfo<typename std::remove_pointer<NodePtr>::type> SNCA; +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, 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, From, To); +} +template <class DomTreeT> +bool Verify(const DomTreeT &DT) { +  SemiNCAInfo<DomTreeT> SNCA;    return SNCA.verifyReachability(DT) && SNCA.VerifyLevels(DT) &&           SNCA.verifyNCD(DT) && SNCA.verifyParentProperty(DT) &&           SNCA.verifySiblingProperty(DT); @@ -519,4 +977,6 @@ bool Verify(const DominatorTreeBaseByGraphTraits<GraphTraits<NodeT>> &DT) {  }  // namespace DomTreeBuilder  }  // namespace llvm +#undef DEBUG_TYPE +  #endif  | 
