//===- Dominators.h - Dominator Info 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 // //===----------------------------------------------------------------------===// // // This file defines the DominatorTree class, which provides fast and efficient // dominance queries. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_DOMINATORS_H #define LLVM_IR_DOMINATORS_H #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/ilist_iterator.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Use.h" #include "llvm/Pass.h" #include "llvm/Support/CFGDiff.h" #include "llvm/Support/CFGUpdate.h" #include "llvm/Support/GenericDomTree.h" #include #include namespace llvm { class Function; class Instruction; class Module; class Value; class raw_ostream; template struct GraphTraits; extern template class DomTreeNodeBase; extern template class DominatorTreeBase; // DomTree extern template class DominatorTreeBase; // PostDomTree extern template class cfg::Update; namespace DomTreeBuilder { using BBDomTree = DomTreeBase; using BBPostDomTree = PostDomTreeBase; using BBUpdates = ArrayRef>; using BBDomTreeGraphDiff = GraphDiff; using BBPostDomTreeGraphDiff = GraphDiff; extern template void Calculate(BBDomTree &DT); extern template void CalculateWithUpdates(BBDomTree &DT, BBUpdates U); extern template void Calculate(BBPostDomTree &DT); extern template void InsertEdge(BBDomTree &DT, BasicBlock *From, BasicBlock *To); extern template void InsertEdge(BBPostDomTree &DT, BasicBlock *From, BasicBlock *To); extern template void DeleteEdge(BBDomTree &DT, BasicBlock *From, BasicBlock *To); extern template void DeleteEdge(BBPostDomTree &DT, BasicBlock *From, BasicBlock *To); extern template void ApplyUpdates(BBDomTree &DT, BBDomTreeGraphDiff &, BBDomTreeGraphDiff *); extern template void ApplyUpdates(BBPostDomTree &DT, BBPostDomTreeGraphDiff &, BBPostDomTreeGraphDiff *); extern template bool Verify(const BBDomTree &DT, BBDomTree::VerificationLevel VL); extern template bool Verify(const BBPostDomTree &DT, BBPostDomTree::VerificationLevel VL); } // namespace DomTreeBuilder using DomTreeNode = DomTreeNodeBase; class BasicBlockEdge { const BasicBlock *Start; const BasicBlock *End; public: BasicBlockEdge(const BasicBlock *Start_, const BasicBlock *End_) : Start(Start_), End(End_) {} BasicBlockEdge(const std::pair &Pair) : Start(Pair.first), End(Pair.second) {} BasicBlockEdge(const std::pair &Pair) : Start(Pair.first), End(Pair.second) {} const BasicBlock *getStart() const { return Start; } const BasicBlock *getEnd() const { return End; } /// Check if this is the only edge between Start and End. bool isSingleEdge() const; }; template <> struct DenseMapInfo { using BBInfo = DenseMapInfo; static unsigned getHashValue(const BasicBlockEdge *V); static inline BasicBlockEdge getEmptyKey() { return BasicBlockEdge(BBInfo::getEmptyKey(), BBInfo::getEmptyKey()); } static inline BasicBlockEdge getTombstoneKey() { return BasicBlockEdge(BBInfo::getTombstoneKey(), BBInfo::getTombstoneKey()); } static unsigned getHashValue(const BasicBlockEdge &Edge) { return hash_combine(BBInfo::getHashValue(Edge.getStart()), BBInfo::getHashValue(Edge.getEnd())); } static bool isEqual(const BasicBlockEdge &LHS, const BasicBlockEdge &RHS) { return BBInfo::isEqual(LHS.getStart(), RHS.getStart()) && BBInfo::isEqual(LHS.getEnd(), RHS.getEnd()); } }; /// Concrete subclass of DominatorTreeBase that is used to compute a /// normal dominator tree. /// /// Definition: A block is said to be forward statically reachable if there is /// a path from the entry of the function to the block. A statically reachable /// block may become statically unreachable during optimization. /// /// A forward unreachable block may appear in the dominator tree, or it may /// not. If it does, dominance queries will return results as if all reachable /// blocks dominate it. When asking for a Node corresponding to a potentially /// unreachable block, calling code must handle the case where the block was /// unreachable and the result of getNode() is nullptr. /// /// Generally, a block known to be unreachable when the dominator tree is /// constructed will not be in the tree. One which becomes unreachable after /// the dominator tree is initially constructed may still exist in the tree, /// even if the tree is properly updated. Calling code should not rely on the /// preceding statements; this is stated only to assist human understanding. class DominatorTree : public DominatorTreeBase { public: using Base = DominatorTreeBase; DominatorTree() = default; explicit DominatorTree(Function &F) { recalculate(F); } explicit DominatorTree(DominatorTree &DT, DomTreeBuilder::BBUpdates U) { recalculate(*DT.Parent, U); } /// Handle invalidation explicitly. bool invalidate(Function &F, const PreservedAnalyses &PA, FunctionAnalysisManager::Invalidator &); // Ensure base-class overloads are visible. using Base::dominates; /// Return true if the (end of the) basic block BB dominates the use U. bool dominates(const BasicBlock *BB, const Use &U) const; /// Return true if value Def dominates use U, in the sense that Def is /// available at U, and could be substituted as the used value without /// violating the SSA dominance requirement. /// /// In particular, it is worth noting that: /// * Non-instruction Defs dominate everything. /// * Def does not dominate a use in Def itself (outside of degenerate cases /// like unreachable code or trivial phi cycles). /// * Invoke Defs only dominate uses in their default destination. bool dominates(const Value *Def, const Use &U) const; /// Return true if value Def dominates all possible uses inside instruction /// User. Same comments as for the Use-based API apply. bool dominates(const Value *Def, const Instruction *User) const; /// Returns true if Def would dominate a use in any instruction in BB. /// If Def is an instruction in BB, then Def does not dominate BB. /// /// Does not accept Value to avoid ambiguity with dominance checks between /// two basic blocks. bool dominates(const Instruction *Def, const BasicBlock *BB) const; /// Return true if an edge dominates a use. /// /// If BBE is not a unique edge between start and end of the edge, it can /// never dominate the use. bool dominates(const BasicBlockEdge &BBE, const Use &U) const; bool dominates(const BasicBlockEdge &BBE, const BasicBlock *BB) const; /// Returns true if edge \p BBE1 dominates edge \p BBE2. bool dominates(const BasicBlockEdge &BBE1, const BasicBlockEdge &BBE2) const; // Ensure base class overloads are visible. using Base::isReachableFromEntry; /// Provide an overload for a Use. bool isReachableFromEntry(const Use &U) const; // Ensure base class overloads are visible. using Base::findNearestCommonDominator; /// Find the nearest instruction I that dominates both I1 and I2, in the sense /// that a result produced before I will be available at both I1 and I2. Instruction *findNearestCommonDominator(Instruction *I1, Instruction *I2) const; // Pop up a GraphViz/gv window with the Dominator Tree rendered using `dot`. void viewGraph(const Twine &Name, const Twine &Title); void viewGraph(); }; //===------------------------------------- // DominatorTree GraphTraits specializations so the DominatorTree can be // iterable by generic graph iterators. template struct DomTreeGraphTraitsBase { using NodeRef = Node *; using ChildIteratorType = ChildIterator; using nodes_iterator = df_iterator>; static NodeRef getEntryNode(NodeRef N) { return N; } static ChildIteratorType child_begin(NodeRef N) { return N->begin(); } static ChildIteratorType child_end(NodeRef N) { return N->end(); } static nodes_iterator nodes_begin(NodeRef N) { return df_begin(getEntryNode(N)); } static nodes_iterator nodes_end(NodeRef N) { return df_end(getEntryNode(N)); } }; template <> struct GraphTraits : public DomTreeGraphTraitsBase { }; template <> struct GraphTraits : public DomTreeGraphTraitsBase {}; template <> struct GraphTraits : public GraphTraits { static NodeRef getEntryNode(DominatorTree *DT) { return DT->getRootNode(); } static nodes_iterator nodes_begin(DominatorTree *N) { return df_begin(getEntryNode(N)); } static nodes_iterator nodes_end(DominatorTree *N) { return df_end(getEntryNode(N)); } }; /// Analysis pass which computes a \c DominatorTree. class DominatorTreeAnalysis : public AnalysisInfoMixin { friend AnalysisInfoMixin; static AnalysisKey Key; public: /// Provide the result typedef for this analysis pass. using Result = DominatorTree; /// Run the analysis pass over a function and produce a dominator tree. DominatorTree run(Function &F, FunctionAnalysisManager &); }; /// Printer pass for the \c DominatorTree. class DominatorTreePrinterPass : public PassInfoMixin { raw_ostream &OS; public: explicit DominatorTreePrinterPass(raw_ostream &OS); PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); static bool isRequired() { return true; } }; /// Verifier pass for the \c DominatorTree. struct DominatorTreeVerifierPass : PassInfoMixin { PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); static bool isRequired() { return true; } }; /// Enables verification of dominator trees. /// /// This check is expensive and is disabled by default. `-verify-dom-info` /// allows selectively enabling the check without needing to recompile. extern bool VerifyDomInfo; /// Legacy analysis pass which computes a \c DominatorTree. class DominatorTreeWrapperPass : public FunctionPass { DominatorTree DT; public: static char ID; DominatorTreeWrapperPass(); DominatorTree &getDomTree() { return DT; } const DominatorTree &getDomTree() const { return DT; } bool runOnFunction(Function &F) override; void verifyAnalysis() const override; void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); } void releaseMemory() override { DT.reset(); } void print(raw_ostream &OS, const Module *M = nullptr) const override; }; } // end namespace llvm #endif // LLVM_IR_DOMINATORS_H