summaryrefslogtreecommitdiff
path: root/include/llvm/Support/GenericDomTree.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support/GenericDomTree.h')
-rw-r--r--include/llvm/Support/GenericDomTree.h444
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