[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
This commit is contained in:
Anna Zaks 2011-12-05 21:33:11 +00:00
parent 5c10794254
commit 02a1fc1da6
6 changed files with 293 additions and 222 deletions

View File

@ -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<CFGBlock> 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<const CFGBlock *, CFGBlock*> CFGBlockMapTy;
public:
DominatorTree(AnalysisDeclContext &ac)
: AC(ac) {}
llvm::DominatorTreeBase<CFGBlock>* DT;
virtual ~DominatorTree();
DominatorTree() {
DT = new llvm::DominatorTreeBase<CFGBlock>(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<CFGBlock>& 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

View File

@ -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<CFGBlock*>::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<CFGBlock*>::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<Inverse< ::clang::CFGBlock*> > {
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<Inverse<const ::clang::CFGBlock*> > {
typedef const ::clang::CFGBlock NodeType;
typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType;
@ -800,37 +883,55 @@ template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > {
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<const ::clang::CFG* >
: public GraphTraits<const ::clang::CFGBlock *> {
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<Inverse< ::clang::CFG*> >
: public GraphTraits<Inverse< ::clang::CFGBlock*> > {
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<Inverse<const ::clang::CFG*> >
: public GraphTraits<Inverse<const ::clang::CFGBlock*> > {
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

View File

@ -3039,7 +3039,7 @@ CFGBlock *CFG::createBlock() {
// Create the block.
CFGBlock *Mem = getAllocator().Allocate<CFGBlock>();
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.

View File

@ -6,7 +6,6 @@ add_clang_library(clangAnalysis
CFGReachabilityAnalysis.cpp
CFGStmtMap.cpp
CocoaConventions.cpp
Dominators.cpp
FormatString.cpp
LiveVariables.cpp
PostOrderCFGView.cpp

View File

@ -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<CFGBlock *, 16> 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<PostOrderCFGView>();
//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";
}
}

View File

@ -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();
}
}