Further refactored DataflowSolver. Now most code for the solver is shared

between forward and backward analyses, with trait classes being used
to implement the key differences in operations/functionality.

Converted the LiveVariables analysis to use the generic DataflowSolver.  This,
along with removing some extra functionality that was not needed, reduced
the code for LiveVariables by over half.

Modified Driver code to handle the updated interface to LiveVariables.

Modified the DeadStores checker to handle the update interface to
LiveVariables.

Updated DataflowValues (generic ADT to store dataflow values) to also
store values for blocks.  This is used by DeadStores.  Updated some comments.

llvm-svn: 42293
This commit is contained in:
Ted Kremenek 2007-09-25 04:31:27 +00:00
parent 7e839f10cf
commit ad8bce02f0
8 changed files with 392 additions and 653 deletions

View File

@ -44,6 +44,61 @@ public:
bool isEmpty() const { return wlist.empty(); }
};
//===----------------------------------------------------------------------===//
// BlockItrTraits - Traits classes that allow transparent iteration over
// successors/predecessors of a block depending on the direction of our
// dataflow analysis.
namespace dataflow {
template<typename Tag> struct ItrTraits {};
template <> struct ItrTraits<forward_analysis_tag> {
typedef CFGBlock::const_pred_iterator PrevBItr;
typedef CFGBlock::const_succ_iterator NextBItr;
typedef CFGBlock::const_iterator StmtItr;
static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); }
static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); }
static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }
static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); }
static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
static CFG::Edge PrevEdge(const CFGBlock* B, const CFGBlock* PrevBlk) {
return CFG::Edge(PrevBlk,B);
}
static CFG::Edge NextEdge(const CFGBlock* B, const CFGBlock* NextBlk) {
return CFG::Edge(B,NextBlk);
}
};
template <> struct ItrTraits<backward_analysis_tag> {
typedef CFGBlock::const_succ_iterator PrevBItr;
typedef CFGBlock::const_pred_iterator NextBItr;
typedef CFGBlock::const_reverse_iterator StmtItr;
static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }
static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); }
static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }
static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }
static CFG::Edge PrevEdge(const CFGBlock* B, const CFGBlock* PrevBlk) {
return CFG::Edge(B,PrevBlk);
}
static CFG::Edge NextEdge(const CFGBlock* B, const CFGBlock* NextBlk) {
return CFG::Edge(NextBlk,B);
}
};
} // end namespace dataflow
//===----------------------------------------------------------------------===//
/// DataflowSolverTy - Generic dataflow solver.
template <typename _DFValuesTy, // Usually a subclass of DataflowValues
@ -57,14 +112,20 @@ class DataflowSolver {
//===--------------------------------------------------------------------===//
public:
typedef _DFValuesTy DFValuesTy;
typedef _TransferFuncsTy TransferFuncsTy;
typedef _MergeOperatorTy MergeOperatorTy;
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
typedef typename _DFValuesTy::ValTy ValTy;
typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
typedef _DFValuesTy DFValuesTy;
typedef _TransferFuncsTy TransferFuncsTy;
typedef _MergeOperatorTy MergeOperatorTy;
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
typedef typename _DFValuesTy::ValTy ValTy;
typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy;
typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits;
typedef typename ItrTraits::NextBItr NextBItr;
typedef typename ItrTraits::PrevBItr PrevBItr;
typedef typename ItrTraits::StmtItr StmtItr;
//===--------------------------------------------------------------------===//
// External interface: constructing and running the solver.
//===--------------------------------------------------------------------===//
@ -88,13 +149,18 @@ public:
/// only be used for querying the dataflow values within a block with
/// and Observer object.
void runOnBlock(const CFGBlock* B) {
if (hasData(B,AnalysisDirTag()))
ProcessBlock(B,AnalysisDirTag());
BlockDataMapTy& M = D.getBlockDataMap();
typename BlockDataMapTy::iterator I = M.find(B);
if (I != M.end()) {
TF.getVal().copyValues(I->second);
ProcessBlock(B);
}
}
void runOnBlock(const CFGBlock& B) { runOnBlock(&B); }
void runOnBlock(CFG::iterator &I) { runOnBlock(*I); }
void runOnBlock(CFG::const_iterator &I) { runOnBlock(*I); }
void runOnBlock(CFG::iterator& I) { runOnBlock(*I); }
void runOnBlock(CFG::const_iterator& I) { runOnBlock(*I); }
void runOnAllBlocks(const CFG& cfg) {
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
@ -110,17 +176,13 @@ private:
/// SolveDataflowEquations - Perform the actual
/// worklist algorithm to compute dataflow values.
void SolveDataflowEquations(const CFG& cfg) {
EnqueueFirstBlock(cfg,AnalysisDirTag());
// Process the worklist until it is empty.
while (!WorkList.isEmpty()) {
const CFGBlock* B = WorkList.dequeue();
// If the dataflow values at the block's entry have changed,
// enqueue all predecessor blocks onto the worklist to have
// their values updated.
ProcessBlock(B,AnalysisDirTag());
UpdateEdges(B,TF.getVal(),AnalysisDirTag());
ProcessMerge(B);
ProcessBlock(B);
UpdateEdges(B,TF.getVal());
}
}
@ -131,42 +193,8 @@ private:
void EnqueueFirstBlock(const CFG& cfg, dataflow::backward_analysis_tag) {
WorkList.enqueue(&cfg.getExit());
}
/// ProcessBlock (FORWARD ANALYSIS) - Process the transfer functions
/// for a given block based on a forward analysis.
void ProcessBlock(const CFGBlock* B, dataflow::forward_analysis_tag) {
// Merge dataflow values from all predecessors of this block.
ValTy& V = TF.getVal();
V.resetValues(D.getAnalysisData());
MergeOperatorTy Merge;
EdgeDataMapTy& M = D.getEdgeDataMap();
bool firstMerge = true;
for (CFGBlock::const_pred_iterator I=B->pred_begin(),
E=B->pred_end(); I!=E; ++I) {
typename EdgeDataMapTy::iterator BI = M.find(CFG::Edge(*I,B));
if (BI != M.end()) {
if (firstMerge) {
firstMerge = false;
V.copyValues(BI->second);
}
else
Merge(V,BI->second);
}
}
// Process the statements in the block in the forward direction.
for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I)
TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
}
/// ProcessBlock (BACKWARD ANALYSIS) - Process the transfer functions
/// for a given block based on a forward analysis.
void ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
dataflow::backward_analysis_tag) {
void ProcessMerge(const CFGBlock* B) {
// Merge dataflow values from all predecessors of this block.
ValTy& V = TF.getVal();
V.resetValues(D.getAnalysisData());
@ -174,59 +202,47 @@ private:
EdgeDataMapTy& M = D.getEdgeDataMap();
bool firstMerge = true;
for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
for (CFGBlock::const_succ_iterator I=B->succ_begin(),
E=B->succ_end(); I!=E; ++I) {
typename EdgeDataMapTy::iterator BI = M.find(CFG::Edge(B,*I));
if (BI != M.end()) {
typename EdgeDataMapTy::iterator EI = M.find(ItrTraits::PrevEdge(B,*I));
if (EI != M.end()) {
if (firstMerge) {
firstMerge = false;
V.copyValues(BI->second);
V.copyValues(EI->second);
}
else
Merge(V,BI->second);
else Merge(V,EI->second);
}
}
// Process the statements in the block in the forward direction.
for (CFGBlock::const_reverse_iterator I=B->begin(), E=B->end(); I!=E; ++I)
TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
// Set the data for the block.
D.getBlockDataMap()[B].copyValues(V);
}
/// ProcessBlock - Process the transfer functions for a given block.
void ProcessBlock(const CFGBlock* B) {
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E; ++I)
TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
}
/// UpdateEdges (FORWARD ANALYSIS) - After processing the transfer
/// UpdateEdges - After processing the transfer
/// functions for a block, update the dataflow value associated with the
/// block's outgoing edges. Enqueue any successor blocks for an
/// outgoing edge whose value has changed.
void UpdateEdges(const CFGBlock* B, ValTy& V,dataflow::forward_analysis_tag) {
for (CFGBlock::const_succ_iterator I=B->succ_begin(), E=B->succ_end();
I!=E; ++I) {
CFG::Edge Edg(B,*I);
UpdateEdgeValue(Edg,V,*I);
}
/// block's outgoing/incoming edges (depending on whether we do a
// forward/backward analysis respectively)
void UpdateEdges(const CFGBlock* B, ValTy& V) {
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
UpdateEdgeValue(ItrTraits::NextEdge(B,*I),V,*I);
}
/// UpdateEdges (BACKWARD ANALYSIS) - After processing the transfer
/// functions for a block, update the dataflow value associated with the
/// block's incoming edges. Enqueue any predecessor blocks for an
/// outgoing edge whose value has changed.
void UpdateEdges(const CFGBlock* B, ValTy& V,dataflow::backward_analysis_tag){
for (CFGBlock::const_pred_iterator I=B->succ_begin(), E=B->succ_end();
I!=E; ++I) {
CFG::Edge Edg(*I,B);
UpdateEdgeValue(Edg,V,*I);
}
}
/// UpdateEdgeValue - Update the value associated with a given edge.
void UpdateEdgeValue(CFG::Edge& E, ValTy& V, const CFGBlock* TargetBlock) {
void UpdateEdgeValue(CFG::Edge E, ValTy& V, const CFGBlock* TargetBlock) {
EdgeDataMapTy& M = D.getEdgeDataMap();
typename EdgeDataMapTy::iterator I = M.find(E);
if (I == M.end()) {
// First value for this edge.
if (I == M.end()) { // First computed value for this edge?
M[E].copyValues(V);
WorkList.enqueue(TargetBlock);
}
@ -235,33 +251,7 @@ private:
WorkList.enqueue(TargetBlock);
}
}
/// hasData (FORWARD ANALYSIS) - Is there any dataflow values associated
/// with the incoming edges of a block?
bool hasData(const CFGBlock* B, dataflow::forward_analysis_tag) {
EdgeDataMapTy& M = D.getEdgeDataMap();
for (CFGBlock::const_pred_iterator I=B->pred_begin(), E=B->pred_end();
I!=E; ++I)
if (M.find(CFG::Edge(*I,B)) != M.end())
return true;
return false;
}
/// hasData (BACKWARD ANALYSIS) - Is there any dataflow values associated
/// with the outgoing edges of a block?
bool hasData(const CFGBlock* B, dataflow::backward_analysis_tag) {
EdgeDataMapTy& M = D.getEdgeDataMap();
for (CFGBlock::const_succ_iterator I=B->succ_begin(), E=B->succ_end();
I!=E; ++I)
if (M.find(CFG::Edge(B,*I)) != M.end())
return true;
return false;
}
private:
DFValuesTy& D;
DataflowWorkListTy WorkList;

View File

@ -12,50 +12,57 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Expr.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/Analysis/LiveVariables.h"
#include "clang/AST/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/ASTContext.h"
#include "llvm/ADT/SmallPtrSet.h"
using namespace clang;
namespace {
class DeadStoreObserver : public LiveVariablesObserver {
class EverKilled : public LiveVariables::ObserverTy {
llvm::SmallPtrSet<const VarDecl*, 10> Killed;
public:
virtual void ObserveKill(DeclRefExpr* DR) {
Killed.insert(cast<VarDecl>(DR->getDecl()));
}
bool hasKill(const VarDecl* V) { return Killed.count(V) != 0; }
};
class DeadStoreObs : public LiveVariables::ObserverTy {
ASTContext &Ctx;
Diagnostic &Diags;
EverKilled EK;
public:
DeadStoreObserver(ASTContext &ctx, Diagnostic &diags)
: Ctx(ctx), Diags(diags) {
}
DeadStoreObs(ASTContext &ctx,Diagnostic &diags) : Ctx(ctx), Diags(diags){}
virtual ~DeadStoreObs() {}
virtual void ObserveStmt(Stmt* S,
const LiveVariables::AnalysisDataTy& AD,
const LiveVariables::ValTy& Live) {
virtual ~DeadStoreObserver() {}
virtual void ObserveStmt(Stmt* S, LiveVariables& L, llvm::BitVector& Live) {
if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
// Is this an assignment?
if (!B->isAssignmentOp())
return;
if (!B->isAssignmentOp()) return; // Skip non-assignments.
// Is this an assignment to a variable?
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
// Is the variable live?
if (!L.isLive(Live,cast<VarDecl>(DR->getDecl()))) {
// Is the variable NOT live? If so, flag a dead store.
if (!Live(AD,DR->getDecl())) {
SourceRange R = B->getRHS()->getSourceRange();
Diags.Report(DR->getSourceRange().Begin(), diag::warn_dead_store,
0, 0, &R, 1);
0, 0, &R, 1);
}
}
else if(DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
// Iterate through the decls. Warn if any of them (which have
// initializers) are not live.
else if(DeclStmt* DS = dyn_cast<DeclStmt>(S))
// Iterate through the decls. Warn if any initializers are complex
// expressions that are not live (never used).
for (VarDecl* V = cast<VarDecl>(DS->getDecl()); V != NULL ;
V = cast_or_null<VarDecl>(V->getNextDeclarator()))
if (Expr* E = V->getInit())
if (!L.isLive(Live,V))
V = cast_or_null<VarDecl>(V->getNextDeclarator())) {
if (Expr* E = V->getInit()) {
if (!Live(AD,DS->getDecl())) {
// Special case: check for initializations with constants.
//
// e.g. : int x = 0;
@ -63,14 +70,15 @@ public:
// If x is EVER assigned a new value later, don't issue
// a warning. This is because such initialization can be
// due to defensive programming.
if (!E->isConstantExpr(Ctx,NULL) ||
L.getVarInfo(V).Kills.size() == 0) {
if (!E->isConstantExpr(Ctx,NULL)) {
// Flag a warning.
SourceRange R = E->getSourceRange();
Diags.Report(V->getLocation(), diag::warn_dead_store, 0, 0,
&R,1);
}
}
}
}
}
}
};
@ -78,18 +86,11 @@ public:
namespace clang {
void CheckDeadStores(CFG& cfg, LiveVariables& L,
ASTContext &Ctx, Diagnostic &Diags) {
DeadStoreObserver A(Ctx, Diags);
for (CFG::iterator I = cfg.begin(), E = cfg.end(); I != E; ++I)
L.runOnBlock(&(*I),&A);
}
void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags) {
LiveVariables L;
L.runOnCFG(cfg);
CheckDeadStores(cfg,L, Ctx, Diags);
DeadStoreObs A(Ctx, Diags);
L.runOnAllBlocks(cfg,A);
}
} // end namespace clang

View File

@ -3,7 +3,8 @@
// The LLVM Compiler Infrastructure
//
// This file was developed by Ted Kremenek and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
// the University of Illinois Open Source License. See LICENSE.TXT for
// details.
//
//===----------------------------------------------------------------------===//
//
@ -15,7 +16,8 @@
#include "clang/Basic/SourceManager.h"
#include "clang/AST/Expr.h"
#include "clang/AST/CFG.h"
#include "clang/Analysis/Visitors/DataflowStmtVisitor.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "DataflowSolver.h"
#include "clang/Lex/IdentifierTable.h"
#include "llvm/ADT/SmallPtrSet.h"
@ -25,326 +27,136 @@
using namespace clang;
//===----------------------------------------------------------------------===//
// RegisterDecls - Utility class to create VarInfo objects for all
// Decls referenced in a function.
//
// Dataflow initialization logic.
//===----------------------------------------------------------------------===//
namespace {
struct RegisterDecls : public CFGRecStmtDeclVisitor<RegisterDecls> {
LiveVariables::AnalysisDataTy& AD;
void VisitVarDecl(VarDecl* VD) { AD.RegisterDecl(VD); }
class RegisterDecls : public StmtVisitor<RegisterDecls,void> {
LiveVariables& L;
const CFG& cfg;
public:
RegisterDecls(LiveVariables& l, const CFG& c)
: L(l), cfg(c) {}
void VisitStmt(Stmt* S);
void VisitDeclRefExpr(DeclRefExpr* DR);
void VisitDeclStmt(DeclStmt* DS);
void Register(ScopedDecl* D);
void RegisterDeclChain(ScopedDecl* D);
void RegisterUsedDecls();
};
void RegisterDecls::VisitStmt(Stmt* S) {
for (Stmt::child_iterator I = S->child_begin(),E = S->child_end(); I != E;++I)
Visit(*I);
}
void RegisterDecls::VisitDeclRefExpr(DeclRefExpr* DR) {
RegisterDeclChain(DR->getDecl());
}
void RegisterDecls::VisitDeclStmt(DeclStmt* DS) {
RegisterDeclChain(DS->getDecl());
}
void RegisterDecls::RegisterDeclChain(ScopedDecl* D) {
for (; D != NULL ; D = D->getNextDeclarator())
Register(D);
}
void RegisterDecls::Register(ScopedDecl* D) {
if (VarDecl* V = dyn_cast<VarDecl>(D)) {
LiveVariables::VPair& VP = L.getVarInfoMap()[V];
VP.V.AliveBlocks.resize(cfg.getNumBlockIDs());
VP.Idx = L.getNumDecls()++;
}
}
void RegisterDecls::RegisterUsedDecls() {
for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI)
for (CFGBlock::const_iterator SI=BI->begin(),SE = BI->end();SI != SE;++SI)
Visit(const_cast<Stmt*>(*SI));
}
RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// WorkList - Data structure representing the liveness algorithm worklist.
//
namespace {
class WorkListTy {
typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
BlockSet wlist;
public:
void enqueue(const CFGBlock* B) { wlist.insert(B); }
const CFGBlock* dequeue() {
assert (!wlist.empty());
const CFGBlock* B = *wlist.begin();
wlist.erase(B);
return B;
}
bool isEmpty() const { return wlist.empty(); }
};
} // end anonymous namespace
void LiveVariables::InitializeValues(const CFG& cfg) {
RegisterDecls R(getAnalysisData());
cfg.VisitBlockStmts(R);
}
//===----------------------------------------------------------------------===//
// TFuncs
//
// Transfer functions.
//===----------------------------------------------------------------------===//
namespace {
class LivenessTFuncs : public DataflowStmtVisitor<LivenessTFuncs,
dataflow::backward_analysis_tag> {
LiveVariables& L;
llvm::BitVector Live;
llvm::BitVector KilledAtLeastOnce;
Stmt* CurrentStmt;
const CFGBlock* CurrentBlock;
bool blockPreviouslyProcessed;
LiveVariablesObserver* Observer;
class TransferFuncs : public CFGStmtVisitor<TransferFuncs> {
LiveVariables::AnalysisDataTy& AD;
LiveVariables::ValTy Live;
public:
LivenessTFuncs(LiveVariables& l, LiveVariablesObserver* A = NULL)
: L(l), CurrentStmt(NULL), CurrentBlock(NULL),
blockPreviouslyProcessed(false), Observer(A) {
Live.resize(l.getNumDecls());
KilledAtLeastOnce.resize(l.getNumDecls());
}
TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
LiveVariables::ValTy& getVal() { return Live; }
void VisitDeclRefExpr(DeclRefExpr* DR);
void VisitBinaryOperator(BinaryOperator* B);
void VisitAssign(BinaryOperator* B);
void VisitDeclStmt(DeclStmt* DS);
void VisitUnaryOperator(UnaryOperator* U);
void ObserveStmt(Stmt* S);
unsigned getIdx(const VarDecl* D) {
LiveVariables::VarInfoMap& V = L.getVarInfoMap();
LiveVariables::VarInfoMap::iterator I = V.find(D);
assert (I != V.end());
return I->second.Idx;
void VisitStmt(Stmt* S) { VisitChildren(S); }
void Visit(Stmt *S) {
if (AD.Observer) AD.Observer->ObserveStmt(S,AD,Live);
static_cast<CFGStmtVisitor<TransferFuncs>*>(this)->Visit(S);
}
bool ProcessBlock(const CFGBlock* B);
llvm::BitVector* getBlockEntryLiveness(const CFGBlock* B);
LiveVariables::VarInfo& KillVar(VarDecl* D);
};
void LivenessTFuncs::ObserveStmt(Stmt* S) {
if (Observer) Observer->ObserveStmt(S,L,Live);
}
void LivenessTFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
// Register a use of the variable.
if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
Live.set(getIdx(V));
void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
Live.set(AD[V]); // Register a use of the variable.
}
void LivenessTFuncs::VisitBinaryOperator(BinaryOperator* B) {
void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
if (B->isAssignmentOp()) VisitAssign(B);
else VisitStmt(B);
}
void LivenessTFuncs::VisitUnaryOperator(UnaryOperator* U) {
void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) {
switch (U->getOpcode()) {
case UnaryOperator::PostInc:
case UnaryOperator::PostDec:
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
case UnaryOperator::AddrOf:
// Walk through the subexpressions, blasting through ParenExprs until
// we either find a DeclRefExpr or some non-DeclRefExpr expression.
for (Stmt* S = U->getSubExpr() ; ; ) {
if (ParenExpr* P = dyn_cast<ParenExpr>(S)) {
S = P->getSubExpr();
continue;
}
else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S)) {
// Treat the --/++/& operator as a kill.
LiveVariables::VarInfo& V =
KillVar(cast<VarDecl>(DR->getDecl()));
case UnaryOperator::PostInc:
case UnaryOperator::PostDec:
case UnaryOperator::PreInc:
case UnaryOperator::PreDec:
case UnaryOperator::AddrOf:
// Walk through the subexpressions, blasting through ParenExprs
// until we either find a DeclRefExpr or some non-DeclRefExpr
// expression.
for (Stmt* S = U->getSubExpr() ;;) {
if (ParenExpr* P = dyn_cast<ParenExpr>(S)) { S=P->getSubExpr(); continue;}
else if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(S)) {
// Treat the --/++/& operator as a kill.
Live.reset(AD[DR->getDecl()]);
if (AD.Observer) AD.Observer->ObserverKill(DR);
VisitDeclRefExpr(DR);
}
else Visit(S);
if (!blockPreviouslyProcessed)
V.AddKill(CurrentStmt,DR);
VisitDeclRefExpr(DR);
}
else Visit(S);
break;
}
break;
default:
Visit(U->getSubExpr());
break;
break;
}
break;
default:
Visit(U->getSubExpr());
break;
}
}
LiveVariables::VarInfo& LivenessTFuncs::KillVar(VarDecl* D) {
LiveVariables::VarInfoMap::iterator I = L.getVarInfoMap().find(D);
assert (I != L.getVarInfoMap().end() &&
"Declaration not managed by variable map in LiveVariables");
// Mark the variable dead, and remove the current block from
// the set of blocks where the variable may be alive the entire time.
Live.reset(I->second.Idx);
I->second.V.AliveBlocks.reset(CurrentBlock->getBlockID());
return I->second.V;
}
void LivenessTFuncs::VisitAssign(BinaryOperator* B) {
// Check if we are assigning to a variable.
void TransferFuncs::VisitAssign(BinaryOperator* B) {
Stmt* LHS = B->getLHS();
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) {
LiveVariables::VarInfo& V = KillVar(cast<VarDecl>(DR->getDecl()));
// We only need to register kills once, so we check if this block
// has been previously processed.
if (!blockPreviouslyProcessed)
V.AddKill(CurrentStmt,DR);
if (B->getOpcode() != BinaryOperator::Assign)
Visit(LHS);
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS)) { // Assigning to a var?
Live.reset(AD[DR->getDecl()]);
if (AD.Observer) AD.Observer->ObserverKill(DR);
// Handle things like +=, etc., which also generate "uses"
// of a variable. Do this just by visiting the subexpression.
if (B->getOpcode() != BinaryOperator::Assign) Visit(LHS);
}
else
else // Not assigning to a variable. Process LHS as usual.
Visit(LHS);
Visit(B->getRHS());
Visit(B->getRHS());
}
void LivenessTFuncs::VisitDeclStmt(DeclStmt* DS) {
// Declarations effectively "kill" a variable since they cannot possibly
// be live before they are declared. Declarations, however, are not kills
// in the sense that the value is obliterated, so we do not register
// DeclStmts as a "kill site" for a variable.
void TransferFuncs::VisitDeclStmt(DeclStmt* DS) {
// Declarations effectively "kill" a variable since they cannot
// possibly be live before they are declared.
for (ScopedDecl* D = DS->getDecl(); D != NULL ; D = D->getNextDeclarator())
KillVar(cast<VarDecl>(D));
Live.reset(AD[D]);
}
llvm::BitVector* LivenessTFuncs::getBlockEntryLiveness(const CFGBlock* B) {
LiveVariables::BlockLivenessMap& BMap = L.getLiveAtBlockEntryMap();
LiveVariables::BlockLivenessMap::iterator I = BMap.find(B);
return (I == BMap.end()) ? NULL : &(I->second);
}
bool LivenessTFuncs::ProcessBlock(const CFGBlock* B) {
CurrentBlock = B;
Live.reset();
KilledAtLeastOnce.reset();
// Check if this block has been previously processed.
LiveVariables::BlockLivenessMap& BMap = L.getLiveAtBlockEntryMap();
LiveVariables::BlockLivenessMap::iterator BI = BMap.find(B);
blockPreviouslyProcessed = BI != BMap.end();
// Merge liveness information from all predecessors.
for (CFGBlock::const_succ_iterator I=B->succ_begin(),E=B->succ_end();I!=E;++I)
if (llvm::BitVector* V = getBlockEntryLiveness(*I))
Live |= *V;
if (Observer)
Observer->ObserveBlockExit(B,L,Live);
// Tentatively mark all variables alive at the end of the current block
// as being alive during the whole block. We then cull these out as
// we process the statements of this block.
for (LiveVariables::VarInfoMap::iterator
I=L.getVarInfoMap().begin(), E=L.getVarInfoMap().end(); I != E; ++I)
if (Live[I->second.Idx])
I->second.V.AliveBlocks.set(B->getBlockID());
// Visit the statements in reverse order;
VisitBlock(B);
// Compare the computed "Live" values with what we already have
// for the entry to this block.
bool hasChanged = false;
if (!blockPreviouslyProcessed) {
// We have not previously calculated liveness information for this block.
// Lazily instantiate a bitvector, and copy the bits from Live.
hasChanged = true;
llvm::BitVector& V = BMap[B];
V.resize(L.getNumDecls());
V = Live;
}
else if (BI->second != Live) {
hasChanged = true;
BI->second = Live;
}
return hasChanged;
}
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// runOnCFG - Method to run the actual liveness computation.
//
namespace {
struct Merge {
void operator()(LiveVariables::ValTy& Dst, LiveVariables::ValTy& Src) {
Src |= Dst;
}
};
} // end anonymous namespace
void LiveVariables::runOnCFG(const CFG& cfg, LiveVariablesObserver* Observer) {
// Scan a CFG for DeclRefStmts. For each one, create a VarInfo object.
{
RegisterDecls R(*this,cfg);
R.RegisterUsedDecls();
}
// Create the worklist and enqueue the exit block.
WorkListTy WorkList;
WorkList.enqueue(&cfg.getExit());
// Create the state for transfer functions.
LivenessTFuncs TF(*this,Observer);
// Process the worklist until it is empty.
while (!WorkList.isEmpty()) {
const CFGBlock* B = WorkList.dequeue();
if (TF.ProcessBlock(B))
for (CFGBlock::const_pred_iterator I = B->pred_begin(), E = B->pred_end();
I != E; ++I)
WorkList.enqueue(*I);
}
// Go through each block and reserve a bitvector. This is needed if
// a block was never visited by the worklist algorithm.
for (CFG::const_iterator I = cfg.begin(), E = cfg.end(); I != E; ++I)
LiveAtBlockEntryMap[&(*I)].resize(NumDecls);
namespace {
typedef DataflowSolver<LiveVariables,TransferFuncs,Merge> Solver;
}
void LiveVariables::runOnCFG(const CFG& cfg) {
Solver S(*this);
S.runOnCFG(cfg);
}
void LiveVariables::runOnBlock(const CFGBlock* B,
LiveVariablesObserver* Observer)
{
LivenessTFuncs TF(*this,Observer);
TF.ProcessBlock(B);
void LiveVariables::runOnAllBlocks(const CFG& cfg,
LiveVariables::ObserverTy& Obs) {
Solver S(*this);
ObserverTy* OldObserver = getAnalysisData().Observer;
getAnalysisData().Observer = &Obs;
S.runOnAllBlocks(cfg);
getAnalysisData().Observer = OldObserver;
}
//===----------------------------------------------------------------------===//
@ -352,81 +164,36 @@ void LiveVariables::runOnBlock(const CFGBlock* B,
//
bool LiveVariables::isLive(const CFGBlock* B, const VarDecl* D) const {
BlockLivenessMap::const_iterator I = LiveAtBlockEntryMap.find(B);
assert (I != LiveAtBlockEntryMap.end());
VarInfoMap::const_iterator VI = VarInfos.find(D);
assert (VI != VarInfos.end());
return I->second[VI->second.Idx];
return getBlockData(B)[ getAnalysisData()[D] ];
}
bool LiveVariables::isLive(llvm::BitVector& Live, const VarDecl* D) const {
VarInfoMap::const_iterator VI = VarInfos.find(D);
assert (VI != VarInfos.end());
return Live[VI->second.Idx];
bool LiveVariables::isLive(const ValTy& Live, const VarDecl* D) const {
return Live[ getAnalysisData()[D] ];
}
bool LiveVariables::KillsVar(const Stmt* S, const VarDecl* D) const {
VarInfoMap::const_iterator VI = VarInfos.find(D);
assert (VI != VarInfos.end());
for (VarInfo::KillsSet::const_iterator
I = VI->second.V.Kills.begin(), E = VI->second.V.Kills.end(); I!=E;++I)
if (I->first == S)
return true;
return false;
}
LiveVariables::VarInfo& LiveVariables::getVarInfo(const VarDecl* D) {
VarInfoMap::iterator VI = VarInfos.find(D);
assert (VI != VarInfos.end());
return VI->second.V;
}
const LiveVariables::VarInfo& LiveVariables::getVarInfo(const VarDecl* D) const{
return const_cast<LiveVariables*>(this)->getVarInfo(D);
}
//===----------------------------------------------------------------------===//
// Defaults for LiveVariablesObserver
void LiveVariablesObserver::ObserveStmt(Stmt* S, LiveVariables& L,
llvm::BitVector& V) {}
void LiveVariablesObserver::ObserveBlockExit(const CFGBlock* B,
LiveVariables& L,
llvm::BitVector& V) {}
//===----------------------------------------------------------------------===//
// printing liveness state for debugging
//
void LiveVariables::dumpLiveness(const llvm::BitVector& V,
SourceManager& SM) const {
for (VarInfoMap::iterator I = VarInfos.begin(), E=VarInfos.end(); I!=E; ++I) {
if (V[I->second.Idx]) {
void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
const AnalysisDataTy& AD = getAnalysisData();
for (AnalysisDataTy::iterator I = AD.begin(), E = AD.end(); I!=E; ++I)
if (V[I->second]) {
SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());
fprintf(stderr, " %s <%s:%u:%u>\n",
I->first->getIdentifier()->getName(),
SM.getSourceName(PhysLoc),
SM.getLineNumber(PhysLoc),
SM.getColumnNumber(PhysLoc));
}
}
}
void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
for (BlockLivenessMap::iterator I = LiveAtBlockEntryMap.begin(),
E = LiveAtBlockEntryMap.end();
I != E; ++I) {
fprintf(stderr,
"\n[ B%d (live variables at block entry) ]\n",
for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
E = getBlockDataMap().end(); I!=E; ++I) {
fprintf(stderr, "\n[ B%d (live variables at block exit) ]\n",
I->first->getBlockID());
dumpLiveness(I->second,M);
@ -434,41 +201,3 @@ void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
fprintf(stderr,"\n");
}
void LiveVariables::dumpVarLiveness(SourceManager& SM) const {
for (VarInfoMap::iterator I = VarInfos.begin(), E=VarInfos.end(); I!=E; ++I) {
SourceLocation PhysLoc = SM.getPhysicalLoc(I->first->getLocation());
fprintf(stderr, "[ %s <%s:%u:%u> ]\n",
I->first->getIdentifier()->getName(),
SM.getSourceName(PhysLoc),
SM.getLineNumber(PhysLoc),
SM.getColumnNumber(PhysLoc));
I->second.V.Dump(SM);
}
}
void LiveVariables::VarInfo::Dump(SourceManager& SM) const {
fprintf(stderr," Blocks Alive:");
for (unsigned i = 0; i < AliveBlocks.size(); ++i) {
if (i % 5 == 0)
fprintf(stderr,"\n ");
fprintf(stderr," B%d", i);
}
fprintf(stderr,"\n Kill Sites:\n");
for (KillsSet::const_iterator I = Kills.begin(), E = Kills.end(); I!=E; ++I) {
SourceLocation PhysLoc =
SM.getPhysicalLoc(I->second->getSourceRange().Begin());
fprintf(stderr, " <%s:%u:%u>\n",
SM.getSourceName(PhysLoc),
SM.getLineNumber(PhysLoc),
SM.getColumnNumber(PhysLoc));
}
fprintf(stderr,"\n");
}

View File

@ -224,8 +224,7 @@ namespace {
virtual void VisitCFG(CFG& C) {
LiveVariables L;
L.runOnCFG(C);
L.dumpBlockLiveness(*SM);
L.dumpVarLiveness(*SM);
L.dumpBlockLiveness(*SM);
}
};
} // end anonymous namespace

View File

@ -64,7 +64,6 @@ namespace dataflow {
struct forward_analysis_tag {};
struct backward_analysis_tag {};
} // end namespace dataflow
//===----------------------------------------------------------------------===//
/// DataflowValues. Container class to store dataflow values for a CFG.
@ -83,6 +82,7 @@ public:
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<CFG::Edge, ValTy> EdgeDataMapTy;
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
//===--------------------------------------------------------------------===//
// Predicates.
@ -110,10 +110,9 @@ public:
/// dataflow analysis. This method is usually specialized by subclasses.
void InitializeValues(const CFG& cfg) {};
/// getEdgeData - Retrieves the dataflow values associated with a
/// specified CFGBlock. If the dataflow analysis is a forward analysis,
/// this data is associated with the END of the block. If the analysis
/// is a backwards analysis, it is associated with the ENTRY of the block.
/// getEdgeData - Retrieves the dataflow values associated with a
/// CFG edge.
ValTy& getEdgeData(const CFG::Edge& E) {
typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
assert (I != EdgeDataMap.end() && "No data associated with Edge.");
@ -123,13 +122,35 @@ public:
const ValTy& getEdgeData(const CFG::Edge& E) const {
return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
}
/// getBlockData - Retrieves the dataflow values associated with a
/// specified CFGBlock. If the dataflow analysis is a forward analysis,
/// this data is associated with the END of the block. If the analysis
/// is a backwards analysis, it is associated with the ENTRY of the block.
ValTy& getBlockData(const CFGBlock* B) {
typename BlockDataMapTy::iterator I = BlockDataMap.find(B);
assert (I != BlockDataMap.end() && "No data associated with block.");
return I->second;
}
/// getEdgeDataMap - Retrieves the internal map between CFGBlocks and
const ValTy& getBlockData(const CFGBlock* B) const {
return const_cast<DataflowValues*>(this)->getBlockData(B);
}
/// getEdgeDataMap - Retrieves the internal map between CFG edges and
/// dataflow values. Usually used by a dataflow solver to compute
/// values for blocks.
EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; }
const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; }
/// getBlockDataMap - Retrieves the internal map between CFGBlocks and
/// dataflow values. If the dataflow analysis operates in the forward
/// direction, the values correspond to the dataflow values at the start
/// of the block. Otherwise, for a backward analysis, the values correpsond
/// to the dataflow values at the end of the block.
BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
/// 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).
@ -143,6 +164,7 @@ public:
protected:
EdgeDataMapTy EdgeDataMap;
BlockDataMapTy BlockDataMap;
AnalysisDataTy AnalysisData;
};

View File

@ -14,139 +14,137 @@
#ifndef LLVM_CLANG_LIVEVARIABLES_H
#define LLVM_CLANG_LIVEVARIABLES_H
#include "clang/AST/Decl.h"
#include "clang/Analysis/DataflowValues.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
namespace clang {
class Stmt;
class DeclRefExpr;
class VarDecl;
class CFG;
class CFGBlock;
class SourceManager;
class LiveVariables;
class Stmt;
class DeclRefExpr;
class SourceManager;
class LiveVariablesObserver {
public:
virtual ~LiveVariablesObserver() {}
struct LiveVariables_ValueTypes {
//===-----------------------------------------------------===//
// AnalysisDataTy - Whole-function analysis meta data.
//===-----------------------------------------------------===//
/// ObserveStmt - A callback invoked right before invoking the liveness
/// transfer function on the given statement. If the liveness information
/// has been previously calculated by running LiveVariables::runOnCFG,
/// then V contains the liveness information after the execution of
/// the given statement.
virtual void ObserveStmt(Stmt* S, LiveVariables& L, llvm::BitVector& V);
/// ObserveBlockExit - A callback invoked right before invoking the liveness
/// transfer function on the given block. If the liveness information
/// has been previously calculated by running LiveVariables::runOnCFG,
/// then V contains the liveness information after the execution of
/// the given block.
virtual void ObserveBlockExit(const CFGBlock* B, LiveVariables& L,
llvm::BitVector& V);
};
class LiveVariables {
public:
struct VarInfo {
/// AliveBlocks - Set of blocks of which this value is alive completely
/// through. This is a bit set which uses the basic block number as an
/// index.
llvm::BitVector AliveBlocks;
class ObserverTy;
class AnalysisDataTy {
typedef llvm::DenseMap<const VarDecl*, unsigned> VMapTy;
VMapTy M;
unsigned NDecls;
public:
ObserverTy* Observer;
/// Kills - List of statements which are the last use of a variable
/// (kill it) in their basic block. The first pointer in the pair
/// is the statement in the list of statements of a basic block where
/// this occurs, while the DeclRefExpr is the subexpression of this
/// statement where the actual last reference takes place.
typedef std::vector< std::pair<const Stmt*,const DeclRefExpr*> > KillsSet;
KillsSet Kills;
AnalysisDataTy() : NDecls(0), Observer(NULL) {}
// AddKill - Adds a kill site to the list of places where a
// a variable is killed.
void AddKill(Stmt* S, DeclRefExpr* DR) {
Kills.push_back(std::make_pair(const_cast<const Stmt*>(S),
const_cast<const DeclRefExpr*>(DR)));
bool Tracked(const VarDecl* VD) const { return M.find(VD) != M.end(); }
void RegisterDecl(const VarDecl* VD) { if (!Tracked(VD)) M[VD] = NDecls++; }
unsigned operator[](const VarDecl* VD) const {
VMapTy::const_iterator I = M.find(VD);
assert (I != M.end());
return I->second;
}
// Dump - prints VarInfo data to stderr.
void Dump(SourceManager& M) const;
};
struct VPair {
VarInfo V;
unsigned Idx;
};
typedef llvm::DenseMap<const VarDecl*, VPair > VarInfoMap;
typedef llvm::DenseMap<const CFGBlock*, llvm::BitVector > BlockLivenessMap;
unsigned operator[](const ScopedDecl* S) const {
return (*this)[cast<VarDecl>(S)];
}
unsigned getNumDecls() const { return NDecls; }
typedef VMapTy::const_iterator iterator;
iterator begin() const { return M.begin(); }
iterator end() const { return M.end(); }
};
//===-----------------------------------------------------===//
// ValTy - Dataflow value.
//===-----------------------------------------------------===//
class ValTy {
llvm::BitVector V;
public:
void copyValues(const ValTy& RHS) { V = RHS.V; }
bool operator==(const ValTy& RHS) const { return V == RHS.V; }
void resetValues(const AnalysisDataTy& AD) {
V.resize(AD.getNumDecls());
V.reset();
}
llvm::BitVector::reference operator[](unsigned i) {
assert (i < V.size() && "Liveness bitvector access is out-of-bounds.");
return V[i];
}
const llvm::BitVector::reference operator[](unsigned i) const {
return const_cast<ValTy&>(*this)[i];
}
bool operator()(const AnalysisDataTy& AD, const ScopedDecl* D) const {
return (*this)[AD[D]];
}
ValTy& operator|=(ValTy& RHS) { V |= RHS.V; return *this; }
void set(unsigned i) { V.set(i); }
void reset(unsigned i) { V.reset(i); }
};
//===-----------------------------------------------------===//
// ObserverTy - Observer for uninitialized values queries.
//===-----------------------------------------------------===//
class ObserverTy {
public:
virtual ~ObserverTy() {}
/// ObserveStmt - A callback invoked right before invoking the
/// liveness transfer function on the given statement.
virtual void ObserveStmt(Stmt* S, const AnalysisDataTy& AD,
const ValTy& V) {}
virtual void ObserverKill(DeclRefExpr* DR) {}
};
};
class LiveVariables : public DataflowValues<LiveVariables_ValueTypes,
dataflow::backward_analysis_tag> {
public:
LiveVariables() : NumDecls(0) {}
/// runOnCFG - Computes live variable information for a given CFG.
void runOnCFG(const CFG& cfg, LiveVariablesObserver* A = NULL);
typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
LiveVariables() {}
/// runOnBlock - Computes live variable information for a given block.
/// This should usually be invoked only after previously computing
/// live variable information using runOnCFG, and is intended to
/// only be used for auditing the liveness within a block.
void runOnBlock(const CFGBlock* B, LiveVariablesObserver* A);
/// KillsVar - Return true if the specified statement kills the
/// specified variable.
bool KillsVar(const Stmt* S, const VarDecl* D) const;
/// IsLive - Return true if a variable is live at beginning of a specified
// block.
/// IsLive - Return true if a variable is live at beginning of a
/// specified block.
bool isLive(const CFGBlock* B, const VarDecl* D) const;
/// IsLive - Return true if a variable is live according to the provided
/// livness bitvector. This is typically used by classes that subclass
/// LiveVariablesObserver.
bool isLive(llvm::BitVector& V, const VarDecl* D) const;
/// IsLive - Return true if a variable is live according to the
/// provided livness bitvector.
bool isLive(const ValTy& V, const VarDecl* D) const;
/// getVarInfo - Return the liveness information associated with a given
/// variable.
VarInfo& getVarInfo(const VarDecl* D);
const VarInfo& getVarInfo(const VarDecl* D) const;
/// dumpLiveness - Print to stderr the liveness information encoded
/// by a specified bitvector.
void dumpLiveness(const ValTy& V, SourceManager& M) const;
/// getVarInfoMap
VarInfoMap& getVarInfoMap() { return VarInfos; }
const VarInfoMap& getVarInfoMap() const { return VarInfos; }
// dumpLiveness
void dumpLiveness(const llvm::BitVector& V, SourceManager& M) const;
// dumpBlockLiveness
/// dumpBlockLiveness - Print to stderr the liveness information
/// associated with each basic block.
void dumpBlockLiveness(SourceManager& M) const;
// dumpVarLiveness
void dumpVarLiveness(SourceManager& M) const;
// getLiveAtBlockEntryMap
BlockLivenessMap& getLiveAtBlockEntryMap() { return LiveAtBlockEntryMap; }
const BlockLivenessMap& getLiveAtBlockEntryMap() const {
return LiveAtBlockEntryMap;
}
// getNumDecls
unsigned& getNumDecls() { return NumDecls; }
unsigned getNumDecls() const { return NumDecls; }
protected:
unsigned NumDecls;
VarInfoMap VarInfos;
BlockLivenessMap LiveAtBlockEntryMap;
/// getNumDecls - Return the number of variables (declarations) that
/// whose liveness status is being tracked by the dataflow
/// analysis.
unsigned getNumDecls() const { return getAnalysisData().getNumDecls(); }
/// IntializeValues - Create initial dataflow values and meta data for
/// a given CFG. This is intended to be called by the dataflow solver.
void InitializeValues(const CFG& cfg);
void runOnCFG(const CFG& cfg);
void runOnAllBlocks(const CFG& cfg, ObserverTy& Obs);
};
} // end namespace clang

View File

@ -18,14 +18,10 @@
namespace clang {
class CFG;
class LiveVariables;
class Diagnostic;
void CheckDeadStores(CFG& cfg, LiveVariables& L,
ASTContext &Ctx, Diagnostic &Diags);
void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags);
class ASTContext;
void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags);
void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags);

View File

@ -26,7 +26,10 @@ static_cast<ImplClass*>(this)->Visit##CLASS(static_cast<CLASS*>(D));\
break;
#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS(CLASS* D) {}
#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS(CLASS* D)\
{ static_cast<ImplClass*>(this)->Visit##VarDecl(D); }
namespace clang {
template <typename ImplClass>
class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> {
@ -66,10 +69,11 @@ public:
}
}
DEFAULT_DISPATCH(VarDecl)
DEFAULT_DISPATCH(FunctionDecl)
DEFAULT_DISPATCH(BlockVarDecl)
DEFAULT_DISPATCH(FileVarDecl)
DEFAULT_DISPATCH(ParmVarDecl)
DEFAULT_DISPATCH_VARDECL(BlockVarDecl)
DEFAULT_DISPATCH_VARDECL(FileVarDecl)
DEFAULT_DISPATCH_VARDECL(ParmVarDecl)
DEFAULT_DISPATCH(EnumConstantDecl)
DEFAULT_DISPATCH(TypedefDecl)
DEFAULT_DISPATCH(RecordDecl)