LiveVariables L(cfg);
L.runOnCFG(cfg);
DeadStoreObs A(Ctx, Diags);
- L.runOnAllBlocks(cfg,A);
+ L.runOnAllBlocks(cfg,&A);
}
} // end namespace clang
cfg = &c;
Liveness = new LiveVariables(c);
Liveness->runOnCFG(c);
+ Liveness->runOnAllBlocks(c, NULL, true);
}
StateTy getInitialState() {
GRConstants::StateTy
GRConstants::RemoveSubExprMappings(StateTy M) {
-#if 0
- return M;
-#else
for (StateTy::iterator I = M.begin(), E = M.end();
I!=E && I.getKey().getKind() == DSPtr::IsSubExp; ++I) {
// Note: we can assign a new map to M since the iterators are
}
return M;
-#endif
}
GRConstants::StateTy
GRConstants::RemoveDescendantMappings(Stmt* S, GRConstants::StateTy State,
unsigned Levels) {
-#if 1
- return State;
-#else
typedef Stmt::child_iterator iterator;
for (iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
}
return State;
-#endif
}
void GRConstants::DoStmt(Stmt* S) {
void GRConstants::VisitBinAssign(BinaryOperator* B) {
- if (DeclRefExpr* D = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens()))
- AddBinding(D->getDecl(), GetBinding(B->getRHS()));
+ if (DeclRefExpr* D = dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParens())) {
+ ExprVariantTy V = GetBinding(B->getRHS());
+ AddBinding(D->getDecl(), V);
+ AddBinding(B, V);
+ }
}
//===----------------------------------------------------------------------===//
}
void LiveVariables::runOnAllBlocks(const CFG& cfg,
- LiveVariables::ObserverTy& Obs) {
+ LiveVariables::ObserverTy* Obs,
+ bool recordStmtValues) {
Solver S(*this);
ObserverTy* OldObserver = getAnalysisData().Observer;
- getAnalysisData().Observer = &Obs;
- S.runOnAllBlocks(cfg);
+ getAnalysisData().Observer = Obs;
+ S.runOnAllBlocks(cfg, recordStmtValues);
getAnalysisData().Observer = OldObserver;
}
/// IsLive - Return true if a variable is live at beginning of a
/// specified block.
bool isLive(const CFGBlock* B, const VarDecl* D) const;
+
+ /// IsLive - Returns true if a variable is live at the beginning of the
+ /// the statement. This query only works if liveness information
+ /// has been recorded at the statement level (see runOnAllBlocks), and
+ /// only returns liveness information for block-level expressions.
+ bool isLive(const Stmt* S, const VarDecl* D) const;
/// IsLive - Return true if a variable is live according to the
/// provided livness bitvector.
void InitializeValues(const CFG& cfg);
void runOnCFG(CFG& cfg);
- void runOnAllBlocks(const CFG& cfg, ObserverTy& Obs);
+
+ /// runOnAllBlocks - Propagate the dataflow values once for each block,
+ /// starting from the current dataflow values. 'recordStmtValues' indicates
+ /// whether the method should store dataflow values per each individual
+ /// block-level expression.
+ void runOnAllBlocks(const CFG& cfg, ObserverTy* Obs,
+ bool recordStmtValues=false);
};
} // end namespace clang
~DataflowSolver() {}
/// runOnCFG - Computes dataflow values for all blocks in a CFG.
- void runOnCFG(CFG& cfg) {
+ void runOnCFG(CFG& cfg, bool recordStmtValues = false) {
// Set initial dataflow values and boundary conditions.
D.InitializeValues(cfg);
// Solve the dataflow equations. This will populate D.EdgeDataMap
// with dataflow values.
- SolveDataflowEquations(cfg);
+ SolveDataflowEquations(cfg, recordStmtValues);
}
/// runOnBlock - Computes dataflow values for a given block. This
/// dataflow values using runOnCFG, as runOnBlock is intended to
/// only be used for querying the dataflow values within a block
/// with and Observer object.
- void runOnBlock(const CFGBlock* B) {
+ void runOnBlock(const CFGBlock* B, bool recordStmtValues) {
BlockDataMapTy& M = D.getBlockDataMap();
typename BlockDataMapTy::iterator I = M.find(B);
if (I != M.end()) {
TF.getVal().copyValues(I->second);
- ProcessBlock(B);
+ ProcessBlock(B, recordStmtValues);
}
}
- void runOnBlock(const CFGBlock& B) { runOnBlock(&B); }
- void runOnBlock(CFG::iterator& I) { runOnBlock(*I); }
- void runOnBlock(CFG::const_iterator& I) { runOnBlock(*I); }
+ void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
+ runOnBlock(&B, recordStmtValues);
+ }
+ void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
+ runOnBlock(*I, recordStmtValues);
+ }
+ void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) {
+ runOnBlock(*I, recordStmtValues);
+ }
- void runOnAllBlocks(const CFG& cfg) {
+ void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) {
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
- runOnBlock(I);
+ runOnBlock(I, recordStmtValues);
}
//===----------------------------------------------------===//
/// SolveDataflowEquations - Perform the actual worklist algorithm
/// to compute dataflow values.
- void SolveDataflowEquations(CFG& cfg) {
+ void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
EnqueueFirstBlock(cfg,AnalysisDirTag());
while (!WorkList.isEmpty()) {
const CFGBlock* B = WorkList.dequeue();
ProcessMerge(cfg,B);
- ProcessBlock(B);
+ ProcessBlock(B, recordStmtValues);
UpdateEdges(cfg,B,TF.getVal());
}
}
/// 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)
+ void ProcessBlock(const CFGBlock* B, bool recordStmtValues) {
+ for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
+ if (recordStmtValues) D.getStmtDataMap()[*I] = TF.getVal();
+ }
}
/// UpdateEdges - After processing the transfer functions for a
typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
+ typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy;
//===--------------------------------------------------------------------===//
// Predicates.
//===--------------------------------------------------------------------===//
public:
+ DataflowValues() : StmtDataMap(NULL) {}
+ ~DataflowValues() { delete StmtDataMap; }
+
/// InitializeValues - Invoked by the solver to initialize state needed for
/// dataflow analysis. This method is usually specialized by subclasses.
void InitializeValues(const CFG& cfg) {};
const ValTy& getBlockData(const CFGBlock* B) const {
return const_cast<DataflowValues*>(this)->getBlockData(B);
- }
+ }
+
+ /// getStmtData - Retrieves the dataflow values associated with a
+ /// specified Stmt. If the dataflow analysis is a forward analysis,
+ /// this data corresponds to the point immediately after a Stmt.
+ /// If the analysis is a backwards analysis, it is associated with
+ /// the point before a Stmt. This data is only computed for block-level
+ /// expressions, and only when requested when the analysis is executed.
+ ValTy& getStmtData(const Stmt* S) {
+ assert (StmtDataMap && "Dataflow values were not computed for statements.");
+ typename StmtDataMapTy::iterator I = StmtDataMap->find(S);
+ assert (I != StmtDataMap->end() && "No data associated with statement.");
+ return I->second;
+ }
+
+ const ValTy& getStmtData(const Stmt* S) const {
+ return const_cast<DataflowValues*>(this)->getStmtData(S);
+ }
/// getEdgeDataMap - Retrieves the internal map between CFG edges and
/// dataflow values. Usually used by a dataflow solver to compute
/// to the dataflow values at the end of the block.
BlockDataMapTy& getBlockDataMap() { return BlockDataMap; }
const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; }
+
+ /// getStmtDataMap - Retrieves the internal map between Stmts and
+ /// dataflow values.
+ StmtDataMapTy& getStmtDataMap() {
+ if (!StmtDataMap) StmtDataMap = new StmtDataMapTy();
+ return *StmtDataMap;
+ }
+
+ const StmtDataMapTy& getStmtDataMap() const {
+ return const_cast<DataflowValues*>(this)->getStmtDataMap();
+ }
/// getAnalysisData - Retrieves the meta data associated with a
/// dataflow analysis for analyzing a particular CFG.
protected:
EdgeDataMapTy EdgeDataMap;
BlockDataMapTy BlockDataMap;
+ StmtDataMapTy* StmtDataMap;
AnalysisDataTy AnalysisData;
};