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
//===--------------------------------------------------------------------===//
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.
//===--------------------------------------------------------------------===//
/// 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)
/// 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());
}
}
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());
EdgeDataMapTy& M = D.getEdgeDataMap();
bool firstMerge = true;
+
+ for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
+
+ typename EdgeDataMapTy::iterator EI = M.find(ItrTraits::PrevEdge(B,*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()) {
+ 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);
}
+
- /// UpdateEdges (FORWARD ANALYSIS) - 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);
- }
+ /// 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 (BACKWARD ANALYSIS) - After processing the transfer
+
+ /// UpdateEdges - 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);
- }
+ /// 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);
}
-
+
/// 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);
}
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;
//
//===----------------------------------------------------------------------===//
-#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;
// 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);
}
- }
+ }
+ }
+ }
}
};
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
// 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.
//
//===----------------------------------------------------------------------===//
//
#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"
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()++;
- }
-}
+ RegisterDecls(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
+};
+} // end anonymous namespace
-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));
+void LiveVariables::InitializeValues(const CFG& cfg) {
+ RegisterDecls R(getAnalysisData());
+ cfg.VisitBlockStmts(R);
}
-
-
-} // end anonymous namespace
//===----------------------------------------------------------------------===//
-// WorkList - Data structure representing the liveness algorithm worklist.
-//
+// Transfer functions.
+//===----------------------------------------------------------------------===//
namespace {
-
-class WorkListTy {
- typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
- BlockSet wlist;
+class TransferFuncs : public CFGStmtVisitor<TransferFuncs> {
+ LiveVariables::AnalysisDataTy& AD;
+ LiveVariables::ValTy Live;
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
+ TransferFuncs(LiveVariables::AnalysisDataTy& ad) : AD(ad) {}
-//===----------------------------------------------------------------------===//
-// TFuncs
-//
-
-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;
-
-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());
- }
+ 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()));
-
- if (!blockPreviouslyProcessed)
- V.AddKill(CurrentStmt,DR);
-
- VisitDeclRefExpr(DR);
- }
- else Visit(S);
-
- break;
- }
- break;
-
- default:
- Visit(U->getSubExpr());
- break;
+ 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);
+
+ 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]);
}
+} // end anonymous namespace
-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;
+namespace {
+struct Merge {
+ void operator()(LiveVariables::ValTy& Dst, LiveVariables::ValTy& Src) {
+ Src |= Dst;
}
-
- return hasChanged;
-}
-
+};
} // end anonymous namespace
-//===----------------------------------------------------------------------===//
-// runOnCFG - Method to run the actual liveness computation.
-//
-
-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;
}
//===----------------------------------------------------------------------===//
//
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);
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");
-}
virtual void VisitCFG(CFG& C) {
LiveVariables L;
L.runOnCFG(C);
- L.dumpBlockLiveness(*SM);
- L.dumpVarLiveness(*SM);
+ L.dumpBlockLiveness(*SM);
}
};
} // end anonymous namespace
struct forward_analysis_tag {};
struct backward_analysis_tag {};
} // end namespace dataflow
-
//===----------------------------------------------------------------------===//
/// DataflowValues. Container class to store dataflow values for a CFG.
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<CFG::Edge, ValTy> EdgeDataMapTy;
+ typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
//===--------------------------------------------------------------------===//
// Predicates.
/// 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.");
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;
+ }
+
+ const ValTy& getBlockData(const CFGBlock* B) const {
+ return const_cast<DataflowValues*>(this)->getBlockData(B);
+ }
- /// getEdgeDataMap - Retrieves the internal map between CFGBlocks and
+ /// 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).
protected:
EdgeDataMapTy EdgeDataMap;
+ BlockDataMapTy BlockDataMap;
AnalysisDataTy AnalysisData;
};
#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);
+ class ObserverTy;
+
+ class AnalysisDataTy {
+ typedef llvm::DenseMap<const VarDecl*, unsigned> VMapTy;
+ VMapTy M;
+ unsigned NDecls;
+ public:
+ ObserverTy* Observer;
+
+ AnalysisDataTy() : NDecls(0), Observer(NULL) {}
+
+ bool Tracked(const VarDecl* VD) const { return M.find(VD) != M.end(); }
+ void RegisterDecl(const VarDecl* VD) { if (!Tracked(VD)) M[VD] = NDecls++; }
- /// 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);
-};
+ unsigned operator[](const VarDecl* VD) const {
+ VMapTy::const_iterator I = M.find(VD);
+ assert (I != M.end());
+ return I->second;
+ }
+
+ unsigned operator[](const ScopedDecl* S) const {
+ return (*this)[cast<VarDecl>(S)];
+ }
-class LiveVariables {
-public:
+ 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; }
- 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;
+ bool operator==(const ValTy& RHS) const { return V == RHS.V; }
- /// 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;
+ 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];
+ }
- // 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)));
+ const llvm::BitVector::reference operator[](unsigned i) const {
+ return const_cast<ValTy&>(*this)[i];
}
- // Dump - prints VarInfo data to stderr.
- void Dump(SourceManager& M) const;
+ 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); }
};
- struct VPair {
- VarInfo V;
- unsigned Idx;
+ //===-----------------------------------------------------===//
+ // 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) {}
};
-
- typedef llvm::DenseMap<const VarDecl*, VPair > VarInfoMap;
- typedef llvm::DenseMap<const CFGBlock*, llvm::BitVector > BlockLivenessMap;
+};
+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);
-
- /// 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;
+ typedef LiveVariables_ValueTypes::ObserverTy ObserverTy;
+
+ LiveVariables() {}
- /// 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;
-
- /// getVarInfo - Return the liveness information associated with a given
- /// variable.
- VarInfo& getVarInfo(const VarDecl* D);
-
- const VarInfo& getVarInfo(const VarDecl* D) const;
-
- /// getVarInfoMap
- VarInfoMap& getVarInfoMap() { return VarInfos; }
-
- const VarInfoMap& getVarInfoMap() const { return VarInfos; }
+ /// IsLive - Return true if a variable is live according to the
+ /// provided livness bitvector.
+ bool isLive(const ValTy& V, const VarDecl* D) const;
- // dumpLiveness
- void dumpLiveness(const llvm::BitVector& V, SourceManager& M) const;
+ /// dumpLiveness - Print to stderr the liveness information encoded
+ /// by a specified bitvector.
+ void dumpLiveness(const ValTy& 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
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);
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> {
}
}
+ 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)