summaryrefslogtreecommitdiffstats
path: root/include/clang/Analysis/FlowSensitive/DataflowSolver.h
blob: 38612593368b60c74184dc25e16875d643b66135 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines skeleton code for implementing dataflow analyses.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER
#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER

#include "clang/AST/CFG.h"
#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "functional" // STL

namespace clang {

//===----------------------------------------------------------------------===//
/// DataflowWorkListTy - Data structure representing the worklist used for
///  dataflow algorithms.
//===----------------------------------------------------------------------===//  

class DataflowWorkListTy {
  typedef llvm::SmallPtrSet<const CFGBlock*,20> BlockSet;
  BlockSet wlist;
public:
  /// enqueue - Add a block to the worklist.  Blocks already on the
  ///  worklist are not added a second time.
  void enqueue(const CFGBlock* B) { wlist.insert(B); }
  
  /// dequeue - Remove a block from the worklist.
  const CFGBlock* dequeue() {
    assert (!wlist.empty());
    const CFGBlock* B = *wlist.begin();
    wlist.erase(B);
    return B;          
  }
  
  /// isEmpty - Return true if the worklist is empty.
  bool isEmpty() const { return wlist.empty(); }
};

//===----------------------------------------------------------------------===//
// BlockItrTraits - Traits classes that allow transparent iteration
//  over successors/predecessors of a block depending on the direction
//  of our dataflow analysis.
//===----------------------------------------------------------------------===//

namespace dataflow {
template<typename Tag> struct ItrTraits {};

template <> struct ItrTraits<forward_analysis_tag> {
  typedef CFGBlock::const_pred_iterator PrevBItr;
  typedef CFGBlock::const_succ_iterator NextBItr;
  typedef CFGBlock::const_iterator      StmtItr;
  
  static PrevBItr PrevBegin(const CFGBlock* B) { return B->pred_begin(); }
  static PrevBItr PrevEnd(const CFGBlock* B) { return B->pred_end(); }
  
  static NextBItr NextBegin(const CFGBlock* B) { return B->succ_begin(); }    
  static NextBItr NextEnd(const CFGBlock* B) { return B->succ_end(); }
  
  static StmtItr StmtBegin(const CFGBlock* B) { return B->begin(); }
  static StmtItr StmtEnd(const CFGBlock* B) { return B->end(); }
  
  static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
    return BlockEdge(Prev, B);
  }
  
  static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
    return BlockEdge(B, Next);
  }
};

template <> struct ItrTraits<backward_analysis_tag> {
  typedef CFGBlock::const_succ_iterator    PrevBItr;
  typedef CFGBlock::const_pred_iterator    NextBItr;
  typedef CFGBlock::const_reverse_iterator StmtItr;
  
  static PrevBItr PrevBegin(const CFGBlock* B) { return B->succ_begin(); }    
  static PrevBItr PrevEnd(const CFGBlock* B) { return B->succ_end(); }
  
  static NextBItr NextBegin(const CFGBlock* B) { return B->pred_begin(); }    
  static NextBItr NextEnd(const CFGBlock* B) { return B->pred_end(); }
  
  static StmtItr StmtBegin(const CFGBlock* B) { return B->rbegin(); }
  static StmtItr StmtEnd(const CFGBlock* B) { return B->rend(); }    
  
  static BlockEdge PrevEdge(const CFGBlock* B, const CFGBlock* Prev) {
    return BlockEdge(B, Prev);
  }
  
  static BlockEdge NextEdge(const CFGBlock* B, const CFGBlock* Next) {
    return BlockEdge(Next, B);
  }
};
} // end namespace dataflow

//===----------------------------------------------------------------------===//
/// DataflowSolverTy - Generic dataflow solver.
//===----------------------------------------------------------------------===//
  
template <typename _DFValuesTy,      // Usually a subclass of DataflowValues
          typename _TransferFuncsTy,
          typename _MergeOperatorTy,
          typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> >
class DataflowSolver {

  //===----------------------------------------------------===//
  // Type declarations.
  //===----------------------------------------------------===//

public:
  typedef _DFValuesTy                              DFValuesTy;
  typedef _TransferFuncsTy                         TransferFuncsTy;
  typedef _MergeOperatorTy                         MergeOperatorTy;
  
  typedef typename _DFValuesTy::AnalysisDirTag     AnalysisDirTag;
  typedef typename _DFValuesTy::ValTy              ValTy;
  typedef typename _DFValuesTy::EdgeDataMapTy      EdgeDataMapTy;
  typedef typename _DFValuesTy::BlockDataMapTy     BlockDataMapTy;

  typedef dataflow::ItrTraits<AnalysisDirTag>      ItrTraits;
  typedef typename ItrTraits::NextBItr             NextBItr;
  typedef typename ItrTraits::PrevBItr             PrevBItr;
  typedef typename ItrTraits::StmtItr              StmtItr;
  
  //===----------------------------------------------------===//
  // External interface: constructing and running the solver.
  //===----------------------------------------------------===//
  
public:
  DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {}
  ~DataflowSolver() {}  
  
