Removed "ObserverTy" from core DataflowValues types. The observer

mechanism can be implemented simply by affixing the Observer to an
analysis meta data, so it doesn't need to be a required type.  This
also permits analyses not to implement an Observer if it doesn't make
sense.

Changed "DataflowValues::MetaDataTy" to
"DataflowValues::AnalysisDataTy" to reflect that the type
enscapsulated the data associated with analyzing a given CFG.

Changed CFGStmtVisitor::BlockStmt_VisitImplicitControlFlowStmt(Stmt*)
to ...VisitImplicitControlFlowExpr(Expr*).  The type narrowing is more
precise and more useful to clients.

Added CFGStmtVisitor::BlockStmt_VisitExpr to reflect the visitation of
expressions at the block statement level.  This captures all implicit
control-flow statements as well as other expressions that are hoisted
to the block level (such as conditions for terminators and function
calls).  This is especially useful for dataflow analysis.

llvm-svn: 42034
This commit is contained in:
Ted Kremenek 2007-09-17 17:14:52 +00:00
parent c3fddac8e7
commit 789ea076a8
6 changed files with 66 additions and 57 deletions

View File

@ -62,14 +62,13 @@ public:
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag; typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
typedef typename _DFValuesTy::ValTy ValTy; typedef typename _DFValuesTy::ValTy ValTy;
typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy; typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy;
typedef typename _DFValuesTy::ObserverTy ObserverTy;
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// External interface: constructing and running the solver. // External interface: constructing and running the solver.
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
public: public:
DataflowSolver(DFValuesTy& d, ObserverTy* o = NULL) : D(d), O(o) {} DataflowSolver(DFValuesTy& d) : D(d) {}
~DataflowSolver() {} ~DataflowSolver() {}
/// runOnCFG - Computes dataflow values for all blocks in a CFG. /// runOnCFG - Computes dataflow values for all blocks in a CFG.
@ -86,7 +85,7 @@ public:
/// only be used for querying the dataflow values within a block with /// only be used for querying the dataflow values within a block with
/// and Observer object. /// and Observer object.
void runOnBlock(const CFGBlock* B) { void runOnBlock(const CFGBlock* B) {
TransferFuncsTy TF (D.getMetaData(),O); TransferFuncsTy TF (D.getAnalysisData());
ProcessBlock(B,TF,AnalysisDirTag()); ProcessBlock(B,TF,AnalysisDirTag());
} }
@ -106,7 +105,7 @@ private:
WorkList.enqueue(&cfg.getEntry()); WorkList.enqueue(&cfg.getEntry());
// Create the state for transfer functions. // Create the state for transfer functions.
TransferFuncsTy TF(D.getMetaData(),O); TransferFuncsTy TF(D.getAnalysisData());
// Process the worklist until it is empty. // Process the worklist until it is empty.
while (!WorkList.isEmpty()) { while (!WorkList.isEmpty()) {
@ -131,7 +130,7 @@ private:
WorkList.enqueue(&cfg.getExit()); WorkList.enqueue(&cfg.getExit());
// Create the state for transfer functions. // Create the state for transfer functions.
TransferFuncsTy TF(D.getMetaData(),O); TransferFuncsTy TF(D.getAnalysisData());
// Process the worklist until it is empty. // Process the worklist until it is empty.
while (!WorkList.isEmpty()) { while (!WorkList.isEmpty()) {
@ -213,7 +212,6 @@ private:
private: private:
DFValuesTy& D; DFValuesTy& D;
ObserverTy* O;
}; };

View File

@ -24,26 +24,30 @@ using namespace clang;
namespace { namespace {
class RegisterDecls : public CFGVarDeclVisitor<RegisterDecls> { class RegisterDeclsAndExprs : public CFGVarDeclVisitor<RegisterDeclsAndExprs> {
UninitializedValues::MetaDataTy& M; UninitializedValues::AnalysisDataTy& AD;
public: public:
RegisterDecls(const CFG& cfg, UninitializedValues::MetaDataTy& m) : RegisterDeclsAndExprs(const CFG& cfg, UninitializedValues::AnalysisDataTy& ad)
CFGVarDeclVisitor<RegisterDecls>(cfg), M(m) {} : CFGVarDeclVisitor<RegisterDeclsAndExprs>(cfg), AD(ad)
{}
void VisitVarDecl(VarDecl* D) { void VisitVarDecl(VarDecl* D) {
if (M.Map.find(D) == M.Map.end()) { if (AD.VMap.find(D) == AD.VMap.end())
M.Map[D] = M.NumDecls++; AD.VMap[D] = AD.Counter++;
} }
void BlockStmt_VisitExpr(Expr* E) {
if (AD.EMap.find(E) == AD.EMap.end())
AD.EMap[E] = AD.Counter++;
} }
}; };
} // end anonymous namespace } // end anonymous namespace
void UninitializedValues::InitializeValues(const CFG& cfg) { void UninitializedValues::InitializeValues(const CFG& cfg) {
RegisterDecls R(cfg,this->getMetaData()); RegisterDeclsAndExprs R(cfg,this->getAnalysisData());
R.VisitAllDecls(); R.VisitAllDecls();
getBlockDataMap()[ &cfg.getEntry() ].resize( getAnalysisData().Counter );
getBlockDataMap()[ &cfg.getEntry() ].resize( getMetaData().NumDecls );
} }
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
@ -53,15 +57,17 @@ void UninitializedValues::InitializeValues(const CFG& cfg) {
namespace { namespace {
class TransferFuncs : public CFGStmtVisitor<TransferFuncs,bool> { class TransferFuncs : public CFGStmtVisitor<TransferFuncs,bool> {
UninitializedValues::ValTy V; UninitializedValues::ValTy V;
UninitializedValues::MetaDataTy& M; UninitializedValues::AnalysisDataTy& AD;
UninitializedValues::ObserverTy* O;
public: public:
TransferFuncs(UninitializedValues::MetaDataTy& m, TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {
UninitializedValues::ObserverTy* o) : M(m), O(o) { V.resize(AD.Counter);
V.resize(M.NumDecls);
} }
UninitializedValues::ValTy& getVal() { return V; } UninitializedValues::ValTy& getVal() { return V; }
// bool VisitDeclRefExpr(DeclRefExpr* DR);
// bool VisitBinaryOperator(BinaryOperator* B);
// bool VisitUnaryOperator(UnaryOperator* U);
}; };
} // end anonymous namespace } // end anonymous namespace

View File

@ -28,7 +28,8 @@ static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S));
#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ #define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\
{ return\ { return\
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowStmt(S); } static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\
cast<Expr>(S)); }
template <typename ImplClass, typename RetTy=void> template <typename ImplClass, typename RetTy=void>
class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> {
@ -54,6 +55,10 @@ public:
} }
default: default:
if (isa<Expr>(S))
return
static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S));
else
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S);
} }
} }
@ -62,8 +67,12 @@ public:
DEFAULT_BLOCKSTMT_VISIT(StmtExpr) DEFAULT_BLOCKSTMT_VISIT(StmtExpr)
DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator)
RetTy BlockStmt_VisitImplicitControlFlowStmt(Stmt* S) { RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr* E) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E);
}
RetTy BlockStmt_VisitExpr(Expr* E) {
return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E);
} }
RetTy BlockStmt_VisitStmt(Stmt* S) { RetTy BlockStmt_VisitStmt(Stmt* S) {
@ -72,12 +81,12 @@ public:
RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) {
return return
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowStmt(B); static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
} }
RetTy BlockStmt_VisitComma(BinaryOperator* B) { RetTy BlockStmt_VisitComma(BinaryOperator* B) {
return return
static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowStmt(B); static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B);
} }
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//

