[cfe-commits] r76092 - in /cfe/trunk: include/clang/AST/ include/clang/Analysis/ include/clang/Analysis/FlowSensitive/ include/clang/Analysis/Support/ include/clang/Analysis/Visitors/ lib/AST/ lib/Analysis/ lib/Frontend/
Ted Kremenek
kremenek at apple.com
Thu Jul 16 11:13:05 PDT 2009
Author: kremenek
Date: Thu Jul 16 13:13:04 2009
New Revision: 76092
URL: http://llvm.org/viewvc/llvm-project?rev=76092&view=rev
Log:
Move the source-level CFG from libAST to libAnalysis.
Added:
cfe/trunk/include/clang/Analysis/CFG.h
- copied unchanged from r76086, cfe/trunk/include/clang/AST/CFG.h
cfe/trunk/lib/Analysis/CFG.cpp
- copied, changed from r76086, cfe/trunk/lib/AST/CFG.cpp
Removed:
cfe/trunk/include/clang/AST/CFG.h
cfe/trunk/lib/AST/CFG.cpp
Modified:
cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowSolver.h
cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowValues.h
cfe/trunk/include/clang/Analysis/ProgramPoint.h
cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h
cfe/trunk/include/clang/Analysis/Visitors/CFGStmtVisitor.h
cfe/trunk/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h
cfe/trunk/lib/AST/CMakeLists.txt
cfe/trunk/lib/Analysis/BugReporter.cpp
cfe/trunk/lib/Analysis/CMakeLists.txt
cfe/trunk/lib/Analysis/LiveVariables.cpp
cfe/trunk/lib/Frontend/AnalysisConsumer.cpp
Removed: cfe/trunk/include/clang/AST/CFG.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CFG.h?rev=76091&view=auto
==============================================================================
--- cfe/trunk/include/clang/AST/CFG.h (original)
+++ cfe/trunk/include/clang/AST/CFG.h (removed)
@@ -1,408 +0,0 @@
-//===--- CFG.h - Classes for representing and building CFGs------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CFG and CFGBuilder classes for representing and
-// building Control-Flow Graphs (CFGs) from ASTs.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_CFG_H
-#define LLVM_CLANG_CFG_H
-
-#include "llvm/ADT/GraphTraits.h"
-#include "llvm/Support/Allocator.h"
-#include <list>
-#include <vector>
-#include <cassert>
-
-namespace llvm {
- class raw_ostream;
-}
-namespace clang {
- class Stmt;
- class Expr;
- class CFG;
- class PrinterHelper;
- class BlockEdge;
- class LangOptions;
-
-/// CFGBlock - Represents a single basic block in a source-level CFG.
-/// It consists of:
-///
-/// (1) A set of statements/expressions (which may contain subexpressions).
-/// (2) A "terminator" statement (not in the set of statements).
-/// (3) A list of successors and predecessors.
-///
-/// Terminator: The terminator represents the type of control-flow that occurs
-/// at the end of the basic block. The terminator is a Stmt* referring to an
-/// AST node that has control-flow: if-statements, breaks, loops, etc.
-/// If the control-flow is conditional, the condition expression will appear
-/// within the set of statements in the block (usually the last statement).
-///
-/// Predecessors: the order in the set of predecessors is arbitrary.
-///
-/// Successors: the order in the set of successors is NOT arbitrary. We
-/// currently have the following orderings based on the terminator:
-///
-/// Terminator Successor Ordering
-/// -----------------------------------------------------
-/// if Then Block; Else Block
-/// ? operator LHS expression; RHS expression
-/// &&, || expression that uses result of && or ||, RHS
-///
-class CFGBlock {
- typedef std::vector<Stmt*> StatementListTy;
- /// Stmts - The set of statements in the basic block.
- StatementListTy Stmts;
-
- /// Label - An (optional) label that prefixes the executable
- /// statements in the block. When this variable is non-NULL, it is
- /// either an instance of LabelStmt or SwitchCase.
- Stmt *Label;
-
- /// Terminator - The terminator for a basic block that
- /// indicates the type of control-flow that occurs between a block
- /// and its successors.
- Stmt *Terminator;
-
- /// LoopTarget - Some blocks are used to represent the "loop edge" to
- /// the start of a loop from within the loop body. This Stmt* will be
- /// refer to the loop statement for such blocks (and be null otherwise).
- const Stmt *LoopTarget;
-
- /// BlockID - A numerical ID assigned to a CFGBlock during construction
- /// of the CFG.
- unsigned BlockID;
-
- /// Predecessors/Successors - Keep track of the predecessor / successor
- /// CFG blocks.
- typedef std::vector<CFGBlock*> AdjacentBlocks;
- AdjacentBlocks Preds;
- AdjacentBlocks Succs;
-
-public:
- explicit CFGBlock(unsigned blockid) : Label(NULL), Terminator(NULL),
- LoopTarget(NULL), BlockID(blockid) {}
- ~CFGBlock() {};
-
- // Statement iterators
- typedef StatementListTy::iterator iterator;
- typedef StatementListTy::const_iterator const_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
-
- Stmt* front() const { return Stmts.front(); }
- Stmt* back() const { return Stmts.back(); }
-
- iterator begin() { return Stmts.begin(); }
- iterator end() { return Stmts.end(); }
- const_iterator begin() const { return Stmts.begin(); }
- const_iterator end() const { return Stmts.end(); }
-
- reverse_iterator rbegin() { return Stmts.rbegin(); }
- reverse_iterator rend() { return Stmts.rend(); }
- const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
- const_reverse_iterator rend() const { return Stmts.rend(); }
-
- unsigned size() const { return Stmts.size(); }
- bool empty() const { return Stmts.empty(); }
-
- Stmt* operator[](size_t i) const { assert (i < size()); return Stmts[i]; }
-
- // CFG iterators
- typedef AdjacentBlocks::iterator pred_iterator;
- typedef AdjacentBlocks::const_iterator const_pred_iterator;
- typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator;
- typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator;
-
- typedef AdjacentBlocks::iterator succ_iterator;
- typedef AdjacentBlocks::const_iterator const_succ_iterator;
- typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator;
- typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator;
-
- pred_iterator pred_begin() { return Preds.begin(); }
- pred_iterator pred_end() { return Preds.end(); }
- const_pred_iterator pred_begin() const { return Preds.begin(); }
- const_pred_iterator pred_end() const { return Preds.end(); }
-
- pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); }
- pred_reverse_iterator pred_rend() { return Preds.rend(); }
- const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); }
- const_pred_reverse_iterator pred_rend() const { return Preds.rend(); }
-
- succ_iterator succ_begin() { return Succs.begin(); }
- succ_iterator succ_end() { return Succs.end(); }
- const_succ_iterator succ_begin() const { return Succs.begin(); }
- const_succ_iterator succ_end() const { return Succs.end(); }
-
- succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); }
- succ_reverse_iterator succ_rend() { return Succs.rend(); }
- const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); }
- const_succ_reverse_iterator succ_rend() const { return Succs.rend(); }
-
- unsigned succ_size() const { return Succs.size(); }
- bool succ_empty() const { return Succs.empty(); }
-
- unsigned pred_size() const { return Preds.size(); }
- bool pred_empty() const { return Preds.empty(); }
-
- // Manipulation of block contents
-
- void appendStmt(Stmt* Statement) { Stmts.push_back(Statement); }
- void setTerminator(Stmt* Statement) { Terminator = Statement; }
- void setLabel(Stmt* Statement) { Label = Statement; }
- void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
-
- Stmt* getTerminator() { return Terminator; }
- const Stmt* getTerminator() const { return Terminator; }
-
- Stmt* getTerminatorCondition();
-
- const Stmt* getTerminatorCondition() const {
- return const_cast<CFGBlock*>(this)->getTerminatorCondition();
- }
-
- const Stmt *getLoopTarget() const { return LoopTarget; }
-
- bool hasBinaryBranchTerminator() const;
-
- Stmt* getLabel() { return Label; }
- const Stmt* getLabel() const { return Label; }
-
- void reverseStmts();
-
- void addSuccessor(CFGBlock* Block) {
- Block->Preds.push_back(this);
- Succs.push_back(Block);
- }
-
- unsigned getBlockID() const { return BlockID; }
-
- void dump(const CFG *cfg, const LangOptions &LO) const;
- void print(llvm::raw_ostream &OS, const CFG* cfg, const LangOptions &LO) const;
- void printTerminator(llvm::raw_ostream &OS, const LangOptions &LO) const;
-};
-
-
-/// CFG - Represents a source-level, intra-procedural CFG that represents the
-/// control-flow of a Stmt. The Stmt can represent an entire function body,
-/// or a single expression. A CFG will always contain one empty block that
-/// represents the Exit point of the CFG. A CFG will also contain a designated
-/// Entry block. The CFG solely represents control-flow; it consists of
-/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG
-/// was constructed from.
-class CFG {
-public:
- //===--------------------------------------------------------------------===//
- // CFG Construction & Manipulation.
- //===--------------------------------------------------------------------===//
-
- /// buildCFG - Builds a CFG from an AST. The responsibility to free the
- /// constructed CFG belongs to the caller.
- static CFG* buildCFG(Stmt* AST);
-
- /// createBlock - Create a new block in the CFG. The CFG owns the block;
- /// the caller should not directly free it.
- CFGBlock* createBlock();
-
- /// setEntry - Set the entry block of the CFG. This is typically used
- /// only during CFG construction. Most CFG clients expect that the
- /// entry block has no predecessors and contains no statements.
- void setEntry(CFGBlock *B) { Entry = B; }
-
- /// setExit - Set the exit block of the CFG. This is typically used
- /// only during CFG construction. Most CFG clients expect that the
- /// exit block has no successors and contains no statements.
- void setIndirectGotoBlock(CFGBlock* B) { IndirectGotoBlock = B; }
-
- //===--------------------------------------------------------------------===//
- // Block Iterators
- //===--------------------------------------------------------------------===//
-
- typedef std::list<CFGBlock> CFGBlockListTy;
-
- typedef CFGBlockListTy::iterator iterator;
- typedef CFGBlockListTy::const_iterator const_iterator;
- typedef std::reverse_iterator<iterator> reverse_iterator;
- typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
-
- CFGBlock& front() { return Blocks.front(); }
- CFGBlock& back() { return Blocks.back(); }
-
- iterator begin() { return Blocks.begin(); }
- iterator end() { return Blocks.end(); }
- const_iterator begin() const { return Blocks.begin(); }
- const_iterator end() const { return Blocks.end(); }
-
- reverse_iterator rbegin() { return Blocks.rbegin(); }
- reverse_iterator rend() { return Blocks.rend(); }
- const_reverse_iterator rbegin() const { return Blocks.rbegin(); }
- const_reverse_iterator rend() const { return Blocks.rend(); }
-
- CFGBlock& getEntry() { return *Entry; }
- const CFGBlock& getEntry() const { return *Entry; }
- CFGBlock& getExit() { return *Exit; }
- const CFGBlock& getExit() const { return *Exit; }
-
- CFGBlock* getIndirectGotoBlock() { return IndirectGotoBlock; }
- const CFGBlock* getIndirectGotoBlock() const { return IndirectGotoBlock; }
-
- //===--------------------------------------------------------------------===//
- // Member templates useful for various batch operations over CFGs.
- //===--------------------------------------------------------------------===//
-
- template <typename CALLBACK>
- void VisitBlockStmts(CALLBACK& O) const {
- for (const_iterator I=begin(), E=end(); I != E; ++I)
- for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI != BE; ++BI)
- O(*BI);
- }
-
- //===--------------------------------------------------------------------===//
- // CFG Introspection.
- //===--------------------------------------------------------------------===//
-
- struct BlkExprNumTy {
- const signed Idx;
- explicit BlkExprNumTy(signed idx) : Idx(idx) {}
- explicit BlkExprNumTy() : Idx(-1) {}
- operator bool() const { return Idx >= 0; }
- operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; }
- };
-
- bool isBlkExpr(const Stmt* S) { return getBlkExprNum(S); }
- BlkExprNumTy getBlkExprNum(const Stmt* S);
- unsigned getNumBlkExprs();
-
- unsigned getNumBlockIDs() const { return NumBlockIDs; }
-
- //===--------------------------------------------------------------------===//
- // CFG Debugging: Pretty-Printing and Visualization.
- //===--------------------------------------------------------------------===//
-
- void viewCFG(const LangOptions &LO) const;
- void print(llvm::raw_ostream& OS, const LangOptions &LO) const;
- void dump(const LangOptions &LO) const;
-
- //===--------------------------------------------------------------------===//
- // Internal: constructors and data.
- //===--------------------------------------------------------------------===//
-
- CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0),
- BlkExprMap(NULL) {};
-
- ~CFG();
-
- llvm::BumpPtrAllocator& getAllocator() {
- return Alloc;
- }
-
-private:
- CFGBlock* Entry;
- CFGBlock* Exit;
- CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch
- // for indirect gotos
- CFGBlockListTy Blocks;
- unsigned NumBlockIDs;
-
- // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h.
- // It represents a map from Expr* to integers to record the set of
- // block-level expressions and their "statement number" in the CFG.
- void* BlkExprMap;
-
- /// Alloc - An internal allocator.
- llvm::BumpPtrAllocator Alloc;
-};
-} // end namespace clang
-
-//===----------------------------------------------------------------------===//
-// GraphTraits specializations for CFG basic block graphs (source-level CFGs)
-//===----------------------------------------------------------------------===//
-
-namespace llvm {
-
-// Traits for: CFGBlock
-
-template <> struct GraphTraits<clang::CFGBlock* > {
- typedef clang::CFGBlock NodeType;
- typedef clang::CFGBlock::succ_iterator ChildIteratorType;
-
- static NodeType* getEntryNode(clang::CFGBlock* BB)
- { return BB; }
-
- static inline ChildIteratorType child_begin(NodeType* N)
- { return N->succ_begin(); }
-
- static inline ChildIteratorType child_end(NodeType* N)
- { return N->succ_end(); }
-};
-
-template <> struct GraphTraits<const clang::CFGBlock* > {
- typedef const clang::CFGBlock NodeType;
- typedef clang::CFGBlock::const_succ_iterator ChildIteratorType;
-
- static NodeType* getEntryNode(const clang::CFGBlock* BB)
- { return BB; }
-
- static inline ChildIteratorType child_begin(NodeType* N)
- { return N->succ_begin(); }
-
- static inline ChildIteratorType child_end(NodeType* N)
- { return N->succ_end(); }
-};
-
-template <> struct GraphTraits<Inverse<const clang::CFGBlock*> > {
- typedef const clang::CFGBlock NodeType;
- typedef clang::CFGBlock::const_pred_iterator ChildIteratorType;
-
- static NodeType *getEntryNode(Inverse<const 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(); }
-};
-
-// Traits for: CFG
-
-template <> struct GraphTraits<clang::CFG* >
- : public GraphTraits<clang::CFGBlock* > {
-
- typedef clang::CFG::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(); }
-};
-
-template <> struct GraphTraits< const clang::CFG* >
- : public GraphTraits< const clang::CFGBlock* > {
-
- typedef clang::CFG::const_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(); }
- static nodes_iterator nodes_end( const clang::CFG* F) { return F->end(); }
-};
-
-template <> struct GraphTraits<Inverse<const clang::CFG*> >
- : public GraphTraits<Inverse<const clang::CFGBlock*> > {
-
- typedef clang::CFG::const_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(); }
-};
-
-} // end llvm namespace
-
-#endif
Modified: cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowSolver.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowSolver.h?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowSolver.h (original)
+++ cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowSolver.h Thu Jul 16 13:13:04 2009
@@ -14,7 +14,7 @@
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "functional" // STL
Modified: cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowValues.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowValues.h?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowValues.h (original)
+++ cfe/trunk/include/clang/Analysis/FlowSensitive/DataflowValues.h Thu Jul 16 13:13:04 2009
@@ -16,7 +16,7 @@
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/DenseMap.h"
Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original)
+++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Thu Jul 16 13:13:04 2009
@@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT
#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
Modified: cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h (original)
+++ cfe/trunk/include/clang/Analysis/Support/BlkExprDeclBitVector.h Thu Jul 16 13:13:04 2009
@@ -17,7 +17,7 @@
#ifndef LLVM_CLANG_STMTDECLBVDVAL_H
#define LLVM_CLANG_STMTDECLBVDVAL_H
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
Modified: cfe/trunk/include/clang/Analysis/Visitors/CFGStmtVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Visitors/CFGStmtVisitor.h?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Visitors/CFGStmtVisitor.h (original)
+++ cfe/trunk/include/clang/Analysis/Visitors/CFGStmtVisitor.h Thu Jul 16 13:13:04 2009
@@ -18,7 +18,7 @@
#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
namespace clang {
Modified: cfe/trunk/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h (original)
+++ cfe/trunk/include/clang/Analysis/Visitors/CFGVarDeclVisitor.h Thu Jul 16 13:13:04 2009
@@ -18,7 +18,6 @@
#include "clang/Analysis/Visitors/CFGStmtVisitor.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
-#include "clang/AST/CFG.h"
namespace clang {
Removed: cfe/trunk/lib/AST/CFG.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CFG.cpp?rev=76091&view=auto
==============================================================================
--- cfe/trunk/lib/AST/CFG.cpp (original)
+++ cfe/trunk/lib/AST/CFG.cpp (removed)
@@ -1,1924 +0,0 @@
-//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CFG and CFGBuilder classes for representing and
-// building Control-Flow Graphs (CFGs) from ASTs.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/CFG.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Streams.h"
-#include "llvm/Support/Compiler.h"
-#include <llvm/Support/Allocator.h>
-#include <llvm/Support/Format.h>
-
-using namespace clang;
-
-namespace {
-
-// SaveAndRestore - A utility class that uses RIIA to save and restore
-// the value of a variable.
-template<typename T>
-struct VISIBILITY_HIDDEN SaveAndRestore {
- SaveAndRestore(T& x) : X(x), old_value(x) {}
- ~SaveAndRestore() { X = old_value; }
- T get() { return old_value; }
-
- T& X;
- T old_value;
-};
-
-static SourceLocation GetEndLoc(Decl* D) {
- if (VarDecl* VD = dyn_cast<VarDecl>(D))
- if (Expr* Ex = VD->getInit())
- return Ex->getSourceRange().getEnd();
-
- return D->getLocation();
-}
-
-/// CFGBuilder - This class implements CFG construction from an AST.
-/// The builder is stateful: an instance of the builder should be used to only
-/// construct a single CFG.
-///
-/// Example usage:
-///
-/// CFGBuilder builder;
-/// CFG* cfg = builder.BuildAST(stmt1);
-///
-/// CFG construction is done via a recursive walk of an AST.
-/// We actually parse the AST in reverse order so that the successor
-/// of a basic block is constructed prior to its predecessor. This
-/// allows us to nicely capture implicit fall-throughs without extra
-/// basic blocks.
-///
-class VISIBILITY_HIDDEN CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> {
- CFG* cfg;
- CFGBlock* Block;
- CFGBlock* Succ;
- CFGBlock* ContinueTargetBlock;
- CFGBlock* BreakTargetBlock;
- CFGBlock* SwitchTerminatedBlock;
- CFGBlock* DefaultCaseBlock;
-
- // LabelMap records the mapping from Label expressions to their blocks.
- typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
- LabelMapTy LabelMap;
-
- // A list of blocks that end with a "goto" that must be backpatched to
- // their resolved targets upon completion of CFG construction.
- typedef std::vector<CFGBlock*> BackpatchBlocksTy;
- BackpatchBlocksTy BackpatchBlocks;
-
- // A list of labels whose address has been taken (for indirect gotos).
- typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy;
- LabelSetTy AddressTakenLabels;
-
-public:
- explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL),
- ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {
- // Create an empty CFG.
- cfg = new CFG();
- }
-
- ~CFGBuilder() { delete cfg; }
-
- // buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(Stmt* Statement);
-
- // Visitors to walk an AST and construct the CFG. Called by
- // buildCFG. Do not call directly!
-
- CFGBlock* VisitBreakStmt(BreakStmt* B);
- CFGBlock* VisitCaseStmt(CaseStmt* Terminator);
- CFGBlock* VisitCompoundStmt(CompoundStmt* C);
- CFGBlock* VisitContinueStmt(ContinueStmt* C);
- CFGBlock* VisitDefaultStmt(DefaultStmt* D);
- CFGBlock* VisitDoStmt(DoStmt* D);
- CFGBlock* VisitForStmt(ForStmt* F);
- CFGBlock* VisitGotoStmt(GotoStmt* G);
- CFGBlock* VisitIfStmt(IfStmt* I);
- CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I);
- CFGBlock* VisitLabelStmt(LabelStmt* L);
- CFGBlock* VisitNullStmt(NullStmt* Statement);
- CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
- CFGBlock* VisitReturnStmt(ReturnStmt* R);
- CFGBlock* VisitStmt(Stmt* Statement);
- CFGBlock* VisitSwitchStmt(SwitchStmt* Terminator);
- CFGBlock* VisitWhileStmt(WhileStmt* W);
-
- // FIXME: Add support for ObjC-specific control-flow structures.
-
- // NYS == Not Yet Supported
- CFGBlock* NYS() {
- badCFG = true;
- return Block;
- }
-
- CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S);
- CFGBlock* VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) {
- // FIXME: For now we pretend that @catch and the code it contains
- // does not exit.
- return Block;
- }
-
- // FIXME: This is not completely supported. We basically @throw like
- // a 'return'.
- CFGBlock* VisitObjCAtThrowStmt(ObjCAtThrowStmt* S);
-
- CFGBlock* VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S);
-
- // Blocks.
- CFGBlock* VisitBlockExpr(BlockExpr* E) { return NYS(); }
- CFGBlock* VisitBlockDeclRefExpr(BlockDeclRefExpr* E) { return NYS(); }
-
-private:
- CFGBlock* createBlock(bool add_successor = true);
- CFGBlock* addStmt(Stmt* Terminator);
- CFGBlock* WalkAST(Stmt* Terminator, bool AlwaysAddStmt);
- CFGBlock* WalkAST_VisitChildren(Stmt* Terminator);
- CFGBlock* WalkAST_VisitDeclSubExpr(Decl* D);
- CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* Terminator);
- bool FinishBlock(CFGBlock* B);
-
- bool badCFG;
-};
-
-// FIXME: Add support for dependent-sized array types in C++?
-// Does it even make sense to build a CFG for an uninstantiated template?
-static VariableArrayType* FindVA(Type* t) {
- while (ArrayType* vt = dyn_cast<ArrayType>(t)) {
- if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
- if (vat->getSizeExpr())
- return vat;
-
- t = vt->getElementType().getTypePtr();
- }
-
- return 0;
-}
-
-/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can
-/// represent an arbitrary statement. Examples include a single expression
-/// or a function body (compound statement). The ownership of the returned
-/// CFG is transferred to the caller. If CFG construction fails, this method
-/// returns NULL.
-CFG* CFGBuilder::buildCFG(Stmt* Statement) {
- assert (cfg);
- if (!Statement) return NULL;
-
- badCFG = false;
-
- // Create an empty block that will serve as the exit block for the CFG.
- // Since this is the first block added to the CFG, it will be implicitly
- // registered as the exit block.
- Succ = createBlock();
- assert (Succ == &cfg->getExit());
- Block = NULL; // the EXIT block is empty. Create all other blocks lazily.
-
- // Visit the statements and create the CFG.
- CFGBlock* B = Visit(Statement);
- if (!B) B = Succ;
-
- if (B) {
- // Finalize the last constructed block. This usually involves
- // reversing the order of the statements in the block.
- if (Block) FinishBlock(B);
-
- // Backpatch the gotos whose label -> block mappings we didn't know
- // when we encountered them.
- for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(),
- E = BackpatchBlocks.end(); I != E; ++I ) {
-
- CFGBlock* B = *I;
- GotoStmt* G = cast<GotoStmt>(B->getTerminator());
- LabelMapTy::iterator LI = LabelMap.find(G->getLabel());
-
- // If there is no target for the goto, then we are looking at an
- // incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end()) continue;
-
- B->addSuccessor(LI->second);
- }
-
- // Add successors to the Indirect Goto Dispatch block (if we have one).
- if (CFGBlock* B = cfg->getIndirectGotoBlock())
- for (LabelSetTy::iterator I = AddressTakenLabels.begin(),
- E = AddressTakenLabels.end(); I != E; ++I ) {
-
- // Lookup the target block.
- LabelMapTy::iterator LI = LabelMap.find(*I);
-
- // If there is no target block that contains label, then we are looking
- // at an incomplete AST. Handle this by not registering a successor.
- if (LI == LabelMap.end()) continue;
-
- B->addSuccessor(LI->second);
- }
-
- Succ = B;
- }
-
- // Create an empty entry block that has no predecessors.
- cfg->setEntry(createBlock());
-
- if (badCFG) {
- delete cfg;
- cfg = NULL;
- return NULL;
- }
-
- // NULL out cfg so that repeated calls to the builder will fail and that
- // the ownership of the constructed CFG is passed to the caller.
- CFG* t = cfg;
- cfg = NULL;
- return t;
-}
-
-/// createBlock - Used to lazily create blocks that are connected
-/// to the current (global) succcessor.
-CFGBlock* CFGBuilder::createBlock(bool add_successor) {
- CFGBlock* B = cfg->createBlock();
- if (add_successor && Succ) B->addSuccessor(Succ);
- return B;
-}
-
-/// FinishBlock - When the last statement has been added to the block,
-/// we must reverse the statements because they have been inserted
-/// in reverse order.
-bool CFGBuilder::FinishBlock(CFGBlock* B) {
- if (badCFG)
- return false;
-
- assert (B);
- B->reverseStmts();
- return true;
-}
-
-/// addStmt - Used to add statements/expressions to the current CFGBlock
-/// "Block". This method calls WalkAST on the passed statement to see if it
-/// contains any short-circuit expressions. If so, it recursively creates
-/// the necessary blocks for such expressions. It returns the "topmost" block
-/// of the created blocks, or the original value of "Block" when this method
-/// was called if no additional blocks are created.
-CFGBlock* CFGBuilder::addStmt(Stmt* Terminator) {
- if (!Block) Block = createBlock();
- return WalkAST(Terminator,true);
-}
-
-/// WalkAST - Used by addStmt to walk the subtree of a statement and
-/// add extra blocks for ternary operators, &&, and ||. We also
-/// process "," and DeclStmts (which may contain nested control-flow).
-CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) {
- switch (Terminator->getStmtClass()) {
- case Stmt::ConditionalOperatorClass: {
- ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
-
- // Create the confluence block that will "merge" the results
- // of the ternary expression.
- CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- // Create a block for the LHS expression if there is an LHS expression.
- // A GCC extension allows LHS to be NULL, causing the condition to
- // be the value that is returned instead.
- // e.g: x ?: y is shorthand for: x ? x : y;
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* LHSBlock = NULL;
- if (C->getLHS()) {
- LHSBlock = Visit(C->getLHS());
- if (!FinishBlock(LHSBlock))
- return 0;
- Block = NULL;
- }
-
- // Create the block for the RHS expression.
- Succ = ConfluenceBlock;
- CFGBlock* RHSBlock = Visit(C->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- // Create the block that will contain the condition.
- Block = createBlock(false);
-
- if (LHSBlock)
- Block->addSuccessor(LHSBlock);
- else {
- // If we have no LHS expression, add the ConfluenceBlock as a direct
- // successor for the block containing the condition. Moreover,
- // we need to reverse the order of the predecessors in the
- // ConfluenceBlock because the RHSBlock will have been added to
- // the succcessors already, and we want the first predecessor to the
- // the block containing the expression for the case when the ternary
- // expression evaluates to true.
- Block->addSuccessor(ConfluenceBlock);
- assert (ConfluenceBlock->pred_size() == 2);
- std::reverse(ConfluenceBlock->pred_begin(),
- ConfluenceBlock->pred_end());
- }
-
- Block->addSuccessor(RHSBlock);
-
- Block->setTerminator(C);
- return addStmt(C->getCond());
- }
-
- case Stmt::ChooseExprClass: {
- ChooseExpr* C = cast<ChooseExpr>(Terminator);
-
- CFGBlock* ConfluenceBlock = Block ? Block : createBlock();
- ConfluenceBlock->appendStmt(C);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* LHSBlock = Visit(C->getLHS());
- if (!FinishBlock(LHSBlock))
- return 0;
-
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* RHSBlock = Visit(C->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- Block = createBlock(false);
- Block->addSuccessor(LHSBlock);
- Block->addSuccessor(RHSBlock);
- Block->setTerminator(C);
- return addStmt(C->getCond());
- }
-
- case Stmt::DeclStmtClass: {
- DeclStmt *DS = cast<DeclStmt>(Terminator);
- if (DS->isSingleDecl()) {
- Block->appendStmt(Terminator);
- return WalkAST_VisitDeclSubExpr(DS->getSingleDecl());
- }
-
- CFGBlock* B = 0;
-
- // FIXME: Add a reverse iterator for DeclStmt to avoid this
- // extra copy.
- typedef llvm::SmallVector<Decl*,10> BufTy;
- BufTy Buf(DS->decl_begin(), DS->decl_end());
-
- for (BufTy::reverse_iterator I=Buf.rbegin(), E=Buf.rend(); I!=E; ++I) {
- // Get the alignment of the new DeclStmt, padding out to >=8 bytes.
- unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8
- ? 8 : llvm::AlignOf<DeclStmt>::Alignment;
-
- // Allocate the DeclStmt using the BumpPtrAllocator. It will
- // get automatically freed with the CFG.
- DeclGroupRef DG(*I);
- Decl* D = *I;
- void* Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A);
-
- DeclStmt* DS = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D));
-
- // Append the fake DeclStmt to block.
- Block->appendStmt(DS);
- B = WalkAST_VisitDeclSubExpr(D);
- }
- return B;
- }
-
- case Stmt::AddrLabelExprClass: {
- AddrLabelExpr* A = cast<AddrLabelExpr>(Terminator);
- AddressTakenLabels.insert(A->getLabel());
-
- if (AlwaysAddStmt) Block->appendStmt(Terminator);
- return Block;
- }
-
- case Stmt::StmtExprClass:
- return WalkAST_VisitStmtExpr(cast<StmtExpr>(Terminator));
-
- case Stmt::SizeOfAlignOfExprClass: {
- SizeOfAlignOfExpr* E = cast<SizeOfAlignOfExpr>(Terminator);
-
- // VLA types have expressions that must be evaluated.
- if (E->isArgumentType()) {
- for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- addStmt(VA->getSizeExpr());
- }
- // Expressions in sizeof/alignof are not evaluated and thus have no
- // control flow.
- else
- Block->appendStmt(Terminator);
-
- return Block;
- }
-
- case Stmt::BinaryOperatorClass: {
- BinaryOperator* B = cast<BinaryOperator>(Terminator);
-
- if (B->isLogicalOp()) { // && or ||
- CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock();
- ConfluenceBlock->appendStmt(B);
- if (!FinishBlock(ConfluenceBlock))
- return 0;
-
- // create the block evaluating the LHS
- CFGBlock* LHSBlock = createBlock(false);
- LHSBlock->setTerminator(B);
-
- // create the block evaluating the RHS
- Succ = ConfluenceBlock;
- Block = NULL;
- CFGBlock* RHSBlock = Visit(B->getRHS());
- if (!FinishBlock(RHSBlock))
- return 0;
-
- // Now link the LHSBlock with RHSBlock.
- if (B->getOpcode() == BinaryOperator::LOr) {
- LHSBlock->addSuccessor(ConfluenceBlock);
- LHSBlock->addSuccessor(RHSBlock);
- }
- else {
- assert (B->getOpcode() == BinaryOperator::LAnd);
- LHSBlock->addSuccessor(RHSBlock);
- LHSBlock->addSuccessor(ConfluenceBlock);
- }
-
- // Generate the blocks for evaluating the LHS.
- Block = LHSBlock;
- return addStmt(B->getLHS());
- }
- else if (B->getOpcode() == BinaryOperator::Comma) { // ,
- Block->appendStmt(B);
- addStmt(B->getRHS());
- return addStmt(B->getLHS());
- }
-
- break;
- }
-
- // Blocks: No support for blocks ... yet
- case Stmt::BlockExprClass:
- case Stmt::BlockDeclRefExprClass:
- return NYS();
-
- case Stmt::ParenExprClass:
- return WalkAST(cast<ParenExpr>(Terminator)->getSubExpr(), AlwaysAddStmt);
-
- default:
- break;
- };
-
- if (AlwaysAddStmt) Block->appendStmt(Terminator);
- return WalkAST_VisitChildren(Terminator);
-}
-
-/// WalkAST_VisitDeclSubExpr - Utility method to add block-level expressions
-/// for initializers in Decls.
-CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExpr(Decl* D) {
- VarDecl* VD = dyn_cast<VarDecl>(D);
-
- if (!VD)
- return Block;
-
- Expr* Init = VD->getInit();
-
- if (Init) {
- // Optimization: Don't create separate block-level statements for literals.
- switch (Init->getStmtClass()) {
- case Stmt::IntegerLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::StringLiteralClass:
- break;
- default:
- Block = addStmt(Init);
- }
- }
-
- // If the type of VD is a VLA, then we must process its size expressions.
- for (VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); VA != 0;
- VA = FindVA(VA->getElementType().getTypePtr()))
- Block = addStmt(VA->getSizeExpr());
-
- return Block;
-}
-
-/// WalkAST_VisitChildren - Utility method to call WalkAST on the
-/// children of a Stmt.
-CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* Terminator) {
- CFGBlock* B = Block;
- for (Stmt::child_iterator I = Terminator->child_begin(),
- E = Terminator->child_end();
- I != E; ++I)
- if (*I) B = WalkAST(*I);
-
- return B;
-}
-
-/// WalkAST_VisitStmtExpr - Utility method to handle (nested) statement
-/// expressions (a GCC extension).
-CFGBlock* CFGBuilder::WalkAST_VisitStmtExpr(StmtExpr* Terminator) {
- Block->appendStmt(Terminator);
- return VisitCompoundStmt(Terminator->getSubStmt());
-}
-
-/// VisitStmt - Handle statements with no branching control flow.
-CFGBlock* CFGBuilder::VisitStmt(Stmt* Statement) {
- // We cannot assume that we are in the middle of a basic block, since
- // the CFG might only be constructed for this single statement. If
- // we have no current basic block, just create one lazily.
- if (!Block) Block = createBlock();
-
- // Simply add the statement to the current block. We actually
- // insert statements in reverse order; this order is reversed later
- // when processing the containing element in the AST.
- addStmt(Statement);
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) {
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
-
- CFGBlock* LastBlock = Block;
-
- for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
- I != E; ++I ) {
- LastBlock = Visit(*I);
- }
-
- return LastBlock;
-}
-
-CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
- // We may see an if statement in the middle of a basic block, or
- // it may be the first statement we are processing. In either case,
- // we create a new basic block. First, we create the blocks for
- // the then...else statements, and then we create the block containing
- // the if statement. If we were in the middle of a block, we
- // stop processing that block and reverse its statements. That block
- // is then the implicit successor for the "then" and "else" clauses.
-
- // The block we were proccessing is now finished. Make it the
- // successor block.
- if (Block) {
- Succ = Block;
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Process the false branch. NULL out Block so that the recursive
- // call to Visit will create a new basic block.
- // Null out Block so that all successor
- CFGBlock* ElseBlock = Succ;
-
- if (Stmt* Else = I->getElse()) {
- SaveAndRestore<CFGBlock*> sv(Succ);
-
- // NULL out Block so that the recursive call to Visit will
- // create a new basic block.
- Block = NULL;
- ElseBlock = Visit(Else);
-
- if (!ElseBlock) // Can occur when the Else body has all NullStmts.
- ElseBlock = sv.get();
- else if (Block) {
- if (!FinishBlock(ElseBlock))
- return 0;
- }
- }
-
- // Process the true branch. NULL out Block so that the recursive
- // call to Visit will create a new basic block.
- // Null out Block so that all successor
- CFGBlock* ThenBlock;
- {
- Stmt* Then = I->getThen();
- assert (Then);
- SaveAndRestore<CFGBlock*> sv(Succ);
- Block = NULL;
- ThenBlock = Visit(Then);
-
- if (!ThenBlock) {
- // We can reach here if the "then" body has all NullStmts.
- // Create an empty block so we can distinguish between true and false
- // branches in path-sensitive analyses.
- ThenBlock = createBlock(false);
- ThenBlock->addSuccessor(sv.get());
- }
- else if (Block) {
- if (!FinishBlock(ThenBlock))
- return 0;
- }
- }
-
- // Now create a new block containing the if statement.
- Block = createBlock(false);
-
- // Set the terminator of the new block to the If statement.
- Block->setTerminator(I);
-
- // Now add the successors.
- Block->addSuccessor(ThenBlock);
- Block->addSuccessor(ElseBlock);
-
- // Add the condition as the last statement in the new block. This
- // may create new blocks as the condition may contain control-flow. Any
- // newly created blocks will be pointed to be "Block".
- return addStmt(I->getCond()->IgnoreParens());
-}
-
-
-CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) {
- // If we were in the middle of a block we stop processing that block
- // and reverse its statements.
- //
- // NOTE: If a "return" appears in the middle of a block, this means
- // that the code afterwards is DEAD (unreachable). We still
- // keep a basic block for that code; a simple "mark-and-sweep"
- // from the entry block will be able to report such dead
- // blocks.
- if (Block) FinishBlock(Block);
-
- // Create the new block.
- Block = createBlock(false);
-
- // The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
-
- // Add the return statement to the block. This may create new blocks
- // if R contains control-flow (short-circuit operations).
- return addStmt(R);
-}
-
-CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) {
- // Get the block of the labeled statement. Add it to our map.
- Visit(L->getSubStmt());
- CFGBlock* LabelBlock = Block;
-
- if (!LabelBlock) // This can happen when the body is empty, i.e.
- LabelBlock=createBlock(); // scopes that only contains NullStmts.
-
- assert (LabelMap.find(L) == LabelMap.end() && "label already in map");
- LabelMap[ L ] = LabelBlock;
-
- // Labels partition blocks, so this is the end of the basic block
- // we were processing (L is the block's label). Because this is
- // label (and we have already processed the substatement) there is no
- // extra control-flow to worry about.
- LabelBlock->setLabel(L);
- if (!FinishBlock(LabelBlock))
- return 0;
-
- // We set Block to NULL to allow lazy creation of a new block
- // (if necessary);
- Block = NULL;
-
- // This block is now the implicit successor of other blocks.
- Succ = LabelBlock;
-
- return LabelBlock;
-}
-
-CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) {
- // Goto is a control-flow statement. Thus we stop processing the
- // current block and create a new one.
- if (Block) FinishBlock(Block);
- Block = createBlock(false);
- Block->setTerminator(G);
-
- // If we already know the mapping to the label block add the
- // successor now.
- LabelMapTy::iterator I = LabelMap.find(G->getLabel());
-
- if (I == LabelMap.end())
- // We will need to backpatch this block later.
- BackpatchBlocks.push_back(Block);
- else
- Block->addSuccessor(I->second);
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
- // "for" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(F);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- if (Stmt* C = F->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Now create the loop body.
- {
- assert (F->getBody());
-
- // Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
-
- // Create a new block to contain the (bottom) of the loop body.
- Block = NULL;
-
- if (Stmt* I = F->getInc()) {
- // Generate increment code in its own basic block. This is the target
- // of continue statements.
- Succ = Visit(I);
- }
- else {
- // No increment code. Create a special, empty, block that is used as
- // the target block for "looping back" to the start of the loop.
- assert(Succ == EntryConditionBlock);
- Succ = createBlock();
- }
-
- // Finish up the increment (or empty) block if it hasn't been already.
- if (Block) {
- assert(Block == Succ);
- if (!FinishBlock(Block))
- return 0;
- Block = 0;
- }
-
- ContinueTargetBlock = Succ;
-
- // The starting block for the loop increment is the block that should
- // represent the 'loop target' for looping back to the start of the loop.
- ContinueTargetBlock->setLoopTarget(F);
-
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
- // Now populate the body block, and in the process create new blocks
- // as we walk the body of the loop.
- CFGBlock* BodyBlock = Visit(F->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "for (...;...; ) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // If the loop contains initialization, create a new block for those
- // statements. This block can also contain statements that precede
- // the loop.
- if (Stmt* I = F->getInit()) {
- Block = createBlock();
- return addStmt(I);
- }
- else {
- // There is no loop initialization. We are thus basically a while
- // loop. NULL out Block to force lazy block construction.
- Block = NULL;
- Succ = EntryConditionBlock;
- return EntryConditionBlock;
- }
-}
-
-CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) {
- // Objective-C fast enumeration 'for' statements:
- // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC
- //
- // for ( Type newVariable in collection_expression ) { statements }
- //
- // becomes:
- //
- // prologue:
- // 1. collection_expression
- // T. jump to loop_entry
- // loop_entry:
- // 1. side-effects of element expression
- // 1. ObjCForCollectionStmt [performs binding to newVariable]
- // T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil]
- // TB:
- // statements
- // T. jump to loop_entry
- // FB:
- // what comes after
- //
- // and
- //
- // Type existingItem;
- // for ( existingItem in expression ) { statements }
- //
- // becomes:
- //
- // the same with newVariable replaced with existingItem; the binding
- // works the same except that for one ObjCForCollectionStmt::getElement()
- // returns a DeclStmt and the other returns a DeclRefExpr.
- //
-
- CFGBlock* LoopSuccessor = 0;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- Block = 0;
- }
- else LoopSuccessor = Succ;
-
- // Build the condition blocks.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(S);
-
- // The last statement in the block should be the ObjCForCollectionStmt,
- // which performs the actual binding to 'element' and determines if there
- // are any more items in the collection.
- ExitConditionBlock->appendStmt(S);
- Block = ExitConditionBlock;
-
- // Walk the 'element' expression to see if there are any side-effects. We
- // generate new blocks as necesary. We DON'T add the statement by default
- // to the CFG unless it contains control-flow.
- EntryConditionBlock = WalkAST(S->getElement(), false);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- Block = 0;
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Now create the true branch.
- {
- // Save the current values for Succ, continue and break targets.
- SaveAndRestore<CFGBlock*> save_Succ(Succ),
- save_continue(ContinueTargetBlock), save_break(BreakTargetBlock);
-
- BreakTargetBlock = LoopSuccessor;
- ContinueTargetBlock = EntryConditionBlock;
-
- CFGBlock* BodyBlock = Visit(S->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // This new body block is a successor to our "exit" condition block.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // Now create a prologue block to contain the collection expression.
- Block = createBlock();
- return addStmt(S->getCollection());
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) {
- // FIXME: Add locking 'primitives' to CFG for @synchronized.
-
- // Inline the body.
- CFGBlock *SyncBlock = Visit(S->getSynchBody());
-
- // The sync body starts its own basic block. This makes it a little easier
- // for diagnostic clients.
- if (SyncBlock) {
- if (!FinishBlock(SyncBlock))
- return 0;
-
- Block = 0;
- }
-
- Succ = SyncBlock;
-
- // Inline the sync expression.
- return Visit(S->getSynchExpr());
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) {
- return NYS();
-}
-
-CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) {
- // "while" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(W);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- // Thus we update "Succ" after adding the condition.
- if (Stmt* C = W->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- assert(Block == EntryConditionBlock);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body as
- // well as any code above the loop.
- Succ = EntryConditionBlock;
-
- // Process the loop body.
- {
- assert(W->getBody());
-
- // Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
-
- // Create an empty block to represent the transition block for looping
- // back to the head of the loop.
- Block = 0;
- assert(Succ == EntryConditionBlock);
- Succ = createBlock();
- Succ->setLoopTarget(W);
- ContinueTargetBlock = Succ;
-
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
- // NULL out Block to force lazy instantiation of blocks for the body.
- Block = NULL;
-
- // Create the body. The returned block is the entry to the loop body.
- CFGBlock* BodyBlock = Visit(W->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "while(...) ;"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // Add the loop body entry as a successor to the condition.
- ExitConditionBlock->addSuccessor(BodyBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // There can be no more statements in the condition block
- // since we loop back to this block. NULL out Block to force
- // lazy creation of another block.
- Block = NULL;
-
- // Return the condition block, which is the dominating block for the loop.
- Succ = EntryConditionBlock;
- return EntryConditionBlock;
-}
-
-CFGBlock* CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) {
- // FIXME: This isn't complete. We basically treat @throw like a return
- // statement.
-
- // If we were in the middle of a block we stop processing that block
- // and reverse its statements.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Create the new block.
- Block = createBlock(false);
-
- // The Exit block is the only successor.
- Block->addSuccessor(&cfg->getExit());
-
- // Add the statement to the block. This may create new blocks
- // if S contains control-flow (short-circuit operations).
- return addStmt(S);
-}
-
-CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) {
- // "do...while" is a control-flow statement. Thus we stop processing the
- // current block.
-
- CFGBlock* LoopSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- LoopSuccessor = Block;
- }
- else LoopSuccessor = Succ;
-
- // Because of short-circuit evaluation, the condition of the loop
- // can span multiple basic blocks. Thus we need the "Entry" and "Exit"
- // blocks that evaluate the condition.
- CFGBlock* ExitConditionBlock = createBlock(false);
- CFGBlock* EntryConditionBlock = ExitConditionBlock;
-
- // Set the terminator for the "exit" condition block.
- ExitConditionBlock->setTerminator(D);
-
- // Now add the actual condition to the condition block. Because the
- // condition itself may contain control-flow, new blocks may be created.
- if (Stmt* C = D->getCond()) {
- Block = ExitConditionBlock;
- EntryConditionBlock = addStmt(C);
- if (Block) {
- if (!FinishBlock(EntryConditionBlock))
- return 0;
- }
- }
-
- // The condition block is the implicit successor for the loop body.
- Succ = EntryConditionBlock;
-
- // Process the loop body.
- CFGBlock* BodyBlock = NULL;
- {
- assert (D->getBody());
-
- // Save the current values for Block, Succ, and continue and break targets
- SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
-
- // All continues within this loop should go to the condition block
- ContinueTargetBlock = EntryConditionBlock;
-
- // All breaks should go to the code following the loop.
- BreakTargetBlock = LoopSuccessor;
-
- // NULL out Block to force lazy instantiation of blocks for the body.
- Block = NULL;
-
- // Create the body. The returned block is the entry to the loop body.
- BodyBlock = Visit(D->getBody());
-
- if (!BodyBlock)
- BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)"
- else if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // Add an intermediate block between the BodyBlock and the
- // ExitConditionBlock to represent the "loop back" transition.
- // Create an empty block to represent the transition block for looping
- // back to the head of the loop.
- // FIXME: Can we do this more efficiently without adding another block?
- Block = NULL;
- Succ = BodyBlock;
- CFGBlock *LoopBackBlock = createBlock();
- LoopBackBlock->setLoopTarget(D);
-
- // Add the loop body entry as a successor to the condition.
- ExitConditionBlock->addSuccessor(LoopBackBlock);
- }
-
- // Link up the condition block with the code that follows the loop.
- // (the false branch).
- ExitConditionBlock->addSuccessor(LoopSuccessor);
-
- // There can be no more statements in the body block(s)
- // since we loop back to the body. NULL out Block to force
- // lazy creation of another block.
- Block = NULL;
-
- // Return the loop body, which is the dominating block for the loop.
- Succ = BodyBlock;
- return BodyBlock;
-}
-
-CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) {
- // "continue" is a control-flow statement. Thus we stop processing the
- // current block.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Now create a new block that ends with the continue statement.
- Block = createBlock(false);
- Block->setTerminator(C);
-
- // If there is no target for the continue, then we are looking at an
- // incomplete AST. This means the CFG cannot be constructed.
- if (ContinueTargetBlock)
- Block->addSuccessor(ContinueTargetBlock);
- else
- badCFG = true;
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) {
- // "break" is a control-flow statement. Thus we stop processing the
- // current block.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
-
- // Now create a new block that ends with the continue statement.
- Block = createBlock(false);
- Block->setTerminator(B);
-
- // If there is no target for the break, then we are looking at an
- // incomplete AST. This means that the CFG cannot be constructed.
- if (BreakTargetBlock)
- Block->addSuccessor(BreakTargetBlock);
- else
- badCFG = true;
-
-
- return Block;
-}
-
-CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
- // "switch" is a control-flow statement. Thus we stop processing the
- // current block.
- CFGBlock* SwitchSuccessor = NULL;
-
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- SwitchSuccessor = Block;
- }
- else SwitchSuccessor = Succ;
-
- // Save the current "switch" context.
- SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock),
- save_break(BreakTargetBlock),
- save_default(DefaultCaseBlock);
-
- // Set the "default" case to be the block after the switch statement.
- // If the switch statement contains a "default:", this value will
- // be overwritten with the block for that code.
- DefaultCaseBlock = SwitchSuccessor;
-
- // Create a new block that will contain the switch statement.
- SwitchTerminatedBlock = createBlock(false);
-
- // Now process the switch body. The code after the switch is the implicit
- // successor.
- Succ = SwitchSuccessor;
- BreakTargetBlock = SwitchSuccessor;
-
- // When visiting the body, the case statements should automatically get
- // linked up to the switch. We also don't keep a pointer to the body,
- // since all control-flow from the switch goes to case/default statements.
- assert (Terminator->getBody() && "switch must contain a non-NULL body");
- Block = NULL;
- CFGBlock *BodyBlock = Visit(Terminator->getBody());
- if (Block) {
- if (!FinishBlock(BodyBlock))
- return 0;
- }
-
- // If we have no "default:" case, the default transition is to the
- // code following the switch body.
- SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock);
-
- // Add the terminator and condition in the switch block.
- SwitchTerminatedBlock->setTerminator(Terminator);
- assert (Terminator->getCond() && "switch condition must be non-NULL");
- Block = SwitchTerminatedBlock;
-
- return addStmt(Terminator->getCond());
-}
-
-CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* Terminator) {
- // CaseStmts are essentially labels, so they are the
- // first statement in a block.
-
- if (Terminator->getSubStmt()) Visit(Terminator->getSubStmt());
- CFGBlock* CaseBlock = Block;
- if (!CaseBlock) CaseBlock = createBlock();
-
- // Cases statements partition blocks, so this is the top of
- // the basic block we were processing (the "case XXX:" is the label).
- CaseBlock->setLabel(Terminator);
- if (!FinishBlock(CaseBlock))
- return 0;
-
- // Add this block to the list of successors for the block with the
- // switch statement.
- assert (SwitchTerminatedBlock);
- SwitchTerminatedBlock->addSuccessor(CaseBlock);
-
- // We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
-
- // This block is now the implicit successor of other blocks.
- Succ = CaseBlock;
-
- return CaseBlock;
-}
-
-CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) {
- if (Terminator->getSubStmt()) Visit(Terminator->getSubStmt());
- DefaultCaseBlock = Block;
- if (!DefaultCaseBlock) DefaultCaseBlock = createBlock();
-
- // Default statements partition blocks, so this is the top of
- // the basic block we were processing (the "default:" is the label).
- DefaultCaseBlock->setLabel(Terminator);
- if (!FinishBlock(DefaultCaseBlock))
- return 0;
-
- // Unlike case statements, we don't add the default block to the
- // successors for the switch statement immediately. This is done
- // when we finish processing the switch statement. This allows for
- // the default case (including a fall-through to the code after the
- // switch statement) to always be the last successor of a switch-terminated
- // block.
-
- // We set Block to NULL to allow lazy creation of a new block (if necessary)
- Block = NULL;
-
- // This block is now the implicit successor of other blocks.
- Succ = DefaultCaseBlock;
-
- return DefaultCaseBlock;
-}
-
-CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
- // Lazily create the indirect-goto dispatch block if there isn't one
- // already.
- CFGBlock* IBlock = cfg->getIndirectGotoBlock();
-
- if (!IBlock) {
- IBlock = createBlock(false);
- cfg->setIndirectGotoBlock(IBlock);
- }
-
- // IndirectGoto is a control-flow statement. Thus we stop processing the
- // current block and create a new one.
- if (Block) {
- if (!FinishBlock(Block))
- return 0;
- }
- Block = createBlock(false);
- Block->setTerminator(I);
- Block->addSuccessor(IBlock);
- return addStmt(I->getTarget());
-}
-
-
-} // end anonymous namespace
-
-/// createBlock - Constructs and adds a new CFGBlock to the CFG. The
-/// block has no successors or predecessors. If this is the first block
-/// created in the CFG, it is automatically set to be the Entry and Exit
-/// of the CFG.
-CFGBlock* CFG::createBlock() {
- bool first_block = begin() == end();
-
- // Create the block.
- Blocks.push_front(CFGBlock(NumBlockIDs++));
-
- // If this is the first block, set it as the Entry and Exit.
- if (first_block) Entry = Exit = &front();
-
- // Return the block.
- return &front();
-}
-
-/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
-/// CFG is returned to the caller.
-CFG* CFG::buildCFG(Stmt* Statement) {
- CFGBuilder Builder;
- return Builder.buildCFG(Statement);
-}
-
-/// reverseStmts - Reverses the orders of statements within a CFGBlock.
-void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); }
-
-//===----------------------------------------------------------------------===//
-// CFG: Queries for BlkExprs.
-//===----------------------------------------------------------------------===//
-
-namespace {
- typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy;
-}
-
-static void FindSubExprAssignments(Stmt* Terminator, llvm::SmallPtrSet<Expr*,50>& Set) {
- if (!Terminator)
- return;
-
- for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->child_end(); I!=E; ++I) {
- if (!*I) continue;
-
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(*I))
- if (B->isAssignmentOp()) Set.insert(B);
-
- FindSubExprAssignments(*I, Set);
- }
-}
-
-static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) {
- BlkExprMapTy* M = new BlkExprMapTy();
-
- // Look for assignments that are used as subexpressions. These are the
- // only assignments that we want to *possibly* register as a block-level
- // expression. Basically, if an assignment occurs both in a subexpression
- // and at the block-level, it is a block-level expression.
- llvm::SmallPtrSet<Expr*,50> SubExprAssignments;
-
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I)
- for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
- FindSubExprAssignments(*BI, SubExprAssignments);
-
- for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) {
-
- // Iterate over the statements again on identify the Expr* and Stmt* at
- // the block-level that are block-level expressions.
-
- for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI)
- if (Expr* Exp = dyn_cast<Expr>(*BI)) {
-
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) {
- // Assignment expressions that are not nested within another
- // expression are really "statements" whose value is never
- // used by another expression.
- if (B->isAssignmentOp() && !SubExprAssignments.count(Exp))
- continue;
- }
- else if (const StmtExpr* Terminator = dyn_cast<StmtExpr>(Exp)) {
- // Special handling for statement expressions. The last statement
- // in the statement expression is also a block-level expr.
- const CompoundStmt* C = Terminator->getSubStmt();
- if (!C->body_empty()) {
- unsigned x = M->size();
- (*M)[C->body_back()] = x;
- }
- }
-
- unsigned x = M->size();
- (*M)[Exp] = x;
- }
-
- // Look at terminators. The condition is a block-level expression.
-
- Stmt* S = I->getTerminatorCondition();
-
- if (S && M->find(S) == M->end()) {
- unsigned x = M->size();
- (*M)[S] = x;
- }
- }
-
- return M;
-}
-
-CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) {
- assert(S != NULL);
- if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); }
-
- BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
- BlkExprMapTy::iterator I = M->find(S);
-
- if (I == M->end()) return CFG::BlkExprNumTy();
- else return CFG::BlkExprNumTy(I->second);
-}
-
-unsigned CFG::getNumBlkExprs() {
- if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap))
- return M->size();
- else {
- // We assume callers interested in the number of BlkExprs will want
- // the map constructed if it doesn't already exist.
- BlkExprMap = (void*) PopulateBlkExprMap(*this);
- return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size();
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Cleanup: CFG dstor.
-//===----------------------------------------------------------------------===//
-
-CFG::~CFG() {
- delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap);
-}
-
-//===----------------------------------------------------------------------===//
-// CFG pretty printing
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper {
-
- typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
- StmtMapTy StmtMap;
- signed CurrentBlock;
- unsigned CurrentStmt;
- const LangOptions &LangOpts;
-public:
-
- StmtPrinterHelper(const CFG* cfg, const LangOptions &LO)
- : CurrentBlock(0), CurrentStmt(0), LangOpts(LO) {
- for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) {
- unsigned j = 1;
- for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ;
- BI != BEnd; ++BI, ++j )
- StmtMap[*BI] = std::make_pair(I->getBlockID(),j);
- }
- }
-
- virtual ~StmtPrinterHelper() {}
-
- const LangOptions &getLangOpts() const { return LangOpts; }
- void setBlockID(signed i) { CurrentBlock = i; }
- void setStmtID(unsigned i) { CurrentStmt = i; }
-
- virtual bool handledStmt(Stmt* Terminator, llvm::raw_ostream& OS) {
-
- StmtMapTy::iterator I = StmtMap.find(Terminator);
-
- if (I == StmtMap.end())
- return false;
-
- if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock
- && I->second.second == CurrentStmt)
- return false;
-
- OS << "[B" << I->second.first << "." << I->second.second << "]";
- return true;
- }
-};
-} // end anonymous namespace
-
-
-namespace {
-class VISIBILITY_HIDDEN CFGBlockTerminatorPrint
- : public StmtVisitor<CFGBlockTerminatorPrint,void> {
-
- llvm::raw_ostream& OS;
- StmtPrinterHelper* Helper;
- PrintingPolicy Policy;
-
-public:
- CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper,
- const PrintingPolicy &Policy)
- : OS(os), Helper(helper), Policy(Policy) {}
-
- void VisitIfStmt(IfStmt* I) {
- OS << "if ";
- I->getCond()->printPretty(OS,Helper,Policy);
- }
-
- // Default case.
- void VisitStmt(Stmt* Terminator) { Terminator->printPretty(OS, Helper, Policy); }
-
- void VisitForStmt(ForStmt* F) {
- OS << "for (" ;
- if (F->getInit()) OS << "...";
- OS << "; ";
- if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy);
- OS << "; ";
- if (F->getInc()) OS << "...";
- OS << ")";
- }
-
- void VisitWhileStmt(WhileStmt* W) {
- OS << "while " ;
- if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy);
- }
-
- void VisitDoStmt(DoStmt* D) {
- OS << "do ... while ";
- if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy);
- }
-
- void VisitSwitchStmt(SwitchStmt* Terminator) {
- OS << "switch ";
- Terminator->getCond()->printPretty(OS, Helper, Policy);
- }
-
- void VisitConditionalOperator(ConditionalOperator* C) {
- C->getCond()->printPretty(OS, Helper, Policy);
- OS << " ? ... : ...";
- }
-
- void VisitChooseExpr(ChooseExpr* C) {
- OS << "__builtin_choose_expr( ";
- C->getCond()->printPretty(OS, Helper, Policy);
- OS << " )";
- }
-
- void VisitIndirectGotoStmt(IndirectGotoStmt* I) {
- OS << "goto *";
- I->getTarget()->printPretty(OS, Helper, Policy);
- }
-
- void VisitBinaryOperator(BinaryOperator* B) {
- if (!B->isLogicalOp()) {
- VisitExpr(B);
- return;
- }
-
- B->getLHS()->printPretty(OS, Helper, Policy);
-
- switch (B->getOpcode()) {
- case BinaryOperator::LOr:
- OS << " || ...";
- return;
- case BinaryOperator::LAnd:
- OS << " && ...";
- return;
- default:
- assert(false && "Invalid logical operator.");
- }
- }
-
- void VisitExpr(Expr* E) {
- E->printPretty(OS, Helper, Policy);
- }
-};
-} // end anonymous namespace
-
-
-static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
- Stmt* Terminator) {
- if (Helper) {
- // special printing for statement-expressions.
- if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) {
- CompoundStmt* Sub = SE->getSubStmt();
-
- if (Sub->child_begin() != Sub->child_end()) {
- OS << "({ ... ; ";
- Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS);
- OS << " })\n";
- return;
- }
- }
-
- // special printing for comma expressions.
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(Terminator)) {
- if (B->getOpcode() == BinaryOperator::Comma) {
- OS << "... , ";
- Helper->handledStmt(B->getRHS(),OS);
- OS << '\n';
- return;
- }
- }
- }
-
- Terminator->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts()));
-
- // Expressions need a newline.
- if (isa<Expr>(Terminator)) OS << '\n';
-}
-
-static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
- const CFGBlock& B,
- StmtPrinterHelper* Helper, bool print_edges) {
-
- if (Helper) Helper->setBlockID(B.getBlockID());
-
- // Print the header.
- OS << "\n [ B" << B.getBlockID();
-
- if (&B == &cfg->getEntry())
- OS << " (ENTRY) ]\n";
- else if (&B == &cfg->getExit())
- OS << " (EXIT) ]\n";
- else if (&B == cfg->getIndirectGotoBlock())
- OS << " (INDIRECT GOTO DISPATCH) ]\n";
- else
- OS << " ]\n";
-
- // Print the label of this block.
- if (Stmt* Terminator = const_cast<Stmt*>(B.getLabel())) {
-
- if (print_edges)
- OS << " ";
-
- if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator))
- OS << L->getName();
- else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) {
- OS << "case ";
- C->getLHS()->printPretty(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
- if (C->getRHS()) {
- OS << " ... ";
- C->getRHS()->printPretty(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
- }
- }
- else if (isa<DefaultStmt>(Terminator))
- OS << "default";
- else
- assert(false && "Invalid label statement in CFGBlock.");
-
- OS << ":\n";
- }
-
- // Iterate through the statements in the block and print them.
- unsigned j = 1;
-
- for (CFGBlock::const_iterator I = B.begin(), E = B.end() ;
- I != E ; ++I, ++j ) {
-
- // Print the statement # in the basic block and the statement itself.
- if (print_edges)
- OS << " ";
-
- OS << llvm::format("%3d", j) << ": ";
-
- if (Helper)
- Helper->setStmtID(j);
-
- print_stmt(OS,Helper,*I);
- }
-
- // Print the terminator of this block.
- if (B.getTerminator()) {
- if (print_edges)
- OS << " ";
-
- OS << " T: ";
-
- if (Helper) Helper->setBlockID(-1);
-
- CFGBlockTerminatorPrint TPrinter(OS, Helper,
- PrintingPolicy(Helper->getLangOpts()));
- TPrinter.Visit(const_cast<Stmt*>(B.getTerminator()));
- OS << '\n';
- }
-
- if (print_edges) {
- // Print the predecessors of this block.
- OS << " Predecessors (" << B.pred_size() << "):";
- unsigned i = 0;
-
- for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end();
- I != E; ++I, ++i) {
-
- if (i == 8 || (i-8) == 0)
- OS << "\n ";
-
- OS << " B" << (*I)->getBlockID();
- }
-
- OS << '\n';
-
- // Print the successors of this block.
- OS << " Successors (" << B.succ_size() << "):";
- i = 0;
-
- for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end();
- I != E; ++I, ++i) {
-
- if (i == 8 || (i-8) % 10 == 0)
- OS << "\n ";
-
- OS << " B" << (*I)->getBlockID();
- }
-
- OS << '\n';
- }
-}
-
-
-/// dump - A simple pretty printer of a CFG that outputs to stderr.
-void CFG::dump(const LangOptions &LO) const { print(llvm::errs(), LO); }
-
-/// print - A simple pretty printer of a CFG that outputs to an ostream.
-void CFG::print(llvm::raw_ostream &OS, const LangOptions &LO) const {
- StmtPrinterHelper Helper(this, LO);
-
- // Print the entry block.
- print_block(OS, this, getEntry(), &Helper, true);
-
- // Iterate through the CFGBlocks and print them one by one.
- for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) {
- // Skip the entry block, because we already printed it.
- if (&(*I) == &getEntry() || &(*I) == &getExit())
- continue;
-
- print_block(OS, this, *I, &Helper, true);
- }
-
- // Print the exit block.
- print_block(OS, this, getExit(), &Helper, true);
- OS.flush();
-}
-
-/// dump - A simply pretty printer of a CFGBlock that outputs to stderr.
-void CFGBlock::dump(const CFG* cfg, const LangOptions &LO) const {
- print(llvm::errs(), cfg, LO);
-}
-
-/// print - A simple pretty printer of a CFGBlock that outputs to an ostream.
-/// Generally this will only be called from CFG::print.
-void CFGBlock::print(llvm::raw_ostream& OS, const CFG* cfg,
- const LangOptions &LO) const {
- StmtPrinterHelper Helper(cfg, LO);
- print_block(OS, cfg, *this, &Helper, true);
-}
-
-/// printTerminator - A simple pretty printer of the terminator of a CFGBlock.
-void CFGBlock::printTerminator(llvm::raw_ostream &OS,
- const LangOptions &LO) const {
- CFGBlockTerminatorPrint TPrinter(OS, NULL, PrintingPolicy(LO));
- TPrinter.Visit(const_cast<Stmt*>(getTerminator()));
-}
-
-Stmt* CFGBlock::getTerminatorCondition() {
-
- if (!Terminator)
- return NULL;
-
- Expr* E = NULL;
-
- switch (Terminator->getStmtClass()) {
- default:
- break;
-
- case Stmt::ForStmtClass:
- E = cast<ForStmt>(Terminator)->getCond();
- break;
-
- case Stmt::WhileStmtClass:
- E = cast<WhileStmt>(Terminator)->getCond();
- break;
-
- case Stmt::DoStmtClass:
- E = cast<DoStmt>(Terminator)->getCond();
- break;
-
- case Stmt::IfStmtClass:
- E = cast<IfStmt>(Terminator)->getCond();
- break;
-
- case Stmt::ChooseExprClass:
- E = cast<ChooseExpr>(Terminator)->getCond();
- break;
-
- case Stmt::IndirectGotoStmtClass:
- E = cast<IndirectGotoStmt>(Terminator)->getTarget();
- break;
-
- case Stmt::SwitchStmtClass:
- E = cast<SwitchStmt>(Terminator)->getCond();
- break;
-
- case Stmt::ConditionalOperatorClass:
- E = cast<ConditionalOperator>(Terminator)->getCond();
- break;
-
- case Stmt::BinaryOperatorClass: // '&&' and '||'
- E = cast<BinaryOperator>(Terminator)->getLHS();
- break;
-
- case Stmt::ObjCForCollectionStmtClass:
- return Terminator;
- }
-
- return E ? E->IgnoreParens() : NULL;
-}
-
-bool CFGBlock::hasBinaryBranchTerminator() const {
-
- if (!Terminator)
- return false;
-
- Expr* E = NULL;
-
- switch (Terminator->getStmtClass()) {
- default:
- return false;
-
- case Stmt::ForStmtClass:
- case Stmt::WhileStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::IfStmtClass:
- case Stmt::ChooseExprClass:
- case Stmt::ConditionalOperatorClass:
- case Stmt::BinaryOperatorClass:
- return true;
- }
-
- return E ? E->IgnoreParens() : NULL;
-}
-
-
-//===----------------------------------------------------------------------===//
-// CFG Graphviz Visualization
-//===----------------------------------------------------------------------===//
-
-
-#ifndef NDEBUG
-static StmtPrinterHelper* GraphHelper;
-#endif
-
-void CFG::viewCFG(const LangOptions &LO) const {
-#ifndef NDEBUG
- StmtPrinterHelper H(this, LO);
- GraphHelper = &H;
- llvm::ViewGraph(this,"CFG");
- GraphHelper = NULL;
-#endif
-}
-
-namespace llvm {
-template<>
-struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph,
- bool ShortNames) {
-
-#ifndef NDEBUG
- std::string OutSStr;
- llvm::raw_string_ostream Out(OutSStr);
- print_block(Out,Graph, *Node, GraphHelper, false);
- std::string& OutStr = Out.str();
-
- if (OutStr[0] == '\n') OutStr.erase(OutStr.begin());
-
- // Process string output to make it nicer...
- for (unsigned i = 0; i != OutStr.length(); ++i)
- if (OutStr[i] == '\n') { // Left justify
- OutStr[i] = '\\';
- OutStr.insert(OutStr.begin()+i+1, 'l');
- }
-
- return OutStr;
-#else
- return "";
-#endif
- }
-};
-} // end namespace llvm
Modified: cfe/trunk/lib/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CMakeLists.txt (original)
+++ cfe/trunk/lib/AST/CMakeLists.txt Thu Jul 16 13:13:04 2009
@@ -4,7 +4,6 @@
APValue.cpp
ASTConsumer.cpp
ASTContext.cpp
- CFG.cpp
Decl.cpp
DeclBase.cpp
DeclCXX.cpp
Modified: cfe/trunk/lib/Analysis/BugReporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BugReporter.cpp?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/BugReporter.cpp (original)
+++ cfe/trunk/lib/Analysis/BugReporter.cpp Thu Jul 16 13:13:04 2009
@@ -15,7 +15,7 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ParentMap.h"
#include "clang/AST/StmtObjC.h"
Copied: cfe/trunk/lib/Analysis/CFG.cpp (from r76086, cfe/trunk/lib/AST/CFG.cpp)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CFG.cpp?p2=cfe/trunk/lib/Analysis/CFG.cpp&p1=cfe/trunk/lib/AST/CFG.cpp&r1=76086&r2=76092&rev=76092&view=diff
==============================================================================
--- cfe/trunk/lib/AST/CFG.cpp (original)
+++ cfe/trunk/lib/Analysis/CFG.cpp Thu Jul 16 13:13:04 2009
@@ -12,7 +12,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/ADT/DenseMap.h"
Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
+++ cfe/trunk/lib/Analysis/CMakeLists.txt Thu Jul 16 13:13:04 2009
@@ -6,6 +6,7 @@
BasicStore.cpp
BasicValueFactory.cpp
BugReporter.cpp
+ CFG.cpp
CFRefCount.cpp
CallGraph.cpp
CheckDeadStores.cpp
Modified: cfe/trunk/lib/Analysis/LiveVariables.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/LiveVariables.cpp?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/LiveVariables.cpp (original)
+++ cfe/trunk/lib/Analysis/LiveVariables.cpp Thu Jul 16 13:13:04 2009
@@ -15,7 +15,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "llvm/ADT/SmallPtrSet.h"
Modified: cfe/trunk/lib/Frontend/AnalysisConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/AnalysisConsumer.cpp?rev=76092&r1=76091&r2=76092&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/AnalysisConsumer.cpp (original)
+++ cfe/trunk/lib/Frontend/AnalysisConsumer.cpp Thu Jul 16 13:13:04 2009
@@ -19,7 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/OwningPtr.h"
-#include "clang/AST/CFG.h"
+#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/SourceManager.h"
More information about the cfe-commits
mailing list