  /// runOnCFG - Computes dataflow values for all blocks in a CFG.
  void runOnCFG(CFG& cfg, bool recordStmtValues = false) {
    // Set initial dataflow values and boundary conditions.
    D.InitializeValues(cfg);     
    // Solve the dataflow equations.  This will populate D.EdgeDataMap
    // with dataflow values.
    SolveDataflowEquations(cfg, recordStmtValues);
  }
  
  /// runOnBlock - Computes dataflow values for a given block.  This
  ///  should usually be invoked only after previously computing
  ///  dataflow values using runOnCFG, as runOnBlock is intended to
  ///  only be used for querying the dataflow values within a block
  ///  with and Observer object.
  void runOnBlock(const CFGBlock* B, bool recordStmtValues) {
    BlockDataMapTy& M = D.getBlockDataMap();
    typename BlockDataMapTy::iterator I = M.find(B);

    if (I != M.end()) {
      TF.getVal().copyValues(I->second);
      ProcessBlock(B, recordStmtValues, AnalysisDirTag());
    }
  }
  
  void runOnBlock(const CFGBlock& B, bool recordStmtValues) {
    runOnBlock(&B, recordStmtValues);
  }  
  void runOnBlock(CFG::iterator& I, bool recordStmtValues) {
    runOnBlock(*I, recordStmtValues);
  }
  void runOnBlock(CFG::const_iterator& I, bool recordStmtValues) {
    runOnBlock(*I, recordStmtValues);
  }

  void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) {
    for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
      runOnBlock(I, recordStmtValues);
  }
  
  //===----------------------------------------------------===//
  // Internal solver logic.
  //===----------------------------------------------------===//
  
private:
 
  /// SolveDataflowEquations - Perform the actual worklist algorithm
  ///  to compute dataflow values.
  void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) {
    // Enqueue all blocks to ensure the dataflow values are computed
    // for every block.  Not all blocks are guaranteed to reach the exit block.
    for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I)
      WorkList.enqueue(&*I);
    
    while (!WorkList.isEmpty()) {
      const CFGBlock* B = WorkList.dequeue();
      ProcessMerge(cfg,B);
      ProcessBlock(B, recordStmtValues, AnalysisDirTag());
      UpdateEdges(cfg,B,TF.getVal());
    }
  }  
  
  void ProcessMerge(CFG& cfg, const CFGBlock* B) {
    ValTy& V = TF.getVal();  
    TF.SetTopValue(V);

    // Merge dataflow values from all predecessors of this block.
    MergeOperatorTy Merge;
    
    EdgeDataMapTy& M = D.getEdgeDataMap();
    bool firstMerge = true;
    
    for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){

      typename EdgeDataMapTy::iterator EI =
        M.find(ItrTraits::PrevEdge(B, *I));

      if (EI != M.end()) {
        if (firstMerge) {
          firstMerge = false;
          V.copyValues(EI->second);
        }
        else Merge(V,EI->second);
      }
    }
    
    // Set the data for the block.
    D.getBlockDataMap()[B].copyValues(V);
  }  

  /// ProcessBlock - Process the transfer functions for a given block.
  void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
                    dataflow::forward_analysis_tag) {
    
    for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
      ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
    
    TF.VisitTerminator(const_cast<CFGBlock*>(B));  
  }
  
  void ProcessBlock(const CFGBlock* B, bool recordStmtValues,
                    dataflow::backward_analysis_tag) {
    
    TF.VisitTerminator(const_cast<CFGBlock*>(B));

    for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I)
      ProcessStmt(*I, recordStmtValues, AnalysisDirTag());
  }
  
  void ProcessStmt(const Stmt* S, bool record, dataflow::forward_analysis_tag) {
    if (record) D.getStmtDataMap()[S] = TF.getVal();
    TF.BlockStmt_Visit(const_cast<Stmt*>(S));  
  }
  
  void ProcessStmt(const Stmt* S, bool record, dataflow::backward_analysis_tag){
    TF.BlockStmt_Visit(const_cast<Stmt*>(S));
    if (record) D.getStmtDataMap()[S] = TF.getVal();
  }

  /// UpdateEdges - After processing the transfer functions for a
  ///   block, update the dataflow value associated with the block's
  ///   outgoing/incoming edges (depending on whether we do a
  //    forward/backward analysis respectively)
  void UpdateEdges(CFG& cfg, const CFGBlock* B, ValTy& V) {
    for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I)
      UpdateEdgeValue(ItrTraits::NextEdge(B, *I),V,*I);
  }
    
  /// UpdateEdgeValue - Update the value associated with a given edge.
  void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock* TargetBlock) {
    EdgeDataMapTy& M = D.getEdgeDataMap();
    typename EdgeDataMapTy::iterator I = M.find(E);
      
    if (I == M.end()) {  // First computed value for this edge?
      M[E].copyValues(V);
      WorkList.enqueue(TargetBlock);
    }
    else if (!_Equal()(V,I->second)) {
      I->second.copyValues(V);
      WorkList.enqueue(TargetBlock);
    }
  }
    
private:
  DFValuesTy& D;
  DataflowWorkListTy WorkList;
  TransferFuncsTy TF;
};

} // end namespace clang
#endif
OpenPOWER on IntegriCloud