View File

@ -15,7 +15,7 @@
#ifndef LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H #ifndef LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H
#define LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H #define LLVM_CLANG_ANALYSIS_CFG_VARDECL_VISITOR_H
#include "clang/AST/StmtVisitor.h" #include "clang/Analysis/CFGStmtVisitor.h"
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h" #include "clang/AST/Stmt.h"
#include "clang/AST/CFG.h" #include "clang/AST/CFG.h"
@ -23,7 +23,7 @@
namespace clang { namespace clang {
template <typename ImplClass> template <typename ImplClass>
class CFGVarDeclVisitor : public StmtVisitor<ImplClass> { class CFGVarDeclVisitor : public CFGStmtVisitor<ImplClass> {
const CFG& cfg; const CFG& cfg;
public: public:
CFGVarDeclVisitor(const CFG& c) : cfg(c) {} CFGVarDeclVisitor(const CFG& c) : cfg(c) {}

View File

@ -35,7 +35,7 @@ namespace dataflow {
} // end namespace dataflow } // end namespace dataflow
template <typename TypeClass, template <typename ValueTypes,
typename _AnalysisDirTag = dataflow::forward_analysis_tag > typename _AnalysisDirTag = dataflow::forward_analysis_tag >
class DataflowValues { class DataflowValues {
@ -44,10 +44,8 @@ class DataflowValues {
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
public: public:
typedef typename TypeClass::ValTy ValTy; typedef typename ValueTypes::ValTy ValTy;
typedef typename TypeClass::MetaDataTy MetaDataTy; typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
typedef typename TypeClass::ObserverTy ObserverTy;
typedef _AnalysisDirTag AnalysisDirTag; typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
@ -101,11 +99,12 @@ public:
BlockDataMapTy& getBlockDataMap() { return BlockDataMap; } BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; } const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
/// getMetaData - Retrieves the meta data associated with a dataflow analysis. /// getAnalysisData - Retrieves the meta data associated with a
/// dataflow analysis for analyzing a particular CFG.
/// This is typically consumed by transfer function code (via the solver). /// This is typically consumed by transfer function code (via the solver).
/// This can also be used by subclasses to interpret the dataflow values. /// This can also be used by subclasses to interpret the dataflow values.
MetaDataTy& getMetaData() { return Meta; } AnalysisDataTy& getAnalysisData() { return AnalysisData; }
const MetaDataTy& getMetaData() const { return Meta; } const AnalysisDataTy& getAnalysisData() const { return AnalysisData; }
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Internal data. // Internal data.
@ -113,7 +112,7 @@ public:
protected: protected:
BlockDataMapTy BlockDataMap; BlockDataMapTy BlockDataMap;
MetaDataTy Meta; AnalysisDataTy AnalysisData;
}; };
} // end namespace clang } // end namespace clang

View File

@ -21,10 +21,12 @@
namespace clang { namespace clang {
class VarDecl; class VarDecl;
class Expr;
/// UninitializedValuesTypes - Utility class to wrap type declarations /// UninitializedValues_ValueTypes - Utility class to wrap type declarations
/// used for defining the UninitializedValues class. /// for dataflow values and dataflow analysis state for the
class UninitializedValuesTypes { /// Unitialized Values analysis.
class UninitializedValues_ValueTypes {
public: public:
class ValTy { class ValTy {
llvm::BitVector BV; llvm::BitVector BV;
@ -41,25 +43,20 @@ public:
void copyValues(ValTy& RHS) { BV = RHS.BV; } void copyValues(ValTy& RHS) { BV = RHS.BV; }
}; };
struct MetaDataTy { struct AnalysisDataTy {
llvm::DenseMap<const VarDecl*, unsigned > Map; llvm::DenseMap<const VarDecl*, unsigned > VMap;
unsigned NumDecls; llvm::DenseMap<const Expr*, unsigned > EMap;
unsigned Counter;
MetaDataTy() : NumDecls(0) {} AnalysisDataTy() : Counter(0) {}
};
class ObserverTy {
virtual ~ObserverTy();
virtual void ObserveStmt(Stmt* S, MetaDataTy& M, ValTy& V) {}
virtual void ObserveBlockExit(const CFGBlock* B, MetaDataTy& M, ValTy& V) {}
}; };
}; };
/// UninitializedValues - Objects of this class encapsulate dataflow analysis /// UninitializedValues - Objects of this class encapsulate dataflow analysis
/// information regarding what variable declarations in a function are /// information regarding what variable declarations in a function are
/// potentially unintialized. /// potentially unintialized.
class UninitializedValues : public DataflowValues<UninitializedValuesTypes> { class UninitializedValues :
public DataflowValues<UninitializedValues_ValueTypes> {
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Public interface. // Public interface.