Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 1
//===- GenericCycleInfo.h - Info for Cycles in any IR ------*- C++ -*------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// \brief Find all cycles in a control-flow graph, including irreducible loops.
11
///
12
/// See docs/CycleTerminology.rst for a formal definition of cycles.
13
///
14
/// Briefly:
15
/// - A cycle is a generalization of a loop which can represent
16
///   irreducible control flow.
17
/// - Cycles identified in a program are implementation defined,
18
///   depending on the DFS traversal chosen.
19
/// - Cycles are well-nested, and form a forest with a parent-child
20
///   relationship.
21
/// - In any choice of DFS, every natural loop L is represented by a
22
///   unique cycle C which is a superset of L.
23
/// - In the absence of irreducible control flow, the cycles are
24
///   exactly the natural loops in the program.
25
///
26
//===----------------------------------------------------------------------===//
27
 
28
#ifndef LLVM_ADT_GENERICCYCLEINFO_H
29
#define LLVM_ADT_GENERICCYCLEINFO_H
30
 
31
#include "llvm/ADT/ArrayRef.h"
32
#include "llvm/ADT/DenseMap.h"
33
#include "llvm/ADT/GenericSSAContext.h"
34
#include "llvm/ADT/GraphTraits.h"
35
#include "llvm/ADT/SmallVector.h"
36
#include "llvm/ADT/iterator.h"
37
#include "llvm/Support/Debug.h"
38
#include "llvm/Support/Printable.h"
39
#include "llvm/Support/raw_ostream.h"
40
#include <vector>
41
 
