blob: de5f9a3dddd01cfbe8239cf16d71c72900fc252f [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);
120 }
121 }
122
123 /// SolveDataflowEquations (BACKWARD ANALYSIS) - Perform the actual
124 /// worklist algorithm to compute dataflow values.
125 void SolveDataflowEquations(const CFG& cfg, dataflow::backward_analysis_tag) {
126 // Create the worklist.
127 DataflowWorkListTy WorkList;
128
129 // Enqueue the EXIT block.
130 WorkList.enqueue(&cfg.getExit());
131
132 // Create the state for transfer functions.
Ted Kremenek3e039752007-09-17 17:14:52 +0000133 TransferFuncsTy TF(D.getAnalysisData());
Ted Kremenek7f49f502007-09-14 22:49:21 +0000134
135 // Process the worklist until it is empty.
136 while (!WorkList.isEmpty()) {
137 const CFGBlock* B = WorkList.dequeue();
138 // If the dataflow values at the block's entry have changed,
139 // enqueue all predecessor blocks onto the worklist to have
140 // their values updated.
141 if (ProcessBlock(B,TF,AnalysisDirTag()))
142 for (CFGBlock::const_pred_iterator I=B->pred_begin(), E=B->pred_end();
143 I != E; ++I)
144 WorkList.enqueue(*I);
145 }
146 }
147
148 /// ProcessBlock (FORWARD ANALYSIS) - Process the transfer functions
149 /// for a given block based on a forward analysis.
150 bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
151 dataflow::forward_analysis_tag) {
152
153 ValTy& V = TF.getVal();
154
155 // Merge dataflow values from all predecessors of this block.
156 V.resetValues();
157 MergeOperatorTy Merge;
158
159 for (CFGBlock::const_pred_iterator I=B->pred_begin(),
160 E=B->pred_end(); I!=E; ++I)
161 Merge(V,D.getBlockData(*I));
162
163 // Process the statements in the block in the forward direction.
164 for (CFGBlock::const_iterator I=B->begin(), E=B->end(); I!=E; ++I)
165 TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
166
167 return UpdateBlockValue(B,V);
168 }
169
170 /// ProcessBlock (BACKWARD ANALYSIS) - Process the transfer functions
171 /// for a given block based on a forward analysis.
172 bool ProcessBlock(const CFGBlock* B, TransferFuncsTy& TF,
173 dataflow::backward_analysis_tag) {
174
175 ValTy& V = TF.getVal();
176
177 // Merge dataflow values from all predecessors of this block.
178 V.resetValues();
179 MergeOperatorTy Merge;
180
181 for (CFGBlock::const_succ_iterator I=B->succ_begin(),
182 E=B->succ_end(); I!=E; ++I)
183 Merge(V,D.getBlockData(*I));
184
185 // Process the statements in the block in the forward direction.
186 for (CFGBlock::const_reverse_iterator I=B->begin(), E=B->end(); I!=E; ++I)
187 TF.BlockStmt_Visit(const_cast<Stmt*>(*I));
188
189 return UpdateBlockValue(B,V);
190 }
191
192 /// UpdateBlockValue - After processing the transfer functions for a block,
193 /// update the dataflow value associated with the block. Return true
194 /// if the block's value has changed. We do lazy instantiation of block
195 /// values, so if the block value has not been previously computed we
196 /// obviously return true.
197 bool UpdateBlockValue(const CFGBlock* B, ValTy& V) {
198 BlockDataMapTy& M = D.getBlockDataMap();
199 typename BlockDataMapTy::iterator I = M.find(B);
200
201 if (I == M.end()) {
202 M[B].copyValues(V);
203 return true;
204 }
205 else if (!V.equal(I->second)) {
206 I->second.copyValues(V);
207 return true;
208 }
209
210 return false;
211 }
212
213private:
214 DFValuesTy& D;
Ted Kremenek7f49f502007-09-14 22:49:21 +0000215};
216
217
218} // end namespace clang
219#endif