Modified DataFlowValues and DataflowSolver to associate dataflow value

with CFG *edges* instead of blocks.  This will fascilitate dataflow
analyses that are sensitive to block terminators, and also simplifies
some reasoning.

Updated UninitializedValues to comply to this new interface.

llvm-svn: 42099
This commit is contained in:
Ted Kremenek 2007-09-18 18:02:44 +00:00
parent 1d77d76837
commit 584e21a349
3 changed files with 147 additions and 96 deletions

View File

@ -61,7 +61,7 @@ public:
typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag; typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag;
typedef typename _DFValuesTy::ValTy ValTy; typedef typename _DFValuesTy::ValTy ValTy;
typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy; typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// External interface: constructing and running the solver. // External interface: constructing and running the solver.
@ -75,8 +75,9 @@ public:
void runOnCFG(const CFG& cfg) { void runOnCFG(const CFG& cfg) {
// Set initial dataflow values and boundary conditions. // Set initial dataflow values and boundary conditions.
D.InitializeValues(cfg); D.InitializeValues(cfg);
// Tag dispatch to the kind of analysis we do: forward or backwards. // Solve the dataflow equations. This will populate D.EdgeDataMap
SolveDataflowEquations(cfg,typename _DFValuesTy::AnalysisDirTag()); // with dataflow values.
SolveDataflowEquations(cfg);
} }
/// runOnBlock - Computes dataflow values for a given block. /// runOnBlock - Computes dataflow values for a given block.
@ -85,7 +86,7 @@ public:
/// only be used for querying the dataflow values within a block with /// only be used for querying the dataflow values within a block with
/// and Observer object. /// and Observer object.
void runOnBlock(const CFGBlock* B) { void runOnBlock(const CFGBlock* B) {
if (D.getBlockDataMap().find(B) == D.getBlockDataMap().end()) if (!hasData(B,AnalysisDirTag()))
return; return;
TransferFuncsTy TF (D.getAnalysisData()); TransferFuncsTy TF (D.getAnalysisData());
@ -98,39 +99,11 @@ public:
private: private:
/// SolveDataflowEquations (FORWARD ANALYSIS) - Perform the actual /// SolveDataflowEquations - Perform the actual
/// worklist algorithm to compute dataflow values.
void SolveDataflowEquations(const CFG& cfg, dataflow::forward_analysis_tag) {
// Create the worklist.
DataflowWorkListTy WorkList;
// Enqueue the ENTRY block.
WorkList.enqueue(&cfg.getEntry());
// Create the state for transfer functions.
TransferFuncsTy TF(D.getAnalysisData());
// Process the worklist until it is empty.
while (!WorkList.isEmpty()) {
const CFGBlock* B = WorkList.dequeue();
// If the dataflow values at the block's exit have changed,
// enqueue all successor blocks onto the worklist to have
// their values updated.
if (ProcessBlock(B,TF,AnalysisDirTag()))
for (CFGBlock::const_succ_iterator I=B->succ_begin(), E=B->succ_end();
I != E; ++I)
WorkList.enqueue(*I);
}
}
/// SolveDataflowEquations (BACKWARD ANALYSIS) - Perform the actual
/// worklist algorithm to compute dataflow values. /// worklist algorithm to compute dataflow values.
void SolveDataflowEquations(const CFG& cfg, dataflow::backward_analysis_tag) { void SolveDataflowEquations(const CFG& cfg) {
// Create the worklist.
DataflowWorkListTy WorkList; EnqueueFirstBlock(cfg,AnalysisDirTag());
// Enqueue the EXIT block.
WorkList.enqueue(&cfg.getExit());
// Create the state for transfer functions. // Create the state for transfer functions.
TransferFuncsTy TF(D.getAnalysisData()); TransferFuncsTy TF(D.getAnalysisData());
@ -141,16 +114,22 @@ private:
// If the dataflow values at the block's entry have changed, // If the dataflow values at the block's entry have changed,
// enqueue all predecessor blocks onto the worklist to have // enqueue all predecessor blocks onto the worklist to have
// their values updated. // their values updated.
if (ProcessBlock(B,TF,AnalysisDirTag())) ProcessBlock(B,TF,AnalysisDirTag());
for (CFGBlock::const_pred_iterator I=B->pred_begin(), E=B->pred_end(); UpdateEdges(B,TF.getVal(),AnalysisDirTag());
I != E; ++I)
WorkList.enqueue(*I);
} }
} }
void EnqueueFirstBlock(const CFG& cfg, dataflow::forward_analysis_tag) {
WorkList.enqueue(&cfg.getEntry());
}
void EnqueueFirstBlock(const CFG& cfg, dataflow::backward_analysis_tag) {
WorkList.enqueue(&cfg.getExit());
}
/// ProcessBlock (FORWARD ANALYSIS) - Process the transfer functions /// ProcessBlock (FORWARD ANALYSIS) - Process the transfer functions
/// for a given block based on a forward analysis. /// for a given block based on a forward analysis.
bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF, void ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
dataflow::forward_analysis_tag) { dataflow::forward_analysis_tag) {
ValTy& V = TF.getVal(); ValTy& V = TF.getVal();
@ -159,12 +138,12 @@ private:
V.resetValues(D.getAnalysisData()); V.resetValues(D.getAnalysisData());
MergeOperatorTy Merge; MergeOperatorTy Merge;
BlockDataMapTy& M = D.getBlockDataMap(); EdgeDataMapTy& M = D.getEdgeDataMap();
bool firstMerge = true; bool firstMerge = true;
for (CFGBlock::const_pred_iterator I=B->pred_begin(), for (CFGBlock::const_pred_iterator I=B->pred_begin(),
E=B->pred_end(); I!=E; ++I) { E=B->pred_end(); I!=E; ++I) {
typename BlockDataMapTy::iterator BI = M.find(*I); typename EdgeDataMapTy::iterator BI = M.find(CFG::Edge(*I,B));
if (BI != M.end()) { if (BI != M.end()) {
if (firstMerge) { if (firstMerge) {
firstMerge = false; firstMerge = false;
@ -177,14 +156,12 @@ private:
// Process the statements in the block in the forward direction. // Process the statements in the block in the forward direction.
for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I) for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I)
TF.BlockStmt_Visit(const_cast<Stmt*>(*I)); TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
return UpdateBlockValue(B,V);
} }
/// ProcessBlock (BACKWARD ANALYSIS) - Process the transfer functions /// ProcessBlock (BACKWARD ANALYSIS) - Process the transfer functions
/// for a given block based on a forward analysis. /// for a given block based on a forward analysis.
bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF, void ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
dataflow::backward_analysis_tag) { dataflow::backward_analysis_tag) {
ValTy& V = TF.getVal(); ValTy& V = TF.getVal();
@ -193,12 +170,12 @@ private:
V.resetValues(D.getAnalysisData()); V.resetValues(D.getAnalysisData());
MergeOperatorTy Merge; MergeOperatorTy Merge;
BlockDataMapTy& M = D.getBlockDataMap(); EdgeDataMapTy& M = D.getEdgeDataMap();
bool firstMerge = true; bool firstMerge = true;
for (CFGBlock::const_succ_iterator I=B->succ_begin(), for (CFGBlock::const_succ_iterator I=B->succ_begin(),
E=B->succ_end(); I!=E; ++I) { E=B->succ_end(); I!=E; ++I) {
typename BlockDataMapTy::iterator BI = M.find(*I); typename EdgeDataMapTy::iterator BI = M.find(CFG::Edge(B,*I));
if (BI != M.end()) { if (BI != M.end()) {
if (firstMerge) { if (firstMerge) {
firstMerge = false; firstMerge = false;
@ -211,34 +188,81 @@ private:
// Process the statements in the block in the forward direction. // Process the statements in the block in the forward direction.
for (CFGBlock::const_reverse_iterator I=B->begin(), E=B->end(); I!=E; ++I) for (CFGBlock::const_reverse_iterator I=B->begin(), E=B->end(); I!=E; ++I)
TF.BlockStmt_Visit(const_cast<Stmt*>(*I)); TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
}
return UpdateBlockValue(B,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 E(B,*I);
UpdateEdgeValue(E,V,*I);
}
} }
/// UpdateBlockValue - After processing the transfer functions for a block, /// UpdateEdges (BACKWARD ANALYSIS) - After processing the transfer
/// update the dataflow value associated with the block. Return true /// functions for a block, update the dataflow value associated with the
/// if the block's value has changed. We do lazy instantiation of block /// block's incoming edges. Enqueue any predecessor blocks for an
/// values, so if the block value has not been previously computed we /// outgoing edge whose value has changed.
/// obviously return true. void UpdateEdges(const CFGBlock* B, ValTy& V,dataflow::backward_analysis_tag){
bool UpdateBlockValue(const CFGBlock* B, ValTy& V) { for (CFGBlock::const_pred_iterator I=B->succ_begin(), E=B->succ_end();
BlockDataMapTy& M = D.getBlockDataMap(); I!=E; ++I) {
typename BlockDataMapTy::iterator I = M.find(B);
CFG::Edge E(*I,B);
UpdateEdgeValue(E,V,*I);
}
}
/// UpdateEdgeValue - Update the value associated with a given edge.
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()) { if (I == M.end()) {
M[B].copyValues(V); // First value for this edge.
return true; M[E].copyValues(V);
WorkList.enqueue(TargetBlock);
} }
else if (!V.equal(I->second)) { else if (!V.equal(I->second)) {
I->second.copyValues(V); I->second.copyValues(V);
return true; 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; return false;
} }
private: private:
DFValuesTy& D; DFValuesTy& D;
DataflowWorkListTy WorkList;
}; };

View File

@ -73,10 +73,6 @@ void UninitializedValues::InitializeValues(const CFG& cfg) {
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI!=BE; ++BI) for (CFGBlock::const_iterator BI=I->begin(), BE=I->end(); BI!=BE; ++BI)
R.BlockStmt_Visit(*BI); R.BlockStmt_Visit(*BI);
// Initialize the values of the last block.
// UninitializedValues::ValTy& V = getBlockDataMap()[&cfg.getEntry()];
// V.resetValues(getAnalysisData());
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -19,22 +19,57 @@
#include "clang/AST/CFG.h" #include "clang/AST/CFG.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
namespace clang { //===----------------------------------------------------------------------===//
// DenseMapInfo for CFG::Edge for use with DenseMap
//===----------------------------------------------------------------------===//
namespace llvm {
template <> struct DenseMapInfo<clang::CFG::Edge> {
static inline clang::CFG::Edge getEmptyKey() {
return clang::CFG::Edge(NULL,NULL);
}
static inline clang::CFG::Edge getTombstoneKey() {
return clang::CFG::Edge(NULL,reinterpret_cast<clang::CFGBlock*>(-1));
}
static unsigned getHashValue(const clang::CFG::Edge& E) {
const clang::CFGBlock* P1 = E.getSrc();
const clang::CFGBlock* P2 = E.getDst();
return (reinterpret_cast<unsigned>(P1) >> 4) ^
(reinterpret_cast<unsigned>(P1) >> 9) ^
(reinterpret_cast<unsigned>(P2) >> 5) ^
(reinterpret_cast<unsigned>(P2) >> 10);
}
static bool isEqual(const clang::CFG::Edge& LHS,
const clang::CFG::Edge& RHS) {
return LHS == RHS;
}
static bool isPod() { return true; }
};
} // end namespace llvm
//===----------------------------------------------------------------------===//
/// Dataflow Directional Tag Classes. These are used for tag dispatching
/// within the dataflow solver/transfer functions to determine what direction
/// a dataflow analysis flows.
//===----------------------------------------------------------------------===//
namespace clang {
namespace dataflow { namespace dataflow {
//===----------------------------------------------------------------------===//
/// Dataflow Directional Tag Classes. These are used for tag dispatching
/// within the dataflow solver/transfer functions to determine what direction
/// a dataflow analysis flows.
//===----------------------------------------------------------------------===//
struct forward_analysis_tag {}; struct forward_analysis_tag {};
struct backward_analysis_tag {}; struct backward_analysis_tag {};
} // end namespace dataflow } // end namespace dataflow
//===----------------------------------------------------------------------===//
/// DataflowValues. Container class to store dataflow values for a CFG.
//===----------------------------------------------------------------------===//
template <typename ValueTypes, template <typename ValueTypes,
typename _AnalysisDirTag = dataflow::forward_analysis_tag > typename _AnalysisDirTag = dataflow::forward_analysis_tag >
class DataflowValues { class DataflowValues {
@ -46,8 +81,8 @@ class DataflowValues {
public: public:
typedef typename ValueTypes::ValTy ValTy; typedef typename ValueTypes::ValTy ValTy;
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy; typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
typedef _AnalysisDirTag AnalysisDirTag; typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; typedef llvm::DenseMap<CFG::Edge, ValTy> EdgeDataMapTy;
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Predicates. // Predicates.
@ -55,19 +90,15 @@ public:
public: public:
/// isForwardAnalysis - Returns true if the dataflow values are computed /// isForwardAnalysis - Returns true if the dataflow values are computed
/// from a forward analysis. If this returns true, the value returned /// from a forward analysis.
/// from getBlockData() is the dataflow values associated with the END of
/// the block.
bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); } bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); }
/// isBackwardAnalysis - Returns true if the dataflow values are computed /// isBackwardAnalysis - Returns true if the dataflow values are computed
/// from a backward analysis. If this returns true, the value returned /// from a backward analysis.
/// from getBlockData() is the dataflow values associated with the ENTRY of
/// the block.
bool isBackwardAnalysis() { return !isForwardAnalysis(); } bool isBackwardAnalysis() { return !isForwardAnalysis(); }
private: private:
bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; } bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; }
bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; }
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
@ -79,25 +110,25 @@ public:
/// dataflow analysis. This method is usually specialized by subclasses. /// dataflow analysis. This method is usually specialized by subclasses.
void InitializeValues(const CFG& cfg) {}; void InitializeValues(const CFG& cfg) {};
/// getBlockData - Retrieves the dataflow values associated with a /// getEdgeData - Retrieves the dataflow values associated with a
/// specified CFGBlock. If the dataflow analysis is a forward analysis, /// specified CFGBlock. If the dataflow analysis is a forward analysis,
/// this data is associated with the END of the block. If the 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. /// is a backwards analysis, it is associated with the ENTRY of the block.
ValTy& getBlockData(const CFGBlock* B) { ValTy& getEdgeData(const CFG::Edge& E) {
typename BlockDataMapTy::iterator I = BlockDataMap.find(B); typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E);
assert (I != BlockDataMap.end() && "No data associated with CFGBlock."); assert (I != EdgeDataMap.end() && "No data associated with Edge.");
return I->second; return I->second;
} }
const ValTy& getBlockData(const CFGBlock*) const { const ValTy& getEdgeData(const CFG::Edge& E) const {
return reinterpret_cast<DataflowValues*>(this)->getBlockData(); return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E);
} }
/// getBlockDataMap - Retrieves the internal map between CFGBlocks and /// getEdgeDataMap - Retrieves the internal map between CFGBlocks and
/// dataflow values. Usually used by a dataflow solver to compute /// dataflow values. Usually used by a dataflow solver to compute
/// values for blocks. /// values for blocks.
BlockDataMapTy& getBlockDataMap() { return BlockDataMap; } EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; }
const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; } const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; }
/// getAnalysisData - Retrieves the meta data associated with a /// getAnalysisData - Retrieves the meta data associated with a
/// dataflow analysis for analyzing a particular CFG. /// dataflow analysis for analyzing a particular CFG.
@ -111,7 +142,7 @@ public:
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
protected: protected:
BlockDataMapTy BlockDataMap; EdgeDataMapTy EdgeDataMap;
AnalysisDataTy AnalysisData; AnalysisDataTy AnalysisData;
}; };