blob: 0f5e7bf246e894ab7c1ab822b3a91e05d666097d [file] [log] [blame]
//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines skeleton code for implementing dataflow analyses.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
#include "functional" // STL
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/FlowSensitive/DataflowValues.h"
#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
//===----------------------------------------------------------------------===//
/// DataflowWorkListTy - Data structure representing the worklist used for
/// dataflow algorithms.
//===----------------------------------------------------------------------===//
class DataflowWorkListTy {
llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet;
SmallVector<const CFGBlock *, 10> BlockQueue;
public:
/// enqueue - Add a block to the worklist. Blocks already on the
/// worklist are not added a second time.
void enqueue(const CFGBlock *B) {
unsigned char &x = BlockSet[B];
if (x == 1)
return;
x = 1;
BlockQueue.push_back(B);
}
/// dequeue - Remove a block from the worklist.
const CFGBlock *dequeue() {
assert(!BlockQueue.empty());
const CFGBlock *B = BlockQueue.back();
BlockQueue.pop_back();
BlockSet[B] = 0;
return B;
}
/// isEmpty - Return true if the worklist is empty.
bool isEmpty() const { return BlockQueue.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 BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
return BlockEdge(Prev, B, 0);
}
static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
return BlockEdge(B, Next, 0);
}
};
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 BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) {
return BlockEdge(B, Prev, 0);
}
static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) {
return BlockEdge(Next, B, 0);
}
};
} // end namespace dataflow
//===----------------------------------------------------------------------===//
/// DataflowSolverTy - Generic dataflow solver.
//===----------------------------------------------------------------------===//
template <typename _DFValuesTy, // Usually a subclass of DataflowValues
typename _TransferFuncsTy,
typename _MergeOperatorTy,
typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> >
class DataflowSolver {
//===----------------------------------------------------===//
// Type declarations.
//===----------------------------------------------------===//
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 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.
//===----------------------------------------------------===//
public:
DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
~DataflowSolver() {}
/// runOnCFG - Computes dataflow values for all blocks in a 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, recordStmtValues);
}
/// runOnBlock - Computes dataflow values for a given block. This
/// should usually be invoked only after previously computing
/// 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, bool recordStmtValues) {
BlockDataMapTy& M = D.getBlockDataMap();
typename BlockDataMapTy::iterator I = M.find(B);
if (I != M.end()) {
TF.getVal().copyValues(I->second);
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
}
}
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, bool recordStmtValues = false) {
for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
runOnBlock(I, recordStmtValues);
}
//===----------------------------------------------------===//
// Internal solver logic.
//===----------------------------------------------------===//
private:
/// SolveDataflowEquations - Perform the actual worklist algorithm
/// to compute dataflow values.
void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
EnqueueBlocksOnWorklist(cfg, AnalysisDirTag());
while (!WorkList.isEmpty()) {
const CFGBlock *B = WorkList.dequeue();
ProcessMerge(cfg, B);
ProcessBlock(B, recordStmtValues, AnalysisDirTag());
UpdateEdges(cfg, B, TF.getVal());
}
}
void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::forward_analysis_tag) {
// Enqueue all blocks to ensure the dataflow values are computed
// for every block. Not all blocks are guaranteed to reach the exit block.
for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
WorkList.enqueue(&**I);
}
void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::backward_analysis_tag) {
// Enqueue all blocks to ensure the dataflow values are computed
// for every block. Not all blocks are guaranteed to reach the exit block.
// Enqueue in reverse order since that will more likely match with
// the order they should ideally processed by the dataflow algorithm.
for (CFG::reverse_iterator I=cfg.rbegin(), E=cfg.rend(); I!=E; ++I)
WorkList.enqueue(&**I);
}
void ProcessMerge(CFG& cfg, const CFGBlock *B) {
ValTy& V = TF.getVal();
TF.SetTopValue(V);
// Merge dataflow values from all predecessors of this block.
MergeOperatorTy Merge;
EdgeDataMapTy& M = D.getEdgeDataMap();
bool firstMerge = true;
bool noEdges = true;
for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){
CFGBlock *PrevBlk = *I;
if (!PrevBlk)
continue;
typename EdgeDataMapTy::iterator EI =
M.find(ItrTraits::PrevEdge(B, PrevBlk));
if (EI != M.end()) {
noEdges = false;
if (firstMerge) {
firstMerge = false;
V.copyValues(EI->second);
}
else
Merge(V, EI->second);
}
}
bool isInitialized = true;
typename BlockDataMapTy::iterator BI = D.getBlockDataMap().find(B);
if(BI == D.getBlockDataMap().end()) {
isInitialized = false;
BI = D.getBlockDataMap().insert( std::make_pair(B,ValTy()) ).first;
}
// If no edges have been found, it means this is the first time the solver
// has been called on block B, we copy the initialization values (if any)
// as current value for V (which will be used as edge data)
if(noEdges && isInitialized)
Merge(V, BI->second);
// Set the data for the block.
BI->second.copyValues(V);
}
/// ProcessBlock - Process the transfer functions for a given block.
void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
dataflow::forward_analysis_tag) {
TF.setCurrentBlock(B);
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
CFGElement El = *I;
if (const CFGStmt *S = El.getAs<CFGStmt>())
ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag());
}
TF.VisitTerminator(const_cast<CFGBlock*>(B));
}
void ProcessBlock(const CFGBlock *B, bool recordStmtValues,
dataflow::backward_analysis_tag) {
TF.setCurrentBlock(B);
TF.VisitTerminator(const_cast<CFGBlock*>(B));
for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) {
CFGElement El = *I;
if (const CFGStmt *S = El.getAs<CFGStmt>())
ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag());
}
}
void ProcessStmt(const Stmt *S, bool record, dataflow::forward_analysis_tag) {
if (record) D.getStmtDataMap()[S] = TF.getVal();
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
}
void ProcessStmt(const Stmt *S, bool record, dataflow::backward_analysis_tag){
TF.BlockStmt_Visit(const_cast<Stmt*>(S));
if (record) D.getStmtDataMap()[S] = TF.getVal();
}
/// UpdateEdges - After processing the transfer functions for a
/// block, update the dataflow value associated with the block's
/// outgoing/incoming edges (depending on whether we do a
// forward/backward analysis respectively)
void UpdateEdges(CFG& cfg, const CFGBlock *B, ValTy& V) {
for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
if (CFGBlock *NextBlk = *I)
UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk);
}
/// UpdateEdgeValue - Update the value associated with a given edge.
void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock *TargetBlock) {
EdgeDataMapTy& M = D.getEdgeDataMap();
typename EdgeDataMapTy::iterator I = M.find(E);
if (I == M.end()) { // First computed value for this edge?
M[E].copyValues(V);
WorkList.enqueue(TargetBlock);
}
else if (!_Equal()(V,I->second)) {
I->second.copyValues(V);
WorkList.enqueue(TargetBlock);
}
}
private:
DFValuesTy& D;
DataflowWorkListTy WorkList;
TransferFuncsTy TF;
};
} // end namespace clang
#endif