| Ted Kremenek | 5746d06 | 2007-09-14 22:49:21 +0000 | [diff] [blame] | 1 | //===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- C++ -*-===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file was developed by Ted Kremenek and is distributed under | 
|  | 6 | // the University of Illinois Open Source 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 "clang/AST/CFG.h" | 
|  | 18 | #include "llvm/ADT/SmallPtrSet.h" | 
|  | 19 |  | 
|  | 20 | namespace clang { | 
|  | 21 |  | 
|  | 22 | //===----------------------------------------------------------------------===// | 
|  | 23 | /// DataflowWorkListTy - Data structure representing the worklist used for | 
|  | 24 | ///  dataflow algorithms. | 
|  | 25 |  | 
|  | 26 | class DataflowWorkListTy { | 
|  | 27 | typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet; | 
|  | 28 | BlockSet wlist; | 
|  | 29 | public: | 
|  | 30 | /// enqueue - Add a block to the worklist.  Blocks already on the worklist | 
|  | 31 | ///  are not added a second time. | 
|  | 32 | void enqueue(const CFGBlock* B) { wlist.insert(B); } | 
|  | 33 |  | 
|  | 34 | /// dequeue - Remove a block from the worklist. | 
|  | 35 | const CFGBlock* dequeue() { | 
|  | 36 | assert (!wlist.empty()); | 
|  | 37 | const CFGBlock* B = *wlist.begin(); | 
|  | 38 | wlist.erase(B); | 
|  | 39 | return B; | 
|  | 40 | } | 
|  | 41 |  | 
|  | 42 | /// isEmpty - Return true if the worklist is empty. | 
|  | 43 | bool isEmpty() const { return wlist.empty(); } | 
|  | 44 | }; | 
|  | 45 |  | 
|  | 46 | //===----------------------------------------------------------------------===// | 
|  | 47 | /// DataflowSolverTy - Generic dataflow solver. | 
|  | 48 | template <typename _DFValuesTy,      // Usually a subclass of DataflowValues | 
|  | 49 | typename _TransferFuncsTy, | 
|  | 50 | typename _MergeOperatorTy > | 
|  | 51 | class DataflowSolver { | 
|  | 52 |  | 
|  | 53 | //===--------------------------------------------------------------------===// | 
|  | 54 | // Type declarations. | 
|  | 55 | //===--------------------------------------------------------------------===// | 
|  | 56 |  | 
|  | 57 | public: | 
|  | 58 | typedef _DFValuesTy                            DFValuesTy; | 
|  | 59 | typedef _TransferFuncsTy                       TransferFuncsTy; | 
|  | 60 | typedef _MergeOperatorTy                       MergeOperatorTy; | 
|  | 61 |  | 
|  | 62 | typedef typename _DFValuesTy::AnalysisDirTag   AnalysisDirTag; | 
|  | 63 | typedef typename _DFValuesTy::ValTy            ValTy; | 
|  | 64 | typedef typename _DFValuesTy::BlockDataMapTy   BlockDataMapTy; | 
|  | 65 | typedef typename _DFValuesTy::ObserverTy       ObserverTy; | 
|  | 66 |  | 
|  | 67 | //===--------------------------------------------------------------------===// | 
|  | 68 | // External interface: constructing and running the solver. | 
|  | 69 | //===--------------------------------------------------------------------===// | 
|  | 70 |  | 
|  | 71 | public: | 
|  | 72 | DataflowSolver(DFValuesTy& d, ObserverTy* o = NULL) : D(d), O(o) {} | 
|  | 73 | ~DataflowSolver() {} | 
|  | 74 |  | 
|  | 75 | /// runOnCFG - Computes dataflow values for all blocks in a CFG. | 
|  | 76 | void runOnCFG(const CFG& cfg) { | 
|  | 77 | // Set initial dataflow values and boundary conditions. | 
|  | 78 | D.InitializeValues(cfg); | 
|  | 79 | // Tag dispatch to the kind of analysis we do: forward or backwards. | 
|  | 80 | SolveDataflowEquations(cfg,typename _DFValuesTy::AnalysisDirTag()); | 
|  | 81 | } | 
|  | 82 |  | 
|  | 83 | /// runOnBlock - Computes dataflow values for a given block. | 
|  | 84 | ///  This should usually be invoked only after previously computing | 
|  | 85 | ///  dataflow values using runOnCFG, as runOnBlock is intended to | 
|  | 86 | ///  only be used for querying the dataflow values within a block with | 
|  | 87 | ///  and Observer object. | 
|  | 88 | void runOnBlock(const CFGBlock* B) { | 
|  | 89 | TransferFuncsTy TF (D.getMetaData(),O); | 
|  | 90 | ProcessBlock(B,TF,AnalysisDirTag()); | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | //===--------------------------------------------------------------------===// | 
|  | 94 | // Internal solver logic. | 
|  | 95 | //===--------------------------------------------------------------------===// | 
|  | 96 |  | 
|  | 97 | private: | 
|  | 98 |  | 
|  | 99 | /// SolveDataflowEquations (FORWARD ANALYSIS) - Perform the actual | 
|  | 100 | ///  worklist algorithm to compute dataflow values. | 
|  | 101 | void SolveDataflowEquations(const CFG& cfg, dataflow::forward_analysis_tag) { | 
|  | 102 | // Create the worklist. | 
|  | 103 | DataflowWorkListTy WorkList; | 
|  | 104 |  | 
|  | 105 | // Enqueue the ENTRY block. | 
|  | 106 | WorkList.enqueue(&cfg.getEntry()); | 
|  | 107 |  | 
|  | 108 | // Create the state for transfer functions. | 
|  | 109 | TransferFuncsTy TF(D.getMetaData(),O); | 
|  | 110 |  | 
|  | 111 | // Process the worklist until it is empty. | 
|  | 112 | while (!WorkList.isEmpty()) { | 
|  | 113 | const CFGBlock* B = WorkList.dequeue(); | 
|  | 114 | // If the dataflow values at the block's exit have changed, | 
|  | 115 | // enqueue all successor blocks onto the worklist to have | 
|  | 116 | // their values updated. | 
|  | 117 | if (ProcessBlock(B,TF,AnalysisDirTag())) | 
|  | 118 | for (CFGBlock::const_succ_iterator I=B->succ_begin(), E=B->succ_end(); | 
|  | 119 | I != E; ++I) | 
|  | 120 | WorkList.enqueue(*I); | 
|  | 121 | } | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | /// SolveDataflowEquations (BACKWARD ANALYSIS) - Perform the actual | 
|  | 125 | ///  worklist algorithm to compute dataflow values. | 
|  | 126 | void SolveDataflowEquations(const CFG& cfg, dataflow::backward_analysis_tag) { | 
|  | 127 | // Create the worklist. | 
|  | 128 | DataflowWorkListTy WorkList; | 
|  | 129 |  | 
|  | 130 | // Enqueue the EXIT block. | 
|  | 131 | WorkList.enqueue(&cfg.getExit()); | 
|  | 132 |  | 
|  | 133 | // Create the state for transfer functions. | 
|  | 134 | TransferFuncsTy TF(D.getMetaData(),O); | 
|  | 135 |  | 
|  | 136 | // Process the worklist until it is empty. | 
|  | 137 | while (!WorkList.isEmpty()) { | 
|  | 138 | const CFGBlock* B = WorkList.dequeue(); | 
|  | 139 | // If the dataflow values at the block's entry have changed, | 
|  | 140 | // enqueue all predecessor blocks onto the worklist to have | 
|  | 141 | // their values updated. | 
|  | 142 | if (ProcessBlock(B,TF,AnalysisDirTag())) | 
|  | 143 | for (CFGBlock::const_pred_iterator I=B->pred_begin(), E=B->pred_end(); | 
|  | 144 | I != E; ++I) | 
|  | 145 | WorkList.enqueue(*I); | 
|  | 146 | } | 
|  | 147 | } | 
|  | 148 |  | 
|  | 149 | /// ProcessBlock (FORWARD ANALYSIS) - Process the transfer functions | 
|  | 150 | ///  for a given block based on a forward analysis. | 
|  | 151 | bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF, | 
|  | 152 | dataflow::forward_analysis_tag) { | 
|  | 153 |  | 
|  | 154 | ValTy& V = TF.getVal(); | 
|  | 155 |  | 
|  | 156 | // Merge dataflow values from all predecessors of this block. | 
|  | 157 | V.resetValues(); | 
|  | 158 | MergeOperatorTy Merge; | 
|  | 159 |  | 
|  | 160 | for (CFGBlock::const_pred_iterator I=B->pred_begin(), | 
|  | 161 | E=B->pred_end(); I!=E; ++I) | 
|  | 162 | Merge(V,D.getBlockData(*I)); | 
|  | 163 |  | 
|  | 164 | // Process the statements in the block in the forward direction. | 
|  | 165 | for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I) | 
|  | 166 | TF.BlockStmt_Visit(const_cast<Stmt*>(*I)); | 
|  | 167 |  | 
|  | 168 | return UpdateBlockValue(B,V); | 
|  | 169 | } | 
|  | 170 |  | 
|  | 171 | /// ProcessBlock (BACKWARD ANALYSIS) - Process the transfer functions | 
|  | 172 | ///  for a given block based on a forward analysis. | 
|  | 173 | bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF, | 
|  | 174 | dataflow::backward_analysis_tag) { | 
|  | 175 |  | 
|  | 176 | ValTy& V = TF.getVal(); | 
|  | 177 |  | 
|  | 178 | // Merge dataflow values from all predecessors of this block. | 
|  | 179 | V.resetValues(); | 
|  | 180 | MergeOperatorTy Merge; | 
|  | 181 |  | 
|  | 182 | for (CFGBlock::const_succ_iterator I=B->succ_begin(), | 
|  | 183 | E=B->succ_end(); I!=E; ++I) | 
|  | 184 | Merge(V,D.getBlockData(*I)); | 
|  | 185 |  | 
|  | 186 | // Process the statements in the block in the forward direction. | 
|  | 187 | for (CFGBlock::const_reverse_iterator I=B->begin(), E=B->end(); I!=E; ++I) | 
|  | 188 | TF.BlockStmt_Visit(const_cast<Stmt*>(*I)); | 
|  | 189 |  | 
|  | 190 | return UpdateBlockValue(B,V); | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | /// UpdateBlockValue - After processing the transfer functions for a block, | 
|  | 194 | ///  update the dataflow value associated with the block.  Return true | 
|  | 195 | ///  if the block's value has changed.  We do lazy instantiation of block | 
|  | 196 | ///  values, so if the block value has not been previously computed we | 
|  | 197 | ///  obviously return true. | 
|  | 198 | bool UpdateBlockValue(const CFGBlock* B, ValTy& V) { | 
|  | 199 | BlockDataMapTy& M = D.getBlockDataMap(); | 
|  | 200 | typename BlockDataMapTy::iterator I = M.find(B); | 
|  | 201 |  | 
|  | 202 | if (I == M.end()) { | 
|  | 203 | M[B].copyValues(V); | 
|  | 204 | return true; | 
|  | 205 | } | 
|  | 206 | else if (!V.equal(I->second)) { | 
|  | 207 | I->second.copyValues(V); | 
|  | 208 | return true; | 
|  | 209 | } | 
|  | 210 |  | 
|  | 211 | return false; | 
|  | 212 | } | 
|  | 213 |  | 
|  | 214 | private: | 
|  | 215 | DFValuesTy& D; | 
|  | 216 | ObserverTy* O; | 
|  | 217 | }; | 
|  | 218 |  | 
|  | 219 |  | 
|  | 220 | } // end namespace clang | 
|  | 221 | #endif |