From 02a1fc1da63f1aad88a5e80460f4f829870ec51a Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Mon, 5 Dec 2011 21:33:11 +0000 Subject: [PATCH] [analyzer] Rely on LLVM Dominators in Clang dominator computation. (Previously, Clang used it's implementation of dominators.) The patch is contributed by Guoping Long! llvm-svn: 145858 --- .../clang/Analysis/Analyses/Dominators.h | 221 ++++++++++++++---- clang/include/clang/Analysis/CFG.h | 127 ++++++++-- clang/lib/Analysis/CFG.cpp | 2 +- clang/lib/Analysis/CMakeLists.txt | 1 - clang/lib/Analysis/Dominators.cpp | 160 ------------- .../StaticAnalyzer/Checkers/DebugCheckers.cpp | 4 +- 6 files changed, 293 insertions(+), 222 deletions(-) delete mode 100644 clang/lib/Analysis/Dominators.cpp diff --git a/clang/include/clang/Analysis/Analyses/Dominators.h b/clang/include/clang/Analysis/Analyses/Dominators.h index 98a9bf12221b..a9b80593d1e3 100644 --- a/clang/include/clang/Analysis/Analyses/Dominators.h +++ b/clang/include/clang/Analysis/Analyses/Dominators.h @@ -1,4 +1,4 @@ -//==- Dominators.h - Construct the Dominance Tree Given CFG -----*- C++ --*-==// +//==- Dominators.h - Implementation of dominators tree for Clang CFG C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -7,74 +7,205 @@ // //===----------------------------------------------------------------------===// // -// This file implements a simple, fast dominance algorithm for source-level -// CFGs. +// This file implements the dominators tree functionality for Clang CFGs. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_DOMINATORS_H #define LLVM_CLANG_DOMINATORS_H -#include "clang/Analysis/CFG.h" #include "clang/Analysis/AnalysisContext.h" -#include "llvm/ADT/DenseMap.h" + +#include "llvm/Module.h" +#include "llvm/ADT/GraphTraits.h" +#include "clang/Analysis/CFG.h" +#include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/DominatorInternals.h" namespace clang { -class CFG; class CFGBlock; +typedef llvm::DomTreeNodeBase DomTreeNode; +/// \brief Concrete subclass of DominatorTreeBase for Clang +/// This class implements the dominators tree functionality given a Clang CFG. +/// class DominatorTree : public ManagedAnalysis { - typedef llvm::DenseMap CFGBlockMapTy; - public: - DominatorTree(AnalysisDeclContext &ac) - : AC(ac) {} + llvm::DominatorTreeBase* DT; - virtual ~DominatorTree(); + DominatorTree() { + DT = new llvm::DominatorTreeBase(false); + } - /// Return the immediate dominator node given a CFGBlock. - /// For entry block, the dominator is itself. - /// This is the same as using operator[] on this class. - CFGBlock *getNode(const CFGBlock *B) const; + ~DominatorTree() { + delete DT; + } - /// This returns the Entry Block for the given CFG - CFGBlock *getRootNode() { return RootNode; } - const CFGBlock *getRootNode() const { return RootNode; } + llvm::DominatorTreeBase& getBase() { return *DT; } - /// Returns true iff A dominates B and A != B. - /// Note that this is not a constant time operation. - bool properlyDominates(const CFGBlock *A, const CFGBlock *B) const; - - /// Returns true iff A dominates B. - bool dominates(const CFGBlock *A, const CFGBlock *B) const; - - /// Find nearest common dominator for blocks A and B. - /// Common dominator always exists, ex: entry block. - const CFGBlock *findNearestCommonDominator(const CFGBlock *A, - const CFGBlock *B) const; - - /// Constructs immediate dominator tree for a given CFG based on the algorithm - /// described in this paper: + /// \brief This method returns the root CFGBlock of the dominators tree. /// - /// A Simple, Fast Dominance Algorithm - /// Keith D. Cooper, Timothy J. Harvey and Ken Kennedy - /// Software-Practice and Expreience, 2001;4:1-10. - /// - /// This implementation is simple and runs faster in practice than the classis - /// Lengauer-Tarjan algorithm. For detailed discussions, refer to the paper. - void BuildDominatorTree(); + inline CFGBlock *getRoot() const { + return DT->getRoot(); + } - /// Dump the immediate dominance tree - void dump(); + /// \brief This method returns the root DomTreeNode, which is the wrapper + /// for CFGBlock. + inline DomTreeNode *getRootNode() const { + return DT->getRootNode(); + } + + /// \brief This method compares two dominator trees. + /// The method returns false if the other dominator tree matches this + /// dominator tree, otherwise returns true. + /// + inline bool compare(DominatorTree &Other) const { + DomTreeNode *R = getRootNode(); + DomTreeNode *OtherR = Other.getRootNode(); + + if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) + return true; + + if (DT->compare(Other.getBase())) + return true; + + return false; + } + + /// \brief This method builds the dominator tree for a given CFG + /// The CFG information is passed via AnalysisDeclContext + /// + void buildDominatorTree(AnalysisDeclContext &AC) { + cfg = AC.getCFG(); + DT->recalculate(*cfg); + } + + /// \brief This method dumps immediate dominators for each block, + /// mainly used for debug purposes. + /// + void dump() { + llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n"; + for (CFG::const_iterator I = cfg->begin(), + E = cfg->end(); I != E; ++I) { + if(DT->getNode(*I)->getIDom()) + llvm::errs() << "(" << (*I)->getBlockID() + << "," + << DT->getNode(*I)->getIDom()->getBlock()->getBlockID() + << ")\n"; + else llvm::errs() << "(" << (*I)->getBlockID() + << "," << (*I)->getBlockID() << ")\n"; + } + } + + /// \brief This method tests if one CFGBlock dominates the other. + /// The method return true if A dominates B, false otherwise. + /// Note a block always dominates itself. + /// + inline bool dominates(const CFGBlock* A, const CFGBlock* B) const { + return DT->dominates(A, B); + } + + /// \brief This method tests if one CFGBlock properly dominates the other. + /// The method return true if A properly dominates B, false otherwise. + /// + bool properlyDominates(const CFGBlock*A, const CFGBlock*B) const { + return DT->properlyDominates(A, B); + } + + /// \brief This method finds the nearest common dominator CFG block + /// for CFG block A and B. If there is no such block then return NULL. + /// + inline CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + inline const CFGBlock *findNearestCommonDominator(const CFGBlock *A, + const CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + /// \brief This method is used to update the dominator + /// tree information when a node's immediate dominator changes. + /// + inline void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) { + DT->changeImmediateDominator(N, NewIDom); + } + + /// \brief This method tests if the given CFGBlock can be reachable from root. + /// Returns true if reachable, false otherwise. + /// + bool isReachableFromEntry(const CFGBlock *A) { + return DT->isReachableFromEntry(A); + } + + /// \brief This method releases the memory held by the dominator tree. + /// + virtual void releaseMemory() { + DT->releaseMemory(); + } + + /// \brief This method converts the dominator tree to human readable form. + /// + virtual void print(raw_ostream &OS, const llvm::Module* M= 0) const { + DT->print(OS); + } private: - AnalysisDeclContext &AC; - CFGBlock *RootNode; - CFGBlockMapTy IDoms; + CFG *cfg; }; +void WriteAsOperand(raw_ostream &OS, const CFGBlock *BB, + bool t) { + OS << "BB#" << BB->getBlockID(); +} + } // end namespace clang -#endif +//===------------------------------------- +/// DominatorTree GraphTraits specialization so the DominatorTree can be +/// iterable by generic graph iterators. +/// +namespace llvm { +template <> struct GraphTraits< ::clang::DomTreeNode* > { + typedef ::clang::DomTreeNode NodeType; + typedef NodeType::iterator ChildIteratorType; + static NodeType *getEntryNode(NodeType *N) { + return N; + } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->end(); + } + + typedef df_iterator< ::clang::DomTreeNode* > nodes_iterator; + + static nodes_iterator nodes_begin(::clang::DomTreeNode *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DomTreeNode *N) { + return df_end(getEntryNode(N)); + } +}; + +template <> struct GraphTraits< ::clang::DominatorTree* > + : public GraphTraits< ::clang::DomTreeNode* > { + static NodeType *getEntryNode(::clang::DominatorTree *DT) { + return DT->getRootNode(); + } + + static nodes_iterator nodes_begin(::clang::DominatorTree *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DominatorTree *N) { + return df_end(getEntryNode(N)); + } +}; +} // end namespace llvm + +#endif diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index 66b7a6de642d..ad23d42f423b 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -344,10 +344,14 @@ class CFGBlock { /// storage if the memory usage of CFGBlock becomes an issue. unsigned HasNoReturnElement : 1; + /// Parent - The parent CFG that owns this CFGBlock. + CFG *Parent; + public: - explicit CFGBlock(unsigned blockid, BumpVectorContext &C) - : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), - BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false) {} + explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent) + : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), + BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false), + Parent(parent) {} ~CFGBlock() {} // Statement iterators @@ -489,6 +493,8 @@ public: unsigned getBlockID() const { return BlockID; } + CFG *getParent() const { return Parent; } + void dump(const CFG *cfg, const LangOptions &LO) const; void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const; void printTerminator(raw_ostream &OS, const LangOptions &LO) const; @@ -583,6 +589,55 @@ public: ,AddImplicitDtors(false) {} }; + /// \brief Provides a custom implementation of the iterator class to have the + /// same interface as Function::iterator - iterator returns CFGBlock + /// (not a pointer to CFGBlock). + class graph_iterator { + public: + typedef const CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector::iterator ImplTy; + + graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const graph_iterator &X) const { return I == X.I; } + bool operator!=(const graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () { return *I; } + + graph_iterator &operator++() { ++I; return *this; } + graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + + class const_graph_iterator { + public: + typedef const CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector::const_iterator ImplTy; + + const_graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const const_graph_iterator &X) const { return I == X.I; } + bool operator!=(const const_graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () const { return *I; } + + const_graph_iterator &operator++() { ++I; return *this; } + const_graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + /// buildCFG - Builds a CFG from an AST. The responsibility to free the /// constructed CFG belongs to the caller. static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C, @@ -619,6 +674,15 @@ public: const_iterator begin() const { return Blocks.begin(); } const_iterator end() const { return Blocks.end(); } + graph_iterator nodes_begin() { return graph_iterator(Blocks.begin()); } + graph_iterator nodes_end() { return graph_iterator(Blocks.end()); } + const_graph_iterator nodes_begin() const { + return const_graph_iterator(Blocks.begin()); + } + const_graph_iterator nodes_end() const { + return const_graph_iterator(Blocks.end()); + } + reverse_iterator rbegin() { return Blocks.rbegin(); } reverse_iterator rend() { return Blocks.rend(); } const_reverse_iterator rbegin() const { return Blocks.rbegin(); } @@ -681,6 +745,11 @@ public: /// start at 0). unsigned getNumBlockIDs() const { return NumBlockIDs; } + /// size - Return the total number of CFGBlocks within the CFG + /// This is simply a renaming of the getNumBlockIDs(). This is necessary + /// because the dominator implementation needs such an interface. + unsigned size() const { return NumBlockIDs; } + //===--------------------------------------------------------------------===// // CFG Debugging: Pretty-Printing and Visualization. //===--------------------------------------------------------------------===// @@ -781,6 +850,20 @@ template <> struct GraphTraits< const ::clang::CFGBlock *> { { return N->succ_end(); } }; +template <> struct GraphTraits > { + typedef ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse< ::clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + template <> struct GraphTraits > { typedef const ::clang::CFGBlock NodeType; typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; @@ -800,37 +883,55 @@ template <> struct GraphTraits > { template <> struct GraphTraits< ::clang::CFG* > : public GraphTraits< ::clang::CFGBlock *> { - typedef ::clang::CFG::iterator nodes_iterator; + typedef ::clang::CFG::graph_iterator nodes_iterator; - static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); } - static nodes_iterator nodes_begin(::clang::CFG* F) { return F->begin(); } - static nodes_iterator nodes_end(::clang::CFG* F) { return F->end(); } + static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();} + static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); } + static unsigned size(::clang::CFG* F) { return F->size(); } }; template <> struct GraphTraits : public GraphTraits { - typedef ::clang::CFG::const_iterator nodes_iterator; + typedef ::clang::CFG::const_graph_iterator nodes_iterator; static NodeType *getEntryNode( const ::clang::CFG* F) { return &F->getEntry(); } static nodes_iterator nodes_begin( const ::clang::CFG* F) { - return F->begin(); + return F->nodes_begin(); } static nodes_iterator nodes_end( const ::clang::CFG* F) { - return F->end(); + return F->nodes_end(); } + static unsigned size(const ::clang::CFG* F) { + return F->size(); + } +}; + +template <> struct GraphTraits > + : public GraphTraits > { + + typedef ::clang::CFG::graph_iterator nodes_iterator; + + static NodeType *getEntryNode( ::clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();} + static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); } }; template <> struct GraphTraits > : public GraphTraits > { - typedef ::clang::CFG::const_iterator nodes_iterator; + typedef ::clang::CFG::const_graph_iterator nodes_iterator; static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); } - static nodes_iterator nodes_begin(const ::clang::CFG* F) { return F->begin();} - static nodes_iterator nodes_end(const ::clang::CFG* F) { return F->end(); } + static nodes_iterator nodes_begin(const ::clang::CFG* F) { + return F->nodes_begin(); + } + static nodes_iterator nodes_end(const ::clang::CFG* F) { + return F->nodes_end(); + } }; } // end llvm namespace #endif diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index 4c1652122f9b..de404d05f729 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -3039,7 +3039,7 @@ CFGBlock *CFG::createBlock() { // Create the block. CFGBlock *Mem = getAllocator().Allocate(); - new (Mem) CFGBlock(NumBlockIDs++, BlkBVC); + new (Mem) CFGBlock(NumBlockIDs++, BlkBVC, this); Blocks.push_back(Mem, BlkBVC); // If this is the first block, set it as the Entry and Exit. diff --git a/clang/lib/Analysis/CMakeLists.txt b/clang/lib/Analysis/CMakeLists.txt index 4b88ad279af9..7ad14c41eb11 100644 --- a/clang/lib/Analysis/CMakeLists.txt +++ b/clang/lib/Analysis/CMakeLists.txt @@ -6,7 +6,6 @@ add_clang_library(clangAnalysis CFGReachabilityAnalysis.cpp CFGStmtMap.cpp CocoaConventions.cpp - Dominators.cpp FormatString.cpp LiveVariables.cpp PostOrderCFGView.cpp diff --git a/clang/lib/Analysis/Dominators.cpp b/clang/lib/Analysis/Dominators.cpp deleted file mode 100644 index 62b72287f974..000000000000 --- a/clang/lib/Analysis/Dominators.cpp +++ /dev/null @@ -1,160 +0,0 @@ -//==- Dominators.cpp - Construct the Dominance Tree Given CFG ----*- C++ --*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements a simple, fast dominance algorithm for source-level CFGs. -// -//===----------------------------------------------------------------------===// - -#include "clang/Analysis/Analyses/Dominators.h" -#include "clang/Analysis/CFG.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Analysis/Analyses/PostOrderCFGView.h" - -using namespace clang; - -DominatorTree::~DominatorTree() { - IDoms.clear(); - RootNode = 0; -} - -CFGBlock * DominatorTree::getNode(const CFGBlock *B) const { - CFGBlockMapTy::const_iterator I = IDoms.find(B); - return I != IDoms.end() ? I->second : 0; -} - -bool DominatorTree::properlyDominates(const CFGBlock *A, - const CFGBlock *B) const { - if (0 == A || 0 == B || A == B) - return false; - - // The EntryBlock dominates every other block. - if (A == RootNode) - return true; - - // Note: The dominator of the EntryBlock is itself. - CFGBlock *IDom = getNode(B); - while (IDom != A && IDom != RootNode) - IDom = getNode(IDom); - - return IDom != RootNode; -} - -bool DominatorTree::dominates(const CFGBlock *A, - const CFGBlock *B) const { - if (A == B) - return true; - - return properlyDominates(A, B); -} - -const CFGBlock * DominatorTree::findNearestCommonDominator - (const CFGBlock *A, const CFGBlock *B) const { - //If A dominates B, then A is the nearest common dominator - if (dominates(A, B)) - return A; - - //If B dominates A, then B is the nearest common dominator - if (dominates(B, A)) - return B; - - //Collect all A's dominators - llvm::SmallPtrSet ADoms; - ADoms.insert(RootNode); - CFGBlock *ADom = getNode(A); - while (ADom != RootNode) { - ADoms.insert(ADom); - ADom = getNode(ADom); - } - - //Check all B's dominators against ADoms - CFGBlock *BDom = getNode(B); - while (BDom != RootNode){ - if (ADoms.count(BDom) != 0) - return BDom; - - BDom = getNode(BDom); - } - - //The RootNode dominates every other node - return RootNode; -} - -/// Constructs immediate dominator tree for a given CFG based on the algorithm -/// described in this paper: -/// -/// A Simple, Fast Dominance Algorithm -/// Keith D. Cooper, Timothy J. Harvey and Ken Kennedy -/// Software-Practice and Expreience, 2001;4:1-10. -/// -/// This implementation is simple and runs faster in practice than the classis -/// Lengauer-Tarjan algorithm. For detailed discussions, refer to the paper. -void DominatorTree::BuildDominatorTree() { - CFG *cfg = AC.getCFG(); - CFGBlock *EntryBlk = &cfg->getEntry(); - - //Sort all CFGBlocks in reverse order - PostOrderCFGView *rpocfg = AC.getAnalysis(); - - //Set the root of the dominance tree - RootNode = EntryBlk; - - //Compute the immediate dominator for each CFGBlock - IDoms[EntryBlk] = EntryBlk; - bool changed = true; - while (changed){ - changed = false; - - for (PostOrderCFGView::iterator I = rpocfg->begin(), - E = rpocfg->end(); I != E; ++I){ - if (EntryBlk == *I) - continue; - if (const CFGBlock *B = *I) { - //Compute immediate dominance information for CFGBlock B - CFGBlock *IDom = 0; - for (CFGBlock::const_pred_iterator J = B->pred_begin(), - K = B->pred_end(); J != K; ++J) - if( CFGBlock *P = *J) { - if (IDoms.find(P) == IDoms.end()) - continue; - if (!IDom) - IDom = P; - else { - //intersect IDom and P - CFGBlock *B1 = IDom, *B2 = P; - while (B1 != B2) { - while ((rpocfg->getComparator())(B2,B1)) - B1 = IDoms[B1]; - while ((rpocfg->getComparator())(B1,B2)) - B2 = IDoms[B2]; - } - IDom = B1; - } - } - if (IDoms[B] != IDom) { - IDoms[B] = IDom; - changed = true; - } - } - } - }//while -} - -void DominatorTree::dump() { - CFG *cfg = AC.getCFG(); - - llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n"; - for (CFG::const_iterator I = cfg->begin(), - E = cfg->end(); I != E; ++I) { - assert(IDoms[(*I)] && - "Failed to find the immediate dominator for all CFG blocks."); - llvm::errs() << "(" << (*I)->getBlockID() - << "," << IDoms[(*I)]->getBlockID() << ")\n"; - } -} - diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index c06be4467aa3..bd1b8542f671 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -30,8 +30,8 @@ public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { if (AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D)) { - DominatorTree dom(*AC); - dom.BuildDominatorTree(); + DominatorTree dom; + dom.buildDominatorTree(*AC); dom.dump(); } }