42
namespace llvm {
43
 
44
template <typename ContextT> class GenericCycleInfo;
45
template <typename ContextT> class GenericCycleInfoCompute;
46
 
47
/// A possibly irreducible generalization of a \ref Loop.
48
template <typename ContextT> class GenericCycle {
49
public:
50
  using BlockT = typename ContextT::BlockT;
51
  using FunctionT = typename ContextT::FunctionT;
52
  template <typename> friend class GenericCycleInfo;
53
  template <typename> friend class GenericCycleInfoCompute;
54
 
55
private:
56
  /// The parent cycle. Is null for the root "cycle". Top-level cycles point
57
  /// at the root.
58
  GenericCycle *ParentCycle = nullptr;
59
 
60
  /// The entry block(s) of the cycle. The header is the only entry if
61
  /// this is a loop. Is empty for the root "cycle", to avoid
62
  /// unnecessary memory use.
63
  SmallVector<BlockT *, 1> Entries;
64
 
65
  /// Child cycles, if any.
66
  std::vector<std::unique_ptr<GenericCycle>> Children;
67
 
68
  /// Basic blocks that are contained in the cycle, including entry blocks,
69
  /// and including blocks that are part of a child cycle.
70
  std::vector<BlockT *> Blocks;
71
 
72
  /// Depth of the cycle in the tree. The root "cycle" is at depth 0.
73
  ///
74
  /// \note Depths are not necessarily contiguous. However, child loops always
75
  ///       have strictly greater depth than their parents, and sibling loops
76
  ///       always have the same depth.
77
  unsigned Depth = 0;
78
 
79
  void clear() {
80
    Entries.clear();
81
    Children.clear();
82
    Blocks.clear();
83
    Depth = 0;
84
    ParentCycle = nullptr;
85
  }
86
 
87
  void appendEntry(BlockT *Block) { Entries.push_back(Block); }
88
  void appendBlock(BlockT *Block) { Blocks.push_back(Block); }
89
 
90
  GenericCycle(const GenericCycle &) = delete;
91
  GenericCycle &operator=(const GenericCycle &) = delete;
92
  GenericCycle(GenericCycle &&Rhs) = delete;
93
  GenericCycle &operator=(GenericCycle &&Rhs) = delete;
94
 
95
public:
96
  GenericCycle() = default;
97
 
98
  /// \brief Whether the cycle is a natural loop.
99
  bool isReducible() const { return Entries.size() == 1; }
100
 
101
  BlockT *getHeader() const { return Entries[0]; }
102
 
103
  const SmallVectorImpl<BlockT *> & getEntries() const {
104
    return Entries;
105
  }
106
 
107
  /// \brief Return whether \p Block is an entry block of the cycle.
108
  bool isEntry(const BlockT *Block) const {
109
    return is_contained(Entries, Block);
110
  }
111
 
112
  /// \brief Return whether \p Block is contained in the cycle.
113
  bool contains(const BlockT *Block) const {
114
    return is_contained(Blocks, Block);
115
  }
116
 
117
  /// \brief Returns true iff this cycle contains \p C.
118
  ///
119
  /// Note: Non-strict containment check, i.e. returns true if C is the
120
  /// same cycle.
121
  bool contains(const GenericCycle *C) const;
122
 
123
  const GenericCycle *getParentCycle() const { return ParentCycle; }
124
  GenericCycle *getParentCycle() { return ParentCycle; }
125
  unsigned getDepth() const { return Depth; }
126
 
127
  /// Return all of the successor blocks of this cycle.
128
  ///
129
  /// These are the blocks _outside of the current cycle_ which are
130
  /// branched to.
131
  void getExitBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
132
 
133
  /// Return the preheader block for this cycle. Pre-header is well-defined for
134
  /// reducible cycle in docs/LoopTerminology.rst as: the only one entering
135
  /// block and its only edge is to the entry block. Return null for irreducible
136
  /// cycles.
137
  BlockT *getCyclePreheader() const;
138
 
139
  /// If the cycle has exactly one entry with exactly one predecessor, return
140
  /// it, otherwise return nullptr.
141
  BlockT *getCyclePredecessor() const;
142
 
143
  /// Iteration over child cycles.
144
  //@{
145
  using const_child_iterator_base =
146
      typename std::vector<std::unique_ptr<GenericCycle>>::const_iterator;
147
  struct const_child_iterator
148
      : iterator_adaptor_base<const_child_iterator, const_child_iterator_base> {
149
    using Base =
150
        iterator_adaptor_base<const_child_iterator, const_child_iterator_base>;
151
 
152
    const_child_iterator() = default;
153
    explicit const_child_iterator(const_child_iterator_base I) : Base(I) {}
154
 
155
    const const_child_iterator_base &wrapped() { return Base::wrapped(); }
156
    GenericCycle *operator*() const { return Base::I->get(); }
157
  };
158
 
159
  const_child_iterator child_begin() const {
160
    return const_child_iterator{Children.begin()};
161
  }
162
  const_child_iterator child_end() const {
163
    return const_child_iterator{Children.end()};
164
  }
165
  size_t getNumChildren() const { return Children.size(); }
166
  iterator_range<const_child_iterator> children() const {
167
    return llvm::make_range(const_child_iterator{Children.begin()},
168
                            const_child_iterator{Children.end()});
169
  }
170
  //@}
171
 
172
  /// Iteration over blocks in the cycle (including entry blocks).
173
  //@{
174
  using const_block_iterator = typename std::vector<BlockT *>::const_iterator;
175
 
176
  const_block_iterator block_begin() const {
177
    return const_block_iterator{Blocks.begin()};
178
  }
179
  const_block_iterator block_end() const {
180
    return const_block_iterator{Blocks.end()};
181
  }
182
  size_t getNumBlocks() const { return Blocks.size(); }
183
  iterator_range<const_block_iterator> blocks() const {
184
    return llvm::make_range(block_begin(), block_end());
185
  }
186
  //@}
187
 
188
  /// Iteration over entry blocks.
189
  //@{
190
  using const_entry_iterator =
191
      typename SmallVectorImpl<BlockT *>::const_iterator;
192
 
193
  size_t getNumEntries() const { return Entries.size(); }
194
  iterator_range<const_entry_iterator> entries() const {
195
    return llvm::make_range(Entries.begin(), Entries.end());
196
  }
197
  //@}
198
 
199
  Printable printEntries(const ContextT &Ctx) const {
200
    return Printable([this, &Ctx](raw_ostream &Out) {
201
      bool First = true;
202
      for (auto *Entry : Entries) {
203
        if (!First)
204
          Out << ' ';
205
        First = false;
206
        Out << Ctx.print(Entry);
207
      }
208
    });
209
  }
210
 
211
  Printable print(const ContextT &Ctx) const {
212
    return Printable([this, &Ctx](raw_ostream &Out) {
213
      Out << "depth=" << Depth << ": entries(" << printEntries(Ctx) << ')';
214
 
215
      for (auto *Block : Blocks) {
216
        if (isEntry(Block))
217
          continue;
218
 
219
        Out << ' ' << Ctx.print(Block);
220
      }
221
    });
222
  }
223
};
224
 
225
/// \brief Cycle information for a function.
226
template <typename ContextT> class GenericCycleInfo {
227
public:
228
  using BlockT = typename ContextT::BlockT;
229
  using CycleT = GenericCycle<ContextT>;
230
  using FunctionT = typename ContextT::FunctionT;
231
  template <typename> friend class GenericCycle;
232
  template <typename> friend class GenericCycleInfoCompute;
233
 
234
private:
235
  ContextT Context;
236
 
237
  /// Map basic blocks to their inner-most containing cycle.
238
  DenseMap<BlockT *, CycleT *> BlockMap;
239
 
240
  /// Map basic blocks to their top level containing cycle.
241
  DenseMap<BlockT *, CycleT *> BlockMapTopLevel;
242
 
243
  /// Top-level cycles discovered by any DFS.
244
  ///
245
  /// Note: The implementation treats the nullptr as the parent of
246
  /// every top-level cycle. See \ref contains for an example.
247
  std::vector<std::unique_ptr<CycleT>> TopLevelCycles;
248
 
249
  /// Move \p Child to \p NewParent by manipulating Children vectors.
250
  ///
251
  /// Note: This is an incomplete operation that does not update the depth of
252
  /// the subtree.
253
  void moveTopLevelCycleToNewParent(CycleT *NewParent, CycleT *Child);
254
 
255
public:
256
  GenericCycleInfo() = default;
257
  GenericCycleInfo(GenericCycleInfo &&) = default;
258
  GenericCycleInfo &operator=(GenericCycleInfo &&) = default;
259
 
260
  void clear();
261
  void compute(FunctionT &F);
262
 
263
  FunctionT *getFunction() const { return Context.getFunction(); }
264
  const ContextT &getSSAContext() const { return Context; }
265
 
266
  CycleT *getCycle(const BlockT *Block) const;
267
  unsigned getCycleDepth(const BlockT *Block) const;
268
  CycleT *getTopLevelParentCycle(BlockT *Block);
269
 
270
  /// Methods for debug and self-test.
271
  //@{
272
#ifndef NDEBUG
273
  bool validateTree() const;
274
#endif
275
  void print(raw_ostream &Out) const;
276
  void dump() const { print(dbgs()); }
277
  //@}
278
 
279
  /// Iteration over top-level cycles.
280
  //@{
281
  using const_toplevel_iterator_base =
282
      typename std::vector<std::unique_ptr<CycleT>>::const_iterator;
283
  struct const_toplevel_iterator
284
      : iterator_adaptor_base<const_toplevel_iterator,
285
                              const_toplevel_iterator_base> {
286
    using Base = iterator_adaptor_base<const_toplevel_iterator,
287
                                       const_toplevel_iterator_base>;
288
 
289
    const_toplevel_iterator() = default;
290
    explicit const_toplevel_iterator(const_toplevel_iterator_base I)
291
        : Base(I) {}
292
 
293
    const const_toplevel_iterator_base &wrapped() { return Base::wrapped(); }
294
    CycleT *operator*() const { return Base::I->get(); }
295
  };
296
 
297
  const_toplevel_iterator toplevel_begin() const {
298
    return const_toplevel_iterator{TopLevelCycles.begin()};
299
  }
300
  const_toplevel_iterator toplevel_end() const {
301
    return const_toplevel_iterator{TopLevelCycles.end()};
302
  }
303
 
304
  iterator_range<const_toplevel_iterator> toplevel_cycles() const {
305
    return llvm::make_range(const_toplevel_iterator{TopLevelCycles.begin()},
306
                            const_toplevel_iterator{TopLevelCycles.end()});
307
  }
308
  //@}
309
};
310
 
311
/// \brief GraphTraits for iterating over a sub-tree of the CycleT tree.
312
template <typename CycleRefT, typename ChildIteratorT> struct CycleGraphTraits {
313
  using NodeRef = CycleRefT;
314
 
315
  using nodes_iterator = ChildIteratorT;
316
  using ChildIteratorType = nodes_iterator;
317
 
318
  static NodeRef getEntryNode(NodeRef Graph) { return Graph; }
319
 
320
  static ChildIteratorType child_begin(NodeRef Ref) {
321
    return Ref->child_begin();
322
  }
323
  static ChildIteratorType child_end(NodeRef Ref) { return Ref->child_end(); }
324
 
325
  // Not implemented:
326
  // static nodes_iterator nodes_begin(GraphType *G)
327
  // static nodes_iterator nodes_end  (GraphType *G)
328
  //    nodes_iterator/begin/end - Allow iteration over all nodes in the graph
329
 
330
  // typedef EdgeRef           - Type of Edge token in the graph, which should
331
  //                             be cheap to copy.
332
  // typedef ChildEdgeIteratorType - Type used to iterate over children edges in
333
  //                             graph, dereference to a EdgeRef.
334
 
335
  // static ChildEdgeIteratorType child_edge_begin(NodeRef)
336
  // static ChildEdgeIteratorType child_edge_end(NodeRef)
337
  //     Return iterators that point to the beginning and ending of the
338
  //     edge list for the given callgraph node.
339
  //
340
  // static NodeRef edge_dest(EdgeRef)
341
  //     Return the destination node of an edge.
342
  // static unsigned       size       (GraphType *G)
343
  //    Return total number of nodes in the graph
344
};
345
 
346
template <typename BlockT>
347
struct GraphTraits<const GenericCycle<BlockT> *>
348
    : CycleGraphTraits<const GenericCycle<BlockT> *,
349
                       typename GenericCycle<BlockT>::const_child_iterator> {};
350
template <typename BlockT>
351
struct GraphTraits<GenericCycle<BlockT> *>
352
    : CycleGraphTraits<GenericCycle<BlockT> *,
353
                       typename GenericCycle<BlockT>::const_child_iterator> {};
354
 
355
} // namespace llvm
356
 
357
#endif // LLVM_ADT_GENERICCYCLEINFO_H