blob: e2150004bb97924701a44e2165bd90b2724f4178 [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;
64 typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy;
65 typedef typename _DFValuesTy::ObserverTy ObserverTy;
66
67 //===--------------------------------------------------------------------===//
68 // External interface: constructing and running the solver.
69 //===--------------------------------------------------------------------===//
70
71public:
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
97private:
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
214private:
215 DFValuesTy& D;
216 ObserverTy* O;
217};
218
219
220} // end namespace clang
221#endif