blob: 4a089dbcdc6ce05c40b46985c65933233c05859a [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;
Ted Kremenek7f49f502007-09-14 22:49:21 +000065
66 //===--------------------------------------------------------------------===//
67 // External interface: constructing and running the solver.
68 //===--------------------------------------------------------------------===//
69
70public:
Ted Kremenek3e039752007-09-17 17:14:52 +000071 DataflowSolver(DFValuesTy& d) : D(d) {}
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);
78 // Tag dispatch to the kind of analysis we do: forward or backwards.
79 SolveDataflowEquations(cfg,typename _DFValuesTy::AnalysisDirTag());
80 }
81
82 /// runOnBlock - Computes dataflow values for a given block.
83 /// This should usually be invoked only after previously computing
84 /// dataflow values using runOnCFG, as runOnBlock is intended to
85 /// only be used for querying the dataflow values within a block with
86 /// and Observer object.
87 void runOnBlock(const CFGBlock* B) {
Ted Kremenek3e039752007-09-17 17:14:52 +000088 TransferFuncsTy TF (D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +000089 ProcessBlock(B,TF,AnalysisDirTag());
90 }
91
92 //===--------------------------------------------------------------------===//
93 // Internal solver logic.
94 //===--------------------------------------------------------------------===//
95
96private:
97
98 /// SolveDataflowEquations (FORWARD ANALYSIS) - Perform the actual
99 /// worklist algorithm to compute dataflow values.
100 void SolveDataflowEquations(const CFG& cfg, dataflow::forward_analysis_tag) {
101 // Create the worklist.
102 DataflowWorkListTy WorkList;
103
104 // Enqueue the ENTRY block.
105 WorkList.enqueue(&cfg.getEntry());
106
107 // Create the state for transfer functions.
Ted Kremenek3e039752007-09-17 17:14:52 +0000108 TransferFuncsTy TF(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000109
110 // Process the worklist until it is empty.
111 while (!WorkList.isEmpty()) {
112 const CFGBlock* B = WorkList.dequeue();
113 // If the dataflow values at the block's exit have changed,
114 // enqueue all successor blocks onto the worklist to have
115 // their values updated.
116 if (ProcessBlock(B,TF,AnalysisDirTag()))
117 for (CFGBlock::const_succ_iterator I=B->succ_begin(), E=B->succ_end();
118 I != E; ++I)
119 WorkList.enqueue(*I);
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000120 }
121
122 // For blocks that have no associated dataflow value, instantiate a
123 // default value.
124 BlockDataMapTy& M = D.getBlockDataMap();
125
126 for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
127 if (M.find(&*I) == M.end())
128 M[&*I].resetValues(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000129 }
130
131 /// SolveDataflowEquations (BACKWARD ANALYSIS) - Perform the actual
132 /// worklist algorithm to compute dataflow values.
133 void SolveDataflowEquations(const CFG& cfg, dataflow::backward_analysis_tag) {
134 // Create the worklist.
135 DataflowWorkListTy WorkList;
136
137 // Enqueue the EXIT block.
138 WorkList.enqueue(&cfg.getExit());
139
140 // Create the state for transfer functions.
Ted Kremenek3e039752007-09-17 17:14:52 +0000141 TransferFuncsTy TF(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000142
143 // Process the worklist until it is empty.
144 while (!WorkList.isEmpty()) {
145 const CFGBlock* B = WorkList.dequeue();
146 // If the dataflow values at the block's entry have changed,
147 // enqueue all predecessor blocks onto the worklist to have
148 // their values updated.
149 if (ProcessBlock(B,TF,AnalysisDirTag()))
150 for (CFGBlock::const_pred_iterator I=B->pred_begin(), E=B->pred_end();
151 I != E; ++I)
152 WorkList.enqueue(*I);
153 }
154 }
155
156 /// ProcessBlock (FORWARD ANALYSIS) - Process the transfer functions
157 /// for a given block based on a forward analysis.
158 bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
159 dataflow::forward_analysis_tag) {
160
161 ValTy& V = TF.getVal();
162
163 // Merge dataflow values from all predecessors of this block.
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000164 V.resetValues(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000165 MergeOperatorTy Merge;
166
167 for (CFGBlock::const_pred_iterator I=B->pred_begin(),
168 E=B->pred_end(); I!=E; ++I)
169 Merge(V,D.getBlockData(*I));
170
171 // Process the statements in the block in the forward direction.
172 for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I)
173 TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
174
175 return UpdateBlockValue(B,V);
176 }
177
178 /// ProcessBlock (BACKWARD ANALYSIS) - Process the transfer functions
179 /// for a given block based on a forward analysis.
180 bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
181 dataflow::backward_analysis_tag) {
182
183 ValTy& V = TF.getVal();
184
185 // Merge dataflow values from all predecessors of this block.
Ted Kremenek0a03ce62007-09-17 20:49:30 +0000186 V.resetValues(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000187 MergeOperatorTy Merge;
188
189 for (CFGBlock::const_succ_iterator I=B->succ_begin(),
190 E=B->succ_end(); I!=E; ++I)
191 Merge(V,D.getBlockData(*I));
192
193 // Process the statements in the block in the forward direction.
194 for (CFGBlock::const_reverse_iterator I=B->begin(), E=B->end(); I!=E; ++I)
195 TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
196
197 return UpdateBlockValue(B,V);
198 }
199
200 /// UpdateBlockValue - After processing the transfer functions for a block,
201 /// update the dataflow value associated with the block. Return true
202 /// if the block's value has changed. We do lazy instantiation of block
203 /// values, so if the block value has not been previously computed we
204 /// obviously return true.
205 bool UpdateBlockValue(const CFGBlock* B, ValTy& V) {
206 BlockDataMapTy& M = D.getBlockDataMap();
207 typename BlockDataMapTy::iterator I = M.find(B);
208
209 if (I == M.end()) {
210 M[B].copyValues(V);
211 return true;
212 }
213 else if (!V.equal(I->second)) {
214 I->second.copyValues(V);
215 return true;
216 }
217
218 return false;
219 }
220
221private:
222 DFValuesTy& D;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000223};
224
225
226} // end namespace clang
227#endif