summaryrefslogtreecommitdiff
path: root/lib/Analysis/DataStructure/PgmDependenceGraph.h
blob: d7774943bd93c6dd8c37257f0413616d2c7db89d (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
292
293
294
295
296
297
298
299
300
301
//===- PgmDependenceGraph.h - Enumerate the PDG for a function --*- C++ -*-===//
// 
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
// 
// The Program Dependence Graph (PDG) for a single function represents all
// data and control dependences for the function.  This file provides an
// iterator to enumerate all these dependences.  In particular, it enumerates:
// 
// -- Data dependences on memory locations, computed using the
//    MemoryDepAnalysis pass;
// -- Data dependences on SSA registers, directly from Def-Use edges of Values;
// -- Control dependences, computed using postdominance frontiers
//    (NOT YET IMPLEMENTED).
// 
// Note that this file does not create an explicit dependence graph --
// it only provides an iterator to traverse the PDG conceptually.
// The MemoryDepAnalysis does build an explicit graph, which is used internally
// here.  That graph could be augmented with the other dependences above if
// desired, but for most uses there will be little need to do that.
// 
// Key Classes:
// 
// enum PDGIteratorFlags -- Specify which dependences to enumerate.
// 
// class PDGIterator     -- The PDG iterator.  This is essentially like a
//                          pointer to class Dependence, but doesn't explicitly
//                          construct a Dependence object for each dependence.
//
// class PgmDependenceGraph -- Interface to obtain PDGIterators for each
//                          instruction.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ANALYSIS_PGMDEPENDENCEGRAPH_H
#define LLVM_ANALYSIS_PGMDEPENDENCEGRAPH_H

#include "MemoryDepAnalysis.h"
/* #include "llvm/Analysis/PostDominators.h" -- see below */
#include "llvm/Instruction.h"
#include "llvm/Pass.h"
#include "llvm/ADT/iterator"

namespace llvm {

class DSGraph;
class DependenceGraph;
class PgmDependenceGraph;

//---------------------------------------------------------------------------
/// enum PDGIteratorFlags - specify which dependences incident on a statement
/// are to be enumerated: Memory deps, SSA deps, Control deps, or any
/// combination thereof.
///
enum PDGIteratorFlags {
  MemoryDeps  = 0x1,                                 // load/store/call deps
  SSADeps     = 0x2,                                 // SSA deps (true)
  ControlDeps = /* 0x4*/ 0x0,                        // control dependences
  AllDataDeps = MemoryDeps | SSADeps,                // shorthand for data deps
  AllDeps     = MemoryDeps | SSADeps | ControlDeps   // shorthand for all three
};

//---------------------------------------------------------------------------
/// struct DepIterState - an internal implementation detail.
/// It are exposed here only to give inlinable access to field dep,
/// which is the representation for the current dependence pointed to by
/// a PgmDependenceGraph::iterator.
///
class DepIterState {
private:
  typedef char IterStateFlags;
  static const IterStateFlags NoFlag, MemDone, SSADone, AllDone, FirstTimeFlag;

public:
  DepGraphNode*              depNode;        // the node being enumerated
  DependenceGraph::iterator  memDepIter;     // pointer to current memory dep
  Instruction::op_iterator   ssaInEdgeIter;  // pointer to current SSA in-dep
  Value::use_iterator        ssaOutEdgeIter; // pointer to current SSA out-dep
  DependenceGraph*           memDepGraph;    // the core dependence graph
  Dependence                 dep;            // the "current" dependence
  PDGIteratorFlags           depFlags:8;     // which deps are we enumerating?
  IterStateFlags             iterFlags:8;    // marking where the iter stands

  DepIterState(DependenceGraph* _memDepGraph,
               Instruction&     I, 
               bool             incomingDeps,
               PDGIteratorFlags whichDeps);

  bool operator==(const DepIterState& S) {
    assert(memDepGraph == S.memDepGraph &&
           "Incompatible iterators! This is a probable sign of something BAD.");
    return (iterFlags == S.iterFlags &&
            dep == S.dep && depFlags == S.depFlags && depNode == S.depNode &&
            memDepIter == S.memDepIter && ssaInEdgeIter == S.ssaInEdgeIter &&
            ssaOutEdgeIter == S.ssaOutEdgeIter);
  }

  // Is the iteration completely done?
  // 
  bool done() const { return iterFlags & AllDone; }

  /// Next - Bump this iterator logically by 1 (to next dependence) and reset
  /// the dep field to represent the new dependence if there is one.
  /// Set done = true otherwise.
  /// 
  void Next();

  /// SetFirstMemoryDep - Find the first memory dependence for the current Mem
  /// In/Out iterators. Sets dep to that dependence and returns true if one is
  /// found. Returns false and leaves dep unchanged otherwise.
  /// 
  bool SetFirstMemoryDep();

  /// SetFirstSSADep - Find the next valid data dependence for the current SSA
  /// In/Out iterators. A valid data dependence is one that is to/from an
  /// Instruction. E.g., an SSA edge from a formal parameter is not a valid
  /// dependence. Sets dep to that dependence and returns true if a valid one is
  /// found. Returns false and leaves dep unchanged otherwise.
  ///
  bool SetFirstSSADep();
};


//---------------------------------------------------------------------------
/// PDGIterator Class - represents a pointer to a single dependence in the
/// program dependence graph.  It is essentially like a pointer to an object of
/// class Dependence but it is much more efficient to retrieve information about
/// the dependence directly rather than constructing the equivalent Dependence
/// object (since that object is normally not constructed for SSA def-use
/// dependences).
///
class PDGIterator: public forward_iterator<Dependence, ptrdiff_t> {
  DepIterState* istate;

#if 0
  /*copy*/     PDGIterator    (const PDGIterator& I);   // do not implement!
  PDGIterator& operator=      (const PDGIterator& I);   // do not implement!

  /*copy*/     PDGIterator    (PDGIterator& I) : istate(I.istate) {
    I.istate = NULL;                  // ensure this is not deleted twice.
  }
#endif

  friend class PgmDependenceGraph;

public:
  typedef PDGIterator _Self;

  PDGIterator(DepIterState* _istate) : istate(_istate) {}
  ~PDGIterator() { delete istate; }

  PDGIterator(const PDGIterator& I) :istate(new DepIterState(*I.istate)) {}

  PDGIterator& operator=(const PDGIterator& I) {
    if (istate) delete istate;
    istate = new DepIterState(*I.istate);
    return *this;
  }

  /// fini - check if the iteration is complete
  /// 
  bool fini() const { return !istate || istate->done(); }

  // Retrieve the underlying Dependence.  Returns NULL if fini().
  // 
  Dependence* operator*()  const { return fini() ?  NULL : &istate->dep; }
  Dependence* operator->() const { assert(!fini()); return &istate->dep; }

  // Increment the iterator
  // 
  _Self& operator++() { if (!fini()) istate->Next(); return *this;}
  _Self& operator++(int);   // do not implement!

  // Equality comparison: a "null" state should compare equal to done
  // This is efficient for comparing with "end" or with itself, but could
  // be quite inefficient for other cases.
  // 
  bool operator==(const PDGIterator& I) const {
    if (I.istate == NULL)               // most common case: iter == end()
      return (istate == NULL || istate->done());
    if (istate == NULL)
      return (I.istate == NULL || I.istate->done());
    return (*istate == *I.istate);
  }
  bool operator!=(const PDGIterator& I) const {
    return ! (*this == I);
  }
};


///---------------------------------------------------------------------------
/// class PgmDependenceGraph:
///
/// This pass enumerates dependences incident on each instruction in a function.
/// It can be made a FunctionPass once a Pass (such as Parallelize) is
/// allowed to use a FunctionPass such as this one.
///---------------------------------------------------------------------------

class PgmDependenceGraph: public ModulePass {

  /// Information about the function being analyzed.
  /// 
  DependenceGraph* memDepGraph;
  
  // print helper function.
  void printOutgoingSSADeps(Instruction& I, std::ostream &O);

  /// MakeIterator - creates and initializes an iterator as specified.
  ///
  PDGIterator   MakeIterator(Instruction&     I,
                             bool             incomingDeps,
                             PDGIteratorFlags whichDeps);
  
  /// MakeIterator - creates a null iterator representing end-of-iteration.
  /// 
  PDGIterator  MakeIterator() { return PDGIterator(NULL); }

  friend class PDGIterator;
  friend class DepIterState;

public:
  typedef PDGIterator iterator;
  /* typedef PDGIterator<const Dependence> const iterator; */

public:
  PgmDependenceGraph() : memDepGraph(NULL) {}
  ~PgmDependenceGraph() {}

  /// Iterators to enumerate the program dependence graph for a function.
  /// Note that this does not provide "end" iterators to check for completion.
  /// Instead, just use iterator::fini() or iterator::operator*() == NULL
  ///
  iterator  inDepBegin(Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
    return MakeIterator(I, /*inDeps*/ true, whichDeps);
  }
  iterator  inDepEnd  (Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
    return MakeIterator();
  }
  iterator  outDepBegin(Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
    return MakeIterator(I, /*inDeps*/ false, whichDeps);
  }
  iterator  outDepEnd  (Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
    return MakeIterator();
  }

  //------------------------------------------------------------------------
  /// TEMPORARY FUNCTIONS TO MAKE THIS A MODULE PASS ---
  /// These functions will go away once this class becomes a FunctionPass.

  /// Driver function to compute dependence graphs for every function.
  /// 
  bool runOnModule(Module& M) { return true; }

  /// getGraph() -- Retrieve the pgm dependence graph for a function.
  /// This is temporary and will go away once this is a FunctionPass.
  /// At that point, this class itself will be the PgmDependenceGraph you want.
  /// 
  PgmDependenceGraph& getGraph(Function& F) {
    Visiting(F);
    return *this;
  }

  private:
  void Visiting(Function& F) {
    memDepGraph = &getAnalysis<MemoryDepAnalysis>().getGraph(F);
  }
  public:
  ///----END TEMPORARY FUNCTIONS---------------------------------------------


  /// This initializes the program dependence graph iterator for a function.
  /// 
  bool runOnFunction(Function& func) {
    Visiting(func);
    return true;
  }

  /// getAnalysisUsage - This does not modify anything.
  /// It uses the Memory Dependence Analysis pass.
  /// It needs to use the PostDominanceFrontier pass, but cannot because
  /// that is a FunctionPass.  This means control dependence are not emumerated.
  ///
  void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.setPreservesAll();
    AU.addRequired<MemoryDepAnalysis>();
    /* AU.addRequired<PostDominanceFrontier>(); */
  }

  /// Debugging support methods
  /// 
  void print(std::ostream &O) const;
  void dump() const;
};

} // End llvm namespace

#endif