diff options
Diffstat (limited to 'include/llvm/Support/GenericDomTree.h')
| -rw-r--r-- | include/llvm/Support/GenericDomTree.h | 444 | 
1 files changed, 190 insertions, 254 deletions
| diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h index 601633d41cff5..394a45387d8ac 100644 --- a/include/llvm/Support/GenericDomTree.h +++ b/include/llvm/Support/GenericDomTree.h @@ -58,40 +58,6 @@ template <typename GT>  using DominatorTreeBaseByGraphTraits =      typename detail::DominatorTreeBaseTraits<GT>::type; -/// \brief Base class that other, more interesting dominator analyses -/// inherit from. -template <class NodeT> class DominatorBase { -protected: -  std::vector<NodeT *> Roots; -  bool IsPostDominators; - -  explicit DominatorBase(bool isPostDom) -      : Roots(), IsPostDominators(isPostDom) {} - -  DominatorBase(DominatorBase &&Arg) -      : Roots(std::move(Arg.Roots)), IsPostDominators(Arg.IsPostDominators) { -    Arg.Roots.clear(); -  } - -  DominatorBase &operator=(DominatorBase &&RHS) { -    Roots = std::move(RHS.Roots); -    IsPostDominators = RHS.IsPostDominators; -    RHS.Roots.clear(); -    return *this; -  } - -public: -  /// getRoots - Return the root blocks of the current CFG.  This may include -  /// multiple blocks if we are computing post dominators.  For forward -  /// dominators, this will always be a single block (the entry node). -  /// -  const std::vector<NodeT *> &getRoots() const { return Roots; } - -  /// isPostDominator - Returns true if analysis based of postdoms -  /// -  bool isPostDominator() const { return IsPostDominators; } -}; -  /// \brief Base class for the actual dominator tree node.  template <class NodeT> class DomTreeNodeBase {    friend struct PostDominatorTree; @@ -99,12 +65,14 @@ template <class NodeT> class DomTreeNodeBase {    NodeT *TheBB;    DomTreeNodeBase *IDom; +  unsigned Level;    std::vector<DomTreeNodeBase *> Children;    mutable unsigned DFSNumIn = ~0;    mutable unsigned DFSNumOut = ~0;   public: -  DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom) : TheBB(BB), IDom(iDom) {} +  DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom) +      : TheBB(BB), IDom(iDom), Level(IDom ? IDom->Level + 1 : 0) {}    using iterator = typename std::vector<DomTreeNodeBase *>::iterator;    using const_iterator = @@ -117,6 +85,7 @@ template <class NodeT> class DomTreeNodeBase {    NodeT *getBlock() const { return TheBB; }    DomTreeNodeBase *getIDom() const { return IDom; } +  unsigned getLevel() const { return Level; }    const std::vector<DomTreeNodeBase *> &getChildren() const { return Children; } @@ -134,6 +103,8 @@ template <class NodeT> class DomTreeNodeBase {      if (getNumChildren() != Other->getNumChildren())        return true; +    if (Level != Other->Level) return true; +      SmallPtrSet<const NodeT *, 4> OtherChildren;      for (const DomTreeNodeBase *I : *Other) {        const NodeT *Nd = I->getBlock(); @@ -150,18 +121,19 @@ template <class NodeT> class DomTreeNodeBase {    void setIDom(DomTreeNodeBase *NewIDom) {      assert(IDom && "No immediate dominator?"); -    if (IDom != NewIDom) { -      typename std::vector<DomTreeNodeBase *>::iterator I = -          find(IDom->Children, this); -      assert(I != IDom->Children.end() && -             "Not in immediate dominator children set!"); -      // I am no longer your child... -      IDom->Children.erase(I); +    if (IDom == NewIDom) return; -      // Switch to new dominator -      IDom = NewIDom; -      IDom->Children.push_back(this); -    } +    auto I = find(IDom->Children, this); +    assert(I != IDom->Children.end() && +           "Not in immediate dominator children set!"); +    // I am no longer your child... +    IDom->Children.erase(I); + +    // Switch to new dominator +    IDom = NewIDom; +    IDom->Children.push_back(this); + +    UpdateLevel();    }    /// getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes @@ -177,6 +149,23 @@ private:      return this->DFSNumIn >= other->DFSNumIn &&             this->DFSNumOut <= other->DFSNumOut;    } + +  void UpdateLevel() { +    assert(IDom); +    if (Level == IDom->Level + 1) return; + +    SmallVector<DomTreeNodeBase *, 64> WorkStack = {this}; + +    while (!WorkStack.empty()) { +      DomTreeNodeBase *Current = WorkStack.pop_back_val(); +      Current->Level = Current->IDom->Level + 1; + +      for (DomTreeNodeBase *C : *Current) { +        assert(C->IDom); +        if (C->Level != C->IDom->Level + 1) WorkStack.push_back(C); +      } +    } +  }  };  template <class NodeT> @@ -186,9 +175,10 @@ raw_ostream &operator<<(raw_ostream &O, const DomTreeNodeBase<NodeT> *Node) {    else      O << " <<exit node>>"; -  O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "}"; +  O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "} [" +    << Node->getLevel() << "]\n"; -  return O << "\n"; +  return O;  }  template <class NodeT> @@ -201,40 +191,28 @@ void PrintDomTree(const DomTreeNodeBase<NodeT> *N, raw_ostream &O,      PrintDomTree<NodeT>(*I, O, Lev + 1);  } +namespace DomTreeBuilder { +template <class NodeT> +struct SemiNCAInfo; +  // The calculate routine is provided in a separate header but referenced here.  template <class FuncT, class N>  void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<N>> &DT, FuncT &F); +// The verify function is provided in a separate header but referenced here. +template <class N> +bool Verify(const DominatorTreeBaseByGraphTraits<GraphTraits<N>> &DT); +}  // namespace DomTreeBuilder +  /// \brief Core dominator tree base class.  ///  /// This class is a generic template over graph nodes. It is instantiated for  /// various graphs in the LLVM IR or in the code generator. -template <class NodeT> class DominatorTreeBase : public DominatorBase<NodeT> { -  bool dominatedBySlowTreeWalk(const DomTreeNodeBase<NodeT> *A, -                               const DomTreeNodeBase<NodeT> *B) const { -    assert(A != B); -    assert(isReachableFromEntry(B)); -    assert(isReachableFromEntry(A)); - -    const DomTreeNodeBase<NodeT> *IDom; -    while ((IDom = B->getIDom()) != nullptr && IDom != A && IDom != B) -      B = IDom; // Walk up the tree -    return IDom != nullptr; -  } - -  /// \brief Wipe this tree's state without releasing any resources. -  /// -  /// This is essentially a post-move helper only. It leaves the object in an -  /// assignable and destroyable state, but otherwise invalid. -  void wipe() { -    DomTreeNodes.clear(); -    IDoms.clear(); -    Vertex.clear(); -    Info.clear(); -    RootNode = nullptr; -  } +template <class NodeT> class DominatorTreeBase { + protected: +  std::vector<NodeT *> Roots; +  bool IsPostDominators; -protected:    using DomTreeNodeMapType =       DenseMap<NodeT *, std::unique_ptr<DomTreeNodeBase<NodeT>>>;    DomTreeNodeMapType DomTreeNodes; @@ -242,117 +220,30 @@ protected:    mutable bool DFSInfoValid = false;    mutable unsigned int SlowQueries = 0; -  // Information record used during immediate dominators computation. -  struct InfoRec { -    unsigned DFSNum = 0; -    unsigned Parent = 0; -    unsigned Semi = 0; -    NodeT *Label = nullptr; - -    InfoRec() = default; -  }; -  DenseMap<NodeT *, NodeT *> IDoms; +  friend struct DomTreeBuilder::SemiNCAInfo<NodeT>; +  using SNCAInfoTy = DomTreeBuilder::SemiNCAInfo<NodeT>; -  // Vertex - Map the DFS number to the NodeT* -  std::vector<NodeT *> Vertex; - -  // Info - Collection of information used during the computation of idoms. -  DenseMap<NodeT *, InfoRec> Info; - -  void reset() { -    DomTreeNodes.clear(); -    IDoms.clear(); -    this->Roots.clear(); -    Vertex.clear(); -    RootNode = nullptr; -    DFSInfoValid = false; -    SlowQueries = 0; -  } - -  // NewBB is split and now it has one successor. Update dominator tree to -  // reflect this change. -  template <class N> -  void Split(typename GraphTraits<N>::NodeRef NewBB) { -    using GraphT = GraphTraits<N>; -    using NodeRef = typename GraphT::NodeRef; -    assert(std::distance(GraphT::child_begin(NewBB), -                         GraphT::child_end(NewBB)) == 1 && -           "NewBB should have a single successor!"); -    NodeRef NewBBSucc = *GraphT::child_begin(NewBB); - -    std::vector<NodeRef> PredBlocks; -    for (const auto &Pred : children<Inverse<N>>(NewBB)) -      PredBlocks.push_back(Pred); - -    assert(!PredBlocks.empty() && "No predblocks?"); - -    bool NewBBDominatesNewBBSucc = true; -    for (const auto &Pred : children<Inverse<N>>(NewBBSucc)) { -      if (Pred != NewBB && !dominates(NewBBSucc, Pred) && -          isReachableFromEntry(Pred)) { -        NewBBDominatesNewBBSucc = false; -        break; -      } -    } - -    // Find NewBB's immediate dominator and create new dominator tree node for -    // NewBB. -    NodeT *NewBBIDom = nullptr; -    unsigned i = 0; -    for (i = 0; i < PredBlocks.size(); ++i) -      if (isReachableFromEntry(PredBlocks[i])) { -        NewBBIDom = PredBlocks[i]; -        break; -      } - -    // It's possible that none of the predecessors of NewBB are reachable; -    // in that case, NewBB itself is unreachable, so nothing needs to be -    // changed. -    if (!NewBBIDom) -      return; - -    for (i = i + 1; i < PredBlocks.size(); ++i) { -      if (isReachableFromEntry(PredBlocks[i])) -        NewBBIDom = findNearestCommonDominator(NewBBIDom, PredBlocks[i]); -    } - -    // Create the new dominator tree node... and set the idom of NewBB. -    DomTreeNodeBase<NodeT> *NewBBNode = addNewBlock(NewBB, NewBBIDom); - -    // If NewBB strictly dominates other blocks, then it is now the immediate -    // dominator of NewBBSucc.  Update the dominator tree as appropriate. -    if (NewBBDominatesNewBBSucc) { -      DomTreeNodeBase<NodeT> *NewBBSuccNode = getNode(NewBBSucc); -      changeImmediateDominator(NewBBSuccNode, NewBBNode); -    } -  } - -public: -  explicit DominatorTreeBase(bool isPostDom) -      : DominatorBase<NodeT>(isPostDom) {} + public: +  explicit DominatorTreeBase(bool isPostDom) : IsPostDominators(isPostDom) {}    DominatorTreeBase(DominatorTreeBase &&Arg) -      : DominatorBase<NodeT>( -            std::move(static_cast<DominatorBase<NodeT> &>(Arg))), +      : Roots(std::move(Arg.Roots)), +        IsPostDominators(Arg.IsPostDominators),          DomTreeNodes(std::move(Arg.DomTreeNodes)),          RootNode(std::move(Arg.RootNode)),          DFSInfoValid(std::move(Arg.DFSInfoValid)), -        SlowQueries(std::move(Arg.SlowQueries)), IDoms(std::move(Arg.IDoms)), -        Vertex(std::move(Arg.Vertex)), Info(std::move(Arg.Info)) { +        SlowQueries(std::move(Arg.SlowQueries)) {      Arg.wipe();    }    DominatorTreeBase &operator=(DominatorTreeBase &&RHS) { -    DominatorBase<NodeT>::operator=( -        std::move(static_cast<DominatorBase<NodeT> &>(RHS))); +    Roots = std::move(RHS.Roots); +    IsPostDominators = RHS.IsPostDominators;      DomTreeNodes = std::move(RHS.DomTreeNodes);      RootNode = std::move(RHS.RootNode);      DFSInfoValid = std::move(RHS.DFSInfoValid);      SlowQueries = std::move(RHS.SlowQueries); -    IDoms = std::move(RHS.IDoms); -    Vertex = std::move(RHS.Vertex); -    Info = std::move(RHS.Info);      RHS.wipe();      return *this;    } @@ -360,6 +251,16 @@ public:    DominatorTreeBase(const DominatorTreeBase &) = delete;    DominatorTreeBase &operator=(const DominatorTreeBase &) = delete; +  /// getRoots - Return the root blocks of the current CFG.  This may include +  /// multiple blocks if we are computing post dominators.  For forward +  /// dominators, this will always be a single block (the entry node). +  /// +  const std::vector<NodeT *> &getRoots() const { return Roots; } + +  /// isPostDominator - Returns true if analysis based of postdoms +  /// +  bool isPostDominator() const { return IsPostDominators; } +    /// compare - Return false if the other dominator tree base matches this    /// dominator tree base. Otherwise return true.    bool compare(const DominatorTreeBase &Other) const { @@ -468,6 +369,13 @@ public:      if (!isReachableFromEntry(A))        return false; +    if (B->getIDom() == A) return true; + +    if (A->getIDom() == B) return false; + +    // A can only dominate B if it is higher in the tree. +    if (A->getLevel() >= B->getLevel()) return false; +      // Compare the result of the tree walk and the dfs numbers, if expensive      // checks are enabled.  #ifdef EXPENSIVE_CHECKS @@ -499,7 +407,7 @@ public:    /// findNearestCommonDominator - Find nearest common dominator basic block    /// for basic block A and B. If there is no such block then return NULL. -  NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) { +  NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) const {      assert(A->getParent() == B->getParent() &&             "Two blocks are not in same function"); @@ -511,54 +419,24 @@ public:          return &Entry;      } -    // If B dominates A then B is nearest common dominator. -    if (dominates(B, A)) -      return B; - -    // If A dominates B then A is nearest common dominator. -    if (dominates(A, B)) -      return A; -      DomTreeNodeBase<NodeT> *NodeA = getNode(A);      DomTreeNodeBase<NodeT> *NodeB = getNode(B); -    // If we have DFS info, then we can avoid all allocations by just querying -    // it from each IDom. Note that because we call 'dominates' twice above, we -    // expect to call through this code at most 16 times in a row without -    // building valid DFS information. This is important as below is a *very* -    // slow tree walk. -    if (DFSInfoValid) { -      DomTreeNodeBase<NodeT> *IDomA = NodeA->getIDom(); -      while (IDomA) { -        if (NodeB->DominatedBy(IDomA)) -          return IDomA->getBlock(); -        IDomA = IDomA->getIDom(); -      } -      return nullptr; -    } - -    // Collect NodeA dominators set. -    SmallPtrSet<DomTreeNodeBase<NodeT> *, 16> NodeADoms; -    NodeADoms.insert(NodeA); -    DomTreeNodeBase<NodeT> *IDomA = NodeA->getIDom(); -    while (IDomA) { -      NodeADoms.insert(IDomA); -      IDomA = IDomA->getIDom(); -    } +    if (!NodeA || !NodeB) return nullptr; -    // Walk NodeB immediate dominators chain and find common dominator node. -    DomTreeNodeBase<NodeT> *IDomB = NodeB->getIDom(); -    while (IDomB) { -      if (NodeADoms.count(IDomB) != 0) -        return IDomB->getBlock(); +    // Use level information to go up the tree until the levels match. Then +    // continue going up til we arrive at the same node. +    while (NodeA && NodeA != NodeB) { +      if (NodeA->getLevel() < NodeB->getLevel()) std::swap(NodeA, NodeB); -      IDomB = IDomB->getIDom(); +      NodeA = NodeA->IDom;      } -    return nullptr; +    return NodeA ? NodeA->getBlock() : nullptr;    } -  const NodeT *findNearestCommonDominator(const NodeT *A, const NodeT *B) { +  const NodeT *findNearestCommonDominator(const NodeT *A, +                                          const NodeT *B) const {      // Cast away the const qualifiers here. This is ok since      // const is re-introduced on the return type.      return findNearestCommonDominator(const_cast<NodeT *>(A), @@ -597,7 +475,6 @@ public:      assert(!this->isPostDominator() &&             "Cannot change root of post-dominator tree");      DFSInfoValid = false; -    auto &Roots = DominatorBase<NodeT>::Roots;      DomTreeNodeBase<NodeT> *NewNode = (DomTreeNodes[BB] =        llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, nullptr)).get();      if (Roots.empty()) { @@ -605,8 +482,10 @@ public:      } else {        assert(Roots.size() == 1);        NodeT *OldRoot = Roots.front(); -      DomTreeNodes[OldRoot] = -        NewNode->addChild(std::move(DomTreeNodes[OldRoot])); +      auto &OldNode = DomTreeNodes[OldRoot]; +      OldNode = NewNode->addChild(std::move(DomTreeNodes[OldRoot])); +      OldNode->IDom = NewNode; +      OldNode->UpdateLevel();        Roots[0] = BB;      }      return RootNode = NewNode; @@ -673,45 +552,6 @@ public:      if (getRootNode()) PrintDomTree<NodeT>(getRootNode(), O, 1);    } -protected: -  template <class GraphT> -  friend typename GraphT::NodeRef -  Eval(DominatorTreeBaseByGraphTraits<GraphT> &DT, typename GraphT::NodeRef V, -       unsigned LastLinked); - -  template <class GraphT> -  friend unsigned ReverseDFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT, -                                 typename GraphT::NodeRef V, unsigned N); - -  template <class GraphT> -  friend unsigned DFSPass(DominatorTreeBaseByGraphTraits<GraphT> &DT, -                          typename GraphT::NodeRef V, unsigned N); - -  template <class FuncT, class N> -  friend void Calculate(DominatorTreeBaseByGraphTraits<GraphTraits<N>> &DT, -                        FuncT &F); - -  DomTreeNodeBase<NodeT> *getNodeForBlock(NodeT *BB) { -    if (DomTreeNodeBase<NodeT> *Node = getNode(BB)) -      return Node; - -    // Haven't calculated this node yet?  Get or calculate the node for the -    // immediate dominator. -    NodeT *IDom = getIDom(BB); - -    assert(IDom || DomTreeNodes[nullptr]); -    DomTreeNodeBase<NodeT> *IDomNode = getNodeForBlock(IDom); - -    // Add a new tree node for this NodeT, and link it as a child of -    // IDomNode -    return (DomTreeNodes[BB] = IDomNode->addChild( -                llvm::make_unique<DomTreeNodeBase<NodeT>>(BB, IDomNode))).get(); -  } - -  NodeT *getIDom(NodeT *BB) const { return IDoms.lookup(BB); } - -  void addRoot(NodeT *BB) { this->Roots.push_back(BB); } -  public:    /// updateDFSNumbers - Assign In and Out numbers to the nodes while walking    /// dominator tree in dfs order. @@ -767,23 +607,119 @@ public:    template <class FT> void recalculate(FT &F) {      using TraitsTy = GraphTraits<FT *>;      reset(); -    Vertex.push_back(nullptr);      if (!this->IsPostDominators) {        // Initialize root        NodeT *entry = TraitsTy::getEntryNode(&F);        addRoot(entry); -      Calculate<FT, NodeT *>(*this, F); +      DomTreeBuilder::Calculate<FT, NodeT *>(*this, F);      } else {        // Initialize the roots list        for (auto *Node : nodes(&F))          if (TraitsTy::child_begin(Node) == TraitsTy::child_end(Node))            addRoot(Node); -      Calculate<FT, Inverse<NodeT *>>(*this, F); +      DomTreeBuilder::Calculate<FT, Inverse<NodeT *>>(*this, F);      }    } + +  /// verify - check parent and sibling property +  bool verify() const { +    return this->isPostDominator() +           ? DomTreeBuilder::Verify<Inverse<NodeT *>>(*this) +           : DomTreeBuilder::Verify<NodeT *>(*this); +  } + + protected: +  void addRoot(NodeT *BB) { this->Roots.push_back(BB); } + +  void reset() { +    DomTreeNodes.clear(); +    this->Roots.clear(); +    RootNode = nullptr; +    DFSInfoValid = false; +    SlowQueries = 0; +  } + +  // NewBB is split and now it has one successor. Update dominator tree to +  // reflect this change. +  template <class N> +  void Split(typename GraphTraits<N>::NodeRef NewBB) { +    using GraphT = GraphTraits<N>; +    using NodeRef = typename GraphT::NodeRef; +    assert(std::distance(GraphT::child_begin(NewBB), +                         GraphT::child_end(NewBB)) == 1 && +           "NewBB should have a single successor!"); +    NodeRef NewBBSucc = *GraphT::child_begin(NewBB); + +    std::vector<NodeRef> PredBlocks; +    for (const auto &Pred : children<Inverse<N>>(NewBB)) +      PredBlocks.push_back(Pred); + +    assert(!PredBlocks.empty() && "No predblocks?"); + +    bool NewBBDominatesNewBBSucc = true; +    for (const auto &Pred : children<Inverse<N>>(NewBBSucc)) { +      if (Pred != NewBB && !dominates(NewBBSucc, Pred) && +          isReachableFromEntry(Pred)) { +        NewBBDominatesNewBBSucc = false; +        break; +      } +    } + +    // Find NewBB's immediate dominator and create new dominator tree node for +    // NewBB. +    NodeT *NewBBIDom = nullptr; +    unsigned i = 0; +    for (i = 0; i < PredBlocks.size(); ++i) +      if (isReachableFromEntry(PredBlocks[i])) { +        NewBBIDom = PredBlocks[i]; +        break; +      } + +    // It's possible that none of the predecessors of NewBB are reachable; +    // in that case, NewBB itself is unreachable, so nothing needs to be +    // changed. +    if (!NewBBIDom) return; + +    for (i = i + 1; i < PredBlocks.size(); ++i) { +      if (isReachableFromEntry(PredBlocks[i])) +        NewBBIDom = findNearestCommonDominator(NewBBIDom, PredBlocks[i]); +    } + +    // Create the new dominator tree node... and set the idom of NewBB. +    DomTreeNodeBase<NodeT> *NewBBNode = addNewBlock(NewBB, NewBBIDom); + +    // If NewBB strictly dominates other blocks, then it is now the immediate +    // dominator of NewBBSucc.  Update the dominator tree as appropriate. +    if (NewBBDominatesNewBBSucc) { +      DomTreeNodeBase<NodeT> *NewBBSuccNode = getNode(NewBBSucc); +      changeImmediateDominator(NewBBSuccNode, NewBBNode); +    } +  } + + private: +  bool dominatedBySlowTreeWalk(const DomTreeNodeBase<NodeT> *A, +                               const DomTreeNodeBase<NodeT> *B) const { +    assert(A != B); +    assert(isReachableFromEntry(B)); +    assert(isReachableFromEntry(A)); + +    const DomTreeNodeBase<NodeT> *IDom; +    while ((IDom = B->getIDom()) != nullptr && IDom != A && IDom != B) +      B = IDom;  // Walk up the tree +    return IDom != nullptr; +  } + +  /// \brief Wipe this tree's state without releasing any resources. +  /// +  /// This is essentially a post-move helper only. It leaves the object in an +  /// assignable and destroyable state, but otherwise invalid. +  void wipe() { +    DomTreeNodes.clear(); +    RootNode = nullptr; +  }  };  // These two functions are declared out of line as a workaround for building | 
