blob: b89b45b67739614a3ac0043a28df6f03f67a9402 [file] [log] [blame]
Ted Kremenek7f49f502007-09-14 22:49:21 +00001//===--- 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
20namespace clang {
21
22//===----------------------------------------------------------------------===//
23/// DataflowWorkListTy - Data structure representing the worklist used for
24/// dataflow algorithms.
25
26class DataflowWorkListTy {
27 typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
28 BlockSet wlist;
29public:
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.
48template <typename _DFValuesTy, // Usually a subclass of DataflowValues
49 typename _TransferFuncsTy,
50 typename _MergeOperatorTy >
51class DataflowSolver {
52
53 //===--------------------------------------------------------------------===//
54 // Type declarations.
55 //===--------------------------------------------------------------------===//
56
57public:
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;
Ted Kremenek2e3e6302007-09-18 18:02:44 +000064 typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy;
Ted Kremenek7f49f502007-09-14 22:49:21 +000065
66 //===--------------------------------------------------------------------===//
67 // External interface: constructing and running the solver.
68 //===--------------------------------------------------------------------===//
69
70public:
Ted Kremenek2a203562007-09-18 18:17:19 +000071 DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
Ted Kremenek7f49f502007-09-14 22:49:21 +000072 ~DataflowSolver() {}
73
74 /// runOnCFG - Computes dataflow values for all blocks in a CFG.
75 void runOnCFG(const CFG& cfg) {
76 // Set initial dataflow values and boundary conditions.
77 D.InitializeValues(cfg);
Ted Kremenek2e3e6302007-09-18 18:02:44 +000078 // Solve the dataflow equations. This will populate D.EdgeDataMap
79 // with dataflow values.
80 SolveDataflowEquations(cfg);
Ted Kremenek7f49f502007-09-14 22:49:21 +000081 }
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) {
Ted Kremenek2a203562007-09-18 18:17:19 +000089 if (hasData(B,AnalysisDirTag()))
90 ProcessBlock(B,AnalysisDirTag());
Ted Kremenek7f49f502007-09-14 22:49:21 +000091 }
92
Ted Kremenek3fa5e092007-09-18 21:08:21 +000093 void runOnBlock(const CFGBlock& B) { runOnBlock(&B); }
94 void runOnBlock(CFG::iterator &I) { runOnBlock(*I); }
95 void runOnBlock(CFG::const_iterator &I) { runOnBlock(*I); }
96
97 void runOnAllBlocks(const CFG& cfg) {
98 for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
99 runOnBlock(I);
100 }
101
Ted Kremenek7f49f502007-09-14 22:49:21 +0000102 //===--------------------------------------------------------------------===//
103 // Internal solver logic.
104 //===--------------------------------------------------------------------===//
105
106private:
107
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000108 /// SolveDataflowEquations - Perform the actual
Ted Kremenek7f49f502007-09-14 22:49:21 +0000109 /// worklist algorithm to compute dataflow values.
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000110 void SolveDataflowEquations(const CFG& cfg) {
111
112 EnqueueFirstBlock(cfg,AnalysisDirTag());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000113
Ted Kremenek7f49f502007-09-14 22:49:21 +0000114 // Process the worklist until it is empty.
115 while (!WorkList.isEmpty()) {
116 const CFGBlock* B = WorkList.dequeue();
117 // If the dataflow values at the block's entry have changed,
118 // enqueue all predecessor blocks onto the worklist to have
119 // their values updated.
Ted Kremenek2a203562007-09-18 18:17:19 +0000120 ProcessBlock(B,AnalysisDirTag());
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000121 UpdateEdges(B,TF.getVal(),AnalysisDirTag());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000122 }
123 }
124
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000125 void EnqueueFirstBlock(const CFG& cfg, dataflow::forward_analysis_tag) {
126 WorkList.enqueue(&cfg.getEntry());
127 }
128
129 void EnqueueFirstBlock(const CFG& cfg, dataflow::backward_analysis_tag) {
130 WorkList.enqueue(&cfg.getExit());
131 }
132
Ted Kremenek7f49f502007-09-14 22:49:21 +0000133 /// ProcessBlock (FORWARD ANALYSIS) - Process the transfer functions
134 /// for a given block based on a forward analysis.
Ted Kremenek2a203562007-09-18 18:17:19 +0000135 void ProcessBlock(const CFGBlock* B, dataflow::forward_analysis_tag) {
136
Ted Kremenek7f49f502007-09-14 22:49:21 +0000137 // Merge dataflow values from all predecessors of this block.
Ted Kremenek2a203562007-09-18 18:17:19 +0000138 ValTy& V = TF.getVal();
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000139 V.resetValues(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000140 MergeOperatorTy Merge;
141
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000142 EdgeDataMapTy& M = D.getEdgeDataMap();
Ted Kremeneke6148f32007-09-17 21:59:08 +0000143 bool firstMerge = true;
144
Ted Kremenek7f49f502007-09-14 22:49:21 +0000145 for (CFGBlock::const_pred_iterator I=B->pred_begin(),
Ted Kremeneke6148f32007-09-17 21:59:08 +0000146 E=B->pred_end(); I!=E; ++I) {
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000147 typename EdgeDataMapTy::iterator BI = M.find(CFG::Edge(*I,B));
Ted Kremeneke6148f32007-09-17 21:59:08 +0000148 if (BI != M.end()) {
149 if (firstMerge) {
150 firstMerge = false;
151 V.copyValues(BI->second);
152 }
153 else
154 Merge(V,BI->second);
155 }
156 }
Ted Kremenek7f49f502007-09-14 22:49:21 +0000157
158 // Process the statements in the block in the forward direction.
159 for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I)
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000160 TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
Ted Kremenek7f49f502007-09-14 22:49:21 +0000161 }
162
163 /// ProcessBlock (BACKWARD ANALYSIS) - Process the transfer functions
164 /// for a given block based on a forward analysis.
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000165 void ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
Ted Kremenek7f49f502007-09-14 22:49:21 +0000166 dataflow::backward_analysis_tag) {
Ted Kremenek2a203562007-09-18 18:17:19 +0000167
Ted Kremenek7f49f502007-09-14 22:49:21 +0000168 // Merge dataflow values from all predecessors of this block.
Ted Kremenek2a203562007-09-18 18:17:19 +0000169 ValTy& V = TF.getVal();
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000170 V.resetValues(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000171 MergeOperatorTy Merge;
172
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000173 EdgeDataMapTy& M = D.getEdgeDataMap();
Ted Kremeneke6148f32007-09-17 21:59:08 +0000174 bool firstMerge = true;
175
Ted Kremenek7f49f502007-09-14 22:49:21 +0000176 for (CFGBlock::const_succ_iterator I=B->succ_begin(),
Ted Kremeneke6148f32007-09-17 21:59:08 +0000177 E=B->succ_end(); I!=E; ++I) {
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000178 typename EdgeDataMapTy::iterator BI = M.find(CFG::Edge(B,*I));
Ted Kremeneke6148f32007-09-17 21:59:08 +0000179 if (BI != M.end()) {
180 if (firstMerge) {
181 firstMerge = false;
182 V.copyValues(BI->second);
183 }
184 else
185 Merge(V,BI->second);
186 }
187 }
Ted Kremenek7f49f502007-09-14 22:49:21 +0000188
189 // Process the statements in the block in the forward direction.
190 for (CFGBlock::const_reverse_iterator I=B->begin(), E=B->end(); I!=E; ++I)
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000191 TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
192 }
193
194 /// UpdateEdges (FORWARD ANALYSIS) - After processing the transfer
195 /// functions for a block, update the dataflow value associated with the
196 /// block's outgoing edges. Enqueue any successor blocks for an
197 /// outgoing edge whose value has changed.
198 void UpdateEdges(const CFGBlock* B, ValTy& V,dataflow::forward_analysis_tag) {
199 for (CFGBlock::const_succ_iterator I=B->succ_begin(), E=B->succ_end();
200 I!=E; ++I) {
201
202 CFG::Edge E(B,*I);
203 UpdateEdgeValue(E,V,*I);
204 }
Ted Kremenek7f49f502007-09-14 22:49:21 +0000205 }
206
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000207 /// UpdateEdges (BACKWARD ANALYSIS) - After processing the transfer
208 /// functions for a block, update the dataflow value associated with the
209 /// block's incoming edges. Enqueue any predecessor blocks for an
210 /// outgoing edge whose value has changed.
211 void UpdateEdges(const CFGBlock* B, ValTy& V,dataflow::backward_analysis_tag){
212 for (CFGBlock::const_pred_iterator I=B->succ_begin(), E=B->succ_end();
213 I!=E; ++I) {
214
215 CFG::Edge E(*I,B);
216 UpdateEdgeValue(E,V,*I);
217 }
218 }
219
220 /// UpdateEdgeValue - Update the value associated with a given edge.
221 void UpdateEdgeValue(CFG::Edge& E, ValTy& V, const CFGBlock* TargetBlock) {
222
223 EdgeDataMapTy& M = D.getEdgeDataMap();
224 typename EdgeDataMapTy::iterator I = M.find(E);
225
Ted Kremenek7f49f502007-09-14 22:49:21 +0000226 if (I == M.end()) {
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000227 // First value for this edge.
228 M[E].copyValues(V);
229 WorkList.enqueue(TargetBlock);
Ted Kremenek7f49f502007-09-14 22:49:21 +0000230 }
Ted Kremenek17aac832007-09-18 23:30:21 +0000231 else if (!(V==I->second)) {
Ted Kremenek7f49f502007-09-14 22:49:21 +0000232 I->second.copyValues(V);
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000233 WorkList.enqueue(TargetBlock);
Ted Kremenek7f49f502007-09-14 22:49:21 +0000234 }
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000235 }
236
237 /// hasData (FORWARD ANALYSIS) - Is there any dataflow values associated
238 /// with the incoming edges of a block?
239 bool hasData(const CFGBlock* B, dataflow::forward_analysis_tag) {
240 EdgeDataMapTy& M = D.getEdgeDataMap();
241
242 for (CFGBlock::const_pred_iterator I=B->pred_begin(), E=B->pred_end();
243 I!=E; ++I)
244 if (M.find(CFG::Edge(*I,B)) != M.end())
245 return true;
246
247 return false;
248 }
249
250 /// hasData (BACKWARD ANALYSIS) - Is there any dataflow values associated
251 /// with the outgoing edges of a block?
252 bool hasData(const CFGBlock* B, dataflow::backward_analysis_tag) {
253 EdgeDataMapTy& M = D.getEdgeDataMap();
254
255 for (CFGBlock::const_succ_iterator I=B->succ_begin(), E=B->succ_end();
256 I!=E; ++I)
257 if (M.find(CFG::Edge(B,*I)) != M.end())
258 return true;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000259
260 return false;
261 }
262
263private:
264 DFValuesTy& D;
Ted Kremenek2e3e6302007-09-18 18:02:44 +0000265 DataflowWorkListTy WorkList;
Ted Kremenek2a203562007-09-18 18:17:19 +0000266 TransferFuncsTy TF;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000267};
268
269
270} // end namespace clang
271#endif