diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
| commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
| tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /include/llvm/Support/GenericDomTree.h | |
| parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
Notes
Diffstat (limited to 'include/llvm/Support/GenericDomTree.h')
| -rw-r--r-- | include/llvm/Support/GenericDomTree.h | 201 |
1 files changed, 141 insertions, 60 deletions
diff --git a/include/llvm/Support/GenericDomTree.h b/include/llvm/Support/GenericDomTree.h index 706320fed9a7..635c87a106f0 100644 --- a/include/llvm/Support/GenericDomTree.h +++ b/include/llvm/Support/GenericDomTree.h @@ -14,8 +14,8 @@ /// graph types. /// /// Unlike ADT/* graph algorithms, generic dominator tree has more requirements -/// on the graph's NodeRef. The NodeRef should be a pointer and, depending on -/// the implementation, e.g. NodeRef->getParent() return the parent node. +/// on the graph's NodeRef. The NodeRef should be a pointer and, +/// NodeRef->getParent() must return the parent node that is also a pointer. /// /// FIXME: Maybe GenericDomTree needs a TreeTraits, instead of GraphTraits. /// @@ -24,12 +24,6 @@ #ifndef LLVM_SUPPORT_GENERICDOMTREE_H #define LLVM_SUPPORT_GENERICDOMTREE_H -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/GraphTraits.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> #include <cstddef> @@ -38,6 +32,13 @@ #include <type_traits> #include <utility> #include <vector> +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { @@ -45,7 +46,7 @@ template <typename NodeT, bool IsPostDom> class DominatorTreeBase; namespace DomTreeBuilder { -template <class DomTreeT> +template <typename DomTreeT> struct SemiNCAInfo; } // namespace DomTreeBuilder @@ -187,17 +188,51 @@ void PrintDomTree(const DomTreeNodeBase<NodeT> *N, raw_ostream &O, namespace DomTreeBuilder { // The routines below are provided in a separate header but referenced here. -template <typename DomTreeT, typename FuncT> -void Calculate(DomTreeT &DT, FuncT &F); +template <typename DomTreeT> +void Calculate(DomTreeT &DT); -template <class DomTreeT> +template <typename DomTreeT> void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From, typename DomTreeT::NodePtr To); -template <class DomTreeT> +template <typename DomTreeT> void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From, typename DomTreeT::NodePtr To); +// UpdateKind and Update are used by the batch update API and it's easiest to +// define them here. +enum class UpdateKind : unsigned char { Insert, Delete }; + +template <typename NodePtr> +struct Update { + using NodeKindPair = PointerIntPair<NodePtr, 1, UpdateKind>; + + NodePtr From; + NodeKindPair ToAndKind; + + Update(UpdateKind Kind, NodePtr From, NodePtr To) + : From(From), ToAndKind(To, Kind) {} + + UpdateKind getKind() const { return ToAndKind.getInt(); } + NodePtr getFrom() const { return From; } + NodePtr getTo() const { return ToAndKind.getPointer(); } + bool operator==(const Update &RHS) const { + return From == RHS.From && ToAndKind == RHS.ToAndKind; + } + + friend raw_ostream &operator<<(raw_ostream &OS, const Update &U) { + OS << (U.getKind() == UpdateKind::Insert ? "Insert " : "Delete "); + U.getFrom()->printAsOperand(OS, false); + OS << " -> "; + U.getTo()->printAsOperand(OS, false); + return OS; + } +}; + +template <typename DomTreeT> +void ApplyUpdates(DomTreeT &DT, + ArrayRef<typename DomTreeT::UpdateType> Updates); + template <typename DomTreeT> bool Verify(const DomTreeT &DT); } // namespace DomTreeBuilder @@ -208,14 +243,30 @@ bool Verify(const DomTreeT &DT); /// various graphs in the LLVM IR or in the code generator. template <typename NodeT, bool IsPostDom> class DominatorTreeBase { + public: + static_assert(std::is_pointer<typename GraphTraits<NodeT *>::NodeRef>::value, + "Currently DominatorTreeBase supports only pointer nodes"); + using NodeType = NodeT; + using NodePtr = NodeT *; + using ParentPtr = decltype(std::declval<NodeT *>()->getParent()); + static_assert(std::is_pointer<ParentPtr>::value, + "Currently NodeT's parent must be a pointer type"); + using ParentType = typename std::remove_pointer<ParentPtr>::type; + static constexpr bool IsPostDominator = IsPostDom; + + using UpdateType = DomTreeBuilder::Update<NodePtr>; + using UpdateKind = DomTreeBuilder::UpdateKind; + static constexpr UpdateKind Insert = UpdateKind::Insert; + static constexpr UpdateKind Delete = UpdateKind::Delete; + protected: - std::vector<NodeT *> Roots; + // Dominators always have a single root, postdominators can have more. + SmallVector<NodeT *, IsPostDom ? 4 : 1> Roots; using DomTreeNodeMapType = DenseMap<NodeT *, std::unique_ptr<DomTreeNodeBase<NodeT>>>; DomTreeNodeMapType DomTreeNodes; DomTreeNodeBase<NodeT> *RootNode; - using ParentPtr = decltype(std::declval<NodeT *>()->getParent()); ParentPtr Parent = nullptr; mutable bool DFSInfoValid = false; @@ -224,12 +275,6 @@ class DominatorTreeBase { friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase>; public: - static_assert(std::is_pointer<typename GraphTraits<NodeT *>::NodeRef>::value, - "Currently DominatorTreeBase supports only pointer nodes"); - using NodeType = NodeT; - using NodePtr = NodeT *; - static constexpr bool IsPostDominator = IsPostDom; - DominatorTreeBase() {} DominatorTreeBase(DominatorTreeBase &&Arg) @@ -260,7 +305,7 @@ class DominatorTreeBase { /// 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; } + const SmallVectorImpl<NodeT *> &getRoots() const { return Roots; } /// isPostDominator - Returns true if analysis based of postdoms /// @@ -412,14 +457,15 @@ class DominatorTreeBase { } /// findNearestCommonDominator - Find nearest common dominator basic block - /// for basic block A and B. If there is no such block then return NULL. + /// for basic block A and B. If there is no such block then return nullptr. NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) const { + assert(A && B && "Pointers are not valid"); assert(A->getParent() == B->getParent() && "Two blocks are not in same function"); // If either A or B is a entry block then it is nearest common dominator // (for forward-dominators). - if (!this->isPostDominator()) { + if (!isPostDominator()) { NodeT &Entry = A->getParent()->front(); if (A == &Entry || B == &Entry) return &Entry; @@ -457,6 +503,41 @@ class DominatorTreeBase { // API to update (Post)DominatorTree information based on modifications to // the CFG... + /// Inform the dominator tree about a sequence of CFG edge insertions and + /// deletions and perform a batch update on the tree. + /// + /// This function should be used when there were multiple CFG updates after + /// the last dominator tree update. It takes care of performing the updates + /// in sync with the CFG and optimizes away the redundant operations that + /// cancel each other. + /// The functions expects the sequence of updates to be balanced. Eg.: + /// - {{Insert, A, B}, {Delete, A, B}, {Insert, A, B}} is fine, because + /// logically it results in a single insertions. + /// - {{Insert, A, B}, {Insert, A, B}} is invalid, because it doesn't make + /// sense to insert the same edge twice. + /// + /// What's more, the functions assumes that it's safe to ask every node in the + /// CFG about its children and inverse children. This implies that deletions + /// of CFG edges must not delete the CFG nodes before calling this function. + /// + /// Batch updates should be generally faster when performing longer sequences + /// of updates than calling insertEdge/deleteEdge manually multiple times, as + /// it can reorder the updates and remove redundant ones internally. + /// The batch updater is also able to detect sequences of zero and exactly one + /// update -- it's optimized to do less work in these cases. + /// + /// Note that for postdominators it automatically takes care of applying + /// updates on reverse edges internally (so there's no need to swap the + /// From and To pointers when constructing DominatorTree::UpdateType). + /// The type of updates is the same for DomTreeBase<T> and PostDomTreeBase<T> + /// with the same template parameter T. + /// + /// \param Updates An unordered sequence of updates to perform. + /// + void applyUpdates(ArrayRef<UpdateType> Updates) { + DomTreeBuilder::ApplyUpdates(*this, Updates); + } + /// Inform the dominator tree about a CFG edge insertion and update the tree. /// /// This function has to be called just before or just after making the update @@ -476,11 +557,10 @@ class DominatorTreeBase { /// Inform the dominator tree about a CFG edge deletion and update the tree. /// - /// This function has to be called just after making the update - /// on the actual CFG. There cannot be any other updates that the dominator - /// tree doesn't know about. The only exception is when the deletion that the - /// tree is informed about makes some (domominator) subtree unreachable -- in - /// this case, it is fine to perform deletions within this subtree. + /// This function has to be called just after making the update on the actual + /// CFG. An internal functions checks if the edge doesn't exist in the CFG in + /// DEBUG mode. There cannot be any other updates that the + /// dominator tree doesn't know about. /// /// Note that for postdominators it automatically takes care of deleting /// a reverse edge internally (so there's no need to swap the parameters). @@ -559,11 +639,12 @@ class DominatorTreeBase { assert(Node && "Removing node that isn't in dominator tree."); assert(Node->getChildren().empty() && "Node is not a leaf node."); + DFSInfoValid = false; + // Remove node from immediate dominator's children list. DomTreeNodeBase<NodeT> *IDom = Node->getIDom(); if (IDom) { - typename std::vector<DomTreeNodeBase<NodeT> *>::iterator I = - find(IDom->Children, Node); + const auto I = find(IDom->Children, Node); assert(I != IDom->Children.end() && "Not in immediate dominator children set!"); // I am no longer your child... @@ -571,6 +652,15 @@ class DominatorTreeBase { } DomTreeNodes.erase(BB); + + if (!IsPostDom) return; + + // Remember to update PostDominatorTree roots. + auto RIt = llvm::find(Roots, BB); + if (RIt != Roots.end()) { + std::swap(*RIt, Roots.back()); + Roots.pop_back(); + } } /// splitBlock - BB is split and now it has one successor. Update dominator @@ -586,7 +676,7 @@ class DominatorTreeBase { /// void print(raw_ostream &O) const { O << "=============================--------------------------------\n"; - if (this->isPostDominator()) + if (IsPostDominator) O << "Inorder PostDominator Tree: "; else O << "Inorder Dominator Tree: "; @@ -596,6 +686,14 @@ class DominatorTreeBase { // The postdom tree can have a null root if there are no returns. if (getRootNode()) PrintDomTree<NodeT>(getRootNode(), O, 1); + if (IsPostDominator) { + O << "Roots: "; + for (const NodePtr Block : Roots) { + Block->printAsOperand(O, false); + O << " "; + } + O << "\n"; + } } public: @@ -607,28 +705,25 @@ public: return; } - unsigned DFSNum = 0; - SmallVector<std::pair<const DomTreeNodeBase<NodeT> *, typename DomTreeNodeBase<NodeT>::const_iterator>, 32> WorkStack; const DomTreeNodeBase<NodeT> *ThisRoot = getRootNode(); - + assert((!Parent || ThisRoot) && "Empty constructed DomTree"); if (!ThisRoot) return; - // Even in the case of multiple exits that form the post dominator root - // nodes, do not iterate over all exits, but start from the virtual root - // node. Otherwise bbs, that are not post dominated by any exit but by the - // virtual root node, will never be assigned a DFS number. - WorkStack.push_back(std::make_pair(ThisRoot, ThisRoot->begin())); + // Both dominators and postdominators have a single root node. In the case + // case of PostDominatorTree, this node is a virtual root. + WorkStack.push_back({ThisRoot, ThisRoot->begin()}); + + unsigned DFSNum = 0; ThisRoot->DFSNumIn = DFSNum++; while (!WorkStack.empty()) { const DomTreeNodeBase<NodeT> *Node = WorkStack.back().first; - typename DomTreeNodeBase<NodeT>::const_iterator ChildIt = - WorkStack.back().second; + const auto ChildIt = WorkStack.back().second; // If we visited all of the children of this node, "recurse" back up the // stack setting the DFOutNum. @@ -640,7 +735,7 @@ public: const DomTreeNodeBase<NodeT> *Child = *ChildIt; ++WorkStack.back().second; - WorkStack.push_back(std::make_pair(Child, Child->begin())); + WorkStack.push_back({Child, Child->begin()}); Child->DFSNumIn = DFSNum++; } } @@ -650,23 +745,9 @@ public: } /// recalculate - compute a dominator tree for the given function - template <class FT> void recalculate(FT &F) { - using TraitsTy = GraphTraits<FT *>; - reset(); - Parent = &F; - - if (!IsPostDominator) { - // Initialize root - NodeT *entry = TraitsTy::getEntryNode(&F); - addRoot(entry); - } else { - // Initialize the roots list - for (auto *Node : nodes(&F)) - if (TraitsTy::child_begin(Node) == TraitsTy::child_end(Node)) - addRoot(Node); - } - - DomTreeBuilder::Calculate(*this, F); + void recalculate(ParentType &Func) { + Parent = &Func; + DomTreeBuilder::Calculate(*this); } /// verify - check parent and sibling property |
