1//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file defines skeleton code for implementing dataflow analyses. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER 15#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER 16 17#include "functional" // STL 18#include "clang/Analysis/CFG.h" 19#include "clang/Analysis/FlowSensitive/DataflowValues.h" 20#include "clang/Analysis/ProgramPoint.h" 21#include "llvm/ADT/DenseMap.h" 22#include "llvm/ADT/SmallVector.h" 23 24namespace clang { 25 26//===----------------------------------------------------------------------===// 27/// DataflowWorkListTy - Data structure representing the worklist used for 28/// dataflow algorithms. 29//===----------------------------------------------------------------------===// 30 31class DataflowWorkListTy { 32 llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet; 33 SmallVector<const CFGBlock *, 10> BlockQueue; 34public: 35 /// enqueue - Add a block to the worklist. Blocks already on the 36 /// worklist are not added a second time. 37 void enqueue(const CFGBlock *B) { 38 unsigned char &x = BlockSet[B]; 39 if (x == 1) 40 return; 41 x = 1; 42 BlockQueue.push_back(B); 43 } 44 45 /// dequeue - Remove a block from the worklist. 46 const CFGBlock *dequeue() { 47 assert(!BlockQueue.empty()); 48 const CFGBlock *B = BlockQueue.pop_back_val(); 49 BlockSet[B] = 0; 50 return B; 51 } 52 53 /// isEmpty - Return true if the worklist is empty. 54 bool isEmpty() const { return BlockQueue.empty(); } 55}; 56 57//===----------------------------------------------------------------------===// 58// BlockItrTraits - Traits classes that allow transparent iteration 59// over successors/predecessors of a block depending on the direction 60// of our dataflow analysis. 61//===----------------------------------------------------------------------===// 62 63namespace dataflow { 64template<typename Tag> struct ItrTraits {}; 65 66template <> struct ItrTraits<forward_analysis_tag> { 67 typedef CFGBlock::const_pred_iterator PrevBItr; 68 typedef CFGBlock::const_succ_iterator NextBItr; 69 typedef CFGBlock::const_iterator StmtItr; 70 71 static PrevBItr PrevBegin(const CFGBlock *B) { return B->pred_begin(); } 72 static PrevBItr PrevEnd(const CFGBlock *B) { return B->pred_end(); } 73 74 static NextBItr NextBegin(const CFGBlock *B) { return B->succ_begin(); } 75 static NextBItr NextEnd(const CFGBlock *B) { return B->succ_end(); } 76 77 static StmtItr StmtBegin(const CFGBlock *B) { return B->begin(); } 78 static StmtItr StmtEnd(const CFGBlock *B) { return B->end(); } 79 80 static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) { 81 return BlockEdge(Prev, B, 0); 82 } 83 84 static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) { 85 return BlockEdge(B, Next, 0); 86 } 87}; 88 89template <> struct ItrTraits<backward_analysis_tag> { 90 typedef CFGBlock::const_succ_iterator PrevBItr; 91 typedef CFGBlock::const_pred_iterator NextBItr; 92 typedef CFGBlock::const_reverse_iterator StmtItr; 93 94 static PrevBItr PrevBegin(const CFGBlock *B) { return B->succ_begin(); } 95 static PrevBItr PrevEnd(const CFGBlock *B) { return B->succ_end(); } 96 97 static NextBItr NextBegin(const CFGBlock *B) { return B->pred_begin(); } 98 static NextBItr NextEnd(const CFGBlock *B) { return B->pred_end(); } 99 100 static StmtItr StmtBegin(const CFGBlock *B) { return B->rbegin(); } 101 static StmtItr StmtEnd(const CFGBlock *B) { return B->rend(); } 102 103 static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) { 104 return BlockEdge(B, Prev, 0); 105 } 106 107 static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) { 108 return BlockEdge(Next, B, 0); 109 } 110}; 111} // end namespace dataflow 112 113//===----------------------------------------------------------------------===// 114/// DataflowSolverTy - Generic dataflow solver. 115//===----------------------------------------------------------------------===// 116 117template <typename _DFValuesTy, // Usually a subclass of DataflowValues 118 typename _TransferFuncsTy, 119 typename _MergeOperatorTy, 120 typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> > 121class DataflowSolver { 122 123 //===----------------------------------------------------===// 124 // Type declarations. 125 //===----------------------------------------------------===// 126 127public: 128 typedef _DFValuesTy DFValuesTy; 129 typedef _TransferFuncsTy TransferFuncsTy; 130 typedef _MergeOperatorTy MergeOperatorTy; 131 132 typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag; 133 typedef typename _DFValuesTy::ValTy ValTy; 134 typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy; 135 typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy; 136 137 typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits; 138 typedef typename ItrTraits::NextBItr NextBItr; 139 typedef typename ItrTraits::PrevBItr PrevBItr; 140 typedef typename ItrTraits::StmtItr StmtItr; 141 142 //===----------------------------------------------------===// 143 // External interface: constructing and running the solver. 144 //===----------------------------------------------------===// 145 146public: 147 DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {} 148 ~DataflowSolver() {} 149 150 /// runOnCFG - Computes dataflow values for all blocks in a CFG. 151 void runOnCFG(CFG& cfg, bool recordStmtValues = false) { 152 // Set initial dataflow values and boundary conditions. 153 D.InitializeValues(cfg); 154 // Solve the dataflow equations. This will populate D.EdgeDataMap 155 // with dataflow values. 156 SolveDataflowEquations(cfg, recordStmtValues); 157 } 158 159 /// runOnBlock - Computes dataflow values for a given block. This 160 /// should usually be invoked only after previously computing 161 /// dataflow values using runOnCFG, as runOnBlock is intended to 162 /// only be used for querying the dataflow values within a block 163 /// with and Observer object. 164 void runOnBlock(const CFGBlock *B, bool recordStmtValues) { 165 BlockDataMapTy& M = D.getBlockDataMap(); 166 typename BlockDataMapTy::iterator I = M.find(B); 167 168 if (I != M.end()) { 169 TF.getVal().copyValues(I->second); 170 ProcessBlock(B, recordStmtValues, AnalysisDirTag()); 171 } 172 } 173 174 void runOnBlock(const CFGBlock &B, bool recordStmtValues) { 175 runOnBlock(&B, recordStmtValues); 176 } 177 void runOnBlock(CFG::iterator &I, bool recordStmtValues) { 178 runOnBlock(*I, recordStmtValues); 179 } 180 void runOnBlock(CFG::const_iterator &I, bool recordStmtValues) { 181 runOnBlock(*I, recordStmtValues); 182 } 183 184 void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) { 185 for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) 186 runOnBlock(I, recordStmtValues); 187 } 188 189 //===----------------------------------------------------===// 190 // Internal solver logic. 191 //===----------------------------------------------------===// 192 193private: 194 195 /// SolveDataflowEquations - Perform the actual worklist algorithm 196 /// to compute dataflow values. 197 void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) { 198 EnqueueBlocksOnWorklist(cfg, AnalysisDirTag()); 199 200 while (!WorkList.isEmpty()) { 201 const CFGBlock *B = WorkList.dequeue(); 202 ProcessMerge(cfg, B); 203 ProcessBlock(B, recordStmtValues, AnalysisDirTag()); 204 UpdateEdges(cfg, B, TF.getVal()); 205 } 206 } 207 208 void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::forward_analysis_tag) { 209 // Enqueue all blocks to ensure the dataflow values are computed 210 // for every block. Not all blocks are guaranteed to reach the exit block. 211 for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) 212 WorkList.enqueue(&**I); 213 } 214 215 void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::backward_analysis_tag) { 216 // Enqueue all blocks to ensure the dataflow values are computed 217 // for every block. Not all blocks are guaranteed to reach the exit block. 218 // Enqueue in reverse order since that will more likely match with 219 // the order they should ideally processed by the dataflow algorithm. 220 for (CFG::reverse_iterator I=cfg.rbegin(), E=cfg.rend(); I!=E; ++I) 221 WorkList.enqueue(&**I); 222 } 223 224 void ProcessMerge(CFG& cfg, const CFGBlock *B) { 225 ValTy& V = TF.getVal(); 226 TF.SetTopValue(V); 227 228 // Merge dataflow values from all predecessors of this block. 229 MergeOperatorTy Merge; 230 231 EdgeDataMapTy& M = D.getEdgeDataMap(); 232 bool firstMerge = true; 233 bool noEdges = true; 234 for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){ 235 236 CFGBlock *PrevBlk = *I; 237 238 if (!PrevBlk) 239 continue; 240 241 typename EdgeDataMapTy::iterator EI = 242 M.find(ItrTraits::PrevEdge(B, PrevBlk)); 243 244 if (EI != M.end()) { 245 noEdges = false; 246 if (firstMerge) { 247 firstMerge = false; 248 V.copyValues(EI->second); 249 } 250 else 251 Merge(V, EI->second); 252 } 253 } 254 255 bool isInitialized = true; 256 typename BlockDataMapTy::iterator BI = D.getBlockDataMap().find(B); 257 if(BI == D.getBlockDataMap().end()) { 258 isInitialized = false; 259 BI = D.getBlockDataMap().insert( std::make_pair(B,ValTy()) ).first; 260 } 261 // If no edges have been found, it means this is the first time the solver 262 // has been called on block B, we copy the initialization values (if any) 263 // as current value for V (which will be used as edge data) 264 if(noEdges && isInitialized) 265 Merge(V, BI->second); 266 267 // Set the data for the block. 268 BI->second.copyValues(V); 269 } 270 271 /// ProcessBlock - Process the transfer functions for a given block. 272 void ProcessBlock(const CFGBlock *B, bool recordStmtValues, 273 dataflow::forward_analysis_tag) { 274 275 TF.setCurrentBlock(B); 276 277 for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { 278 CFGElement El = *I; 279 if (const CFGStmt *S = El.getAs<CFGStmt>()) 280 ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag()); 281 } 282 283 TF.VisitTerminator(const_cast<CFGBlock*>(B)); 284 } 285 286 void ProcessBlock(const CFGBlock *B, bool recordStmtValues, 287 dataflow::backward_analysis_tag) { 288 289 TF.setCurrentBlock(B); 290 291 TF.VisitTerminator(const_cast<CFGBlock*>(B)); 292 293 for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { 294 CFGElement El = *I; 295 if (const CFGStmt *S = El.getAs<CFGStmt>()) 296 ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag()); 297 } 298 } 299 300 void ProcessStmt(const Stmt *S, bool record, dataflow::forward_analysis_tag) { 301 if (record) D.getStmtDataMap()[S] = TF.getVal(); 302 TF.BlockStmt_Visit(const_cast<Stmt*>(S)); 303 } 304 305 void ProcessStmt(const Stmt *S, bool record, dataflow::backward_analysis_tag){ 306 TF.BlockStmt_Visit(const_cast<Stmt*>(S)); 307 if (record) D.getStmtDataMap()[S] = TF.getVal(); 308 } 309 310 /// UpdateEdges - After processing the transfer functions for a 311 /// block, update the dataflow value associated with the block's 312 /// outgoing/incoming edges (depending on whether we do a 313 // forward/backward analysis respectively) 314 void UpdateEdges(CFG& cfg, const CFGBlock *B, ValTy& V) { 315 for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I) 316 if (CFGBlock *NextBlk = *I) 317 UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk); 318 } 319 320 /// UpdateEdgeValue - Update the value associated with a given edge. 321 void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock *TargetBlock) { 322 EdgeDataMapTy& M = D.getEdgeDataMap(); 323 typename EdgeDataMapTy::iterator I = M.find(E); 324 325 if (I == M.end()) { // First computed value for this edge? 326 M[E].copyValues(V); 327 WorkList.enqueue(TargetBlock); 328 } 329 else if (!_Equal()(V,I->second)) { 330 I->second.copyValues(V); 331 WorkList.enqueue(TargetBlock); 332 } 333 } 334 335private: 336 DFValuesTy& D; 337 DataflowWorkListTy WorkList; 338 TransferFuncsTy TF; 339}; 340 341} // end namespace clang 342#endif 343