xref: /llvm-project/llvm/include/llvm/ADT/GenericCycleInfo.h (revision 6233346895abfb57782511cddc263d439fdd537b)
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/DenseSet.h"
32 #include "llvm/ADT/GenericSSAContext.h"
33 #include "llvm/ADT/GraphTraits.h"
34 #include "llvm/ADT/SetVector.h"
35 #include "llvm/Support/Debug.h"
36 #include "llvm/Support/raw_ostream.h"
37 
38 namespace llvm {
39 
40 template <typename ContextT> class GenericCycleInfo;
41 template <typename ContextT> class GenericCycleInfoCompute;
42 
43 /// A possibly irreducible generalization of a \ref Loop.
44 template <typename ContextT> class GenericCycle {
45 public:
46   using BlockT = typename ContextT::BlockT;
47   using FunctionT = typename ContextT::FunctionT;
48   template <typename> friend class GenericCycleInfo;
49   template <typename> friend class GenericCycleInfoCompute;
50 
51 private:
52   /// The parent cycle. Is null for the root "cycle". Top-level cycles point
53   /// at the root.
54   GenericCycle *ParentCycle = nullptr;
55 
56   /// The entry block(s) of the cycle. The header is the only entry if
57   /// this is a loop. Is empty for the root "cycle", to avoid
58   /// unnecessary memory use.
59   SmallVector<BlockT *, 1> Entries;
60 
61   /// Child cycles, if any.
62   std::vector<std::unique_ptr<GenericCycle>> Children;
63 
64   /// Basic blocks that are contained in the cycle, including entry blocks,
65   /// and including blocks that are part of a child cycle.
66   using BlockSetVectorT = SetVector<BlockT *, SmallVector<BlockT *, 8>,
67                                     DenseSet<const BlockT *>, 8>;
68   BlockSetVectorT Blocks;
69 
70   /// Depth of the cycle in the tree. The root "cycle" is at depth 0.
71   ///
72   /// \note Depths are not necessarily contiguous. However, child loops always
73   ///       have strictly greater depth than their parents, and sibling loops
74   ///       always have the same depth.
75   unsigned Depth = 0;
76 
77   /// Cache for the results of GetExitBlocks
78   mutable SmallVector<BlockT *, 4> ExitBlocksCache;
79 
80   void clear() {
81     Entries.clear();
82     Children.clear();
83     Blocks.clear();
84     Depth = 0;
85     ParentCycle = nullptr;
86     clearCache();
87   }
88 
89   void appendEntry(BlockT *Block) {
90     Entries.push_back(Block);
91     clearCache();
92   }
93 
94   void appendBlock(BlockT *Block) {
95     Blocks.insert(Block);
96     clearCache();
97   }
98 
99   GenericCycle(const GenericCycle &) = delete;
100   GenericCycle &operator=(const GenericCycle &) = delete;
101   GenericCycle(GenericCycle &&Rhs) = delete;
102   GenericCycle &operator=(GenericCycle &&Rhs) = delete;
103 
104 public:
105   GenericCycle() = default;
106 
107   /// \brief Whether the cycle is a natural loop.
108   bool isReducible() const { return Entries.size() == 1; }
109 
110   BlockT *getHeader() const { return Entries[0]; }
111 
112   const SmallVectorImpl<BlockT *> & getEntries() const {
113     return Entries;
114   }
115 
116   /// Clear the cache of the cycle.
117   /// This should be run in all non-const function in GenericCycle
118   /// and GenericCycleInfo.
119   void clearCache() const { ExitBlocksCache.clear(); }
120 
121   /// \brief Return whether \p Block is an entry block of the cycle.
122   bool isEntry(const BlockT *Block) const {
123     return is_contained(Entries, Block);
124   }
125 
126   /// \brief Replace all entries with \p Block as single entry.
127   void setSingleEntry(BlockT *Block) {
128     assert(contains(Block));
129     Entries.clear();
130     Entries.push_back(Block);
131     clearCache();
132   }
133 
134   /// \brief Return whether \p Block is contained in the cycle.
135   bool contains(const BlockT *Block) const { return Blocks.contains(Block); }
136 
137   /// \brief Returns true iff this cycle contains \p C.
138   ///
139   /// Note: Non-strict containment check, i.e. returns true if C is the
140   /// same cycle.
141   bool contains(const GenericCycle *C) const;
142 
143   const GenericCycle *getParentCycle() const { return ParentCycle; }
144   GenericCycle *getParentCycle() { return ParentCycle; }
145   unsigned getDepth() const { return Depth; }
146 
147   /// Return all of the successor blocks of this cycle.
148   ///
149   /// These are the blocks _outside of the current cycle_ which are
150   /// branched to.
151   void getExitBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
152 
153   /// Return all blocks of this cycle that have successor outside of this cycle.
154   /// These blocks have cycle exit branch.
155   void getExitingBlocks(SmallVectorImpl<BlockT *> &TmpStorage) const;
156 
157   /// Return the preheader block for this cycle. Pre-header is well-defined for
158   /// reducible cycle in docs/LoopTerminology.rst as: the only one entering
159   /// block and its only edge is to the entry block. Return null for irreducible
160   /// cycles.
161   BlockT *getCyclePreheader() const;
162 
163   /// If the cycle has exactly one entry with exactly one predecessor, return
164   /// it, otherwise return nullptr.
165   BlockT *getCyclePredecessor() const;
166 
167   void verifyCycle() const;
168   void verifyCycleNest() const;
169 
170   /// Iteration over child cycles.
171   //@{
172   using const_child_iterator_base =
173       typename std::vector<std::unique_ptr<GenericCycle>>::const_iterator;
174   struct const_child_iterator
175       : iterator_adaptor_base<const_child_iterator, const_child_iterator_base> {
176     using Base =
177         iterator_adaptor_base<const_child_iterator, const_child_iterator_base>;
178 
179     const_child_iterator() = default;
180     explicit const_child_iterator(const_child_iterator_base I) : Base(I) {}
181 
182     const const_child_iterator_base &wrapped() { return Base::wrapped(); }
183     GenericCycle *operator*() const { return Base::I->get(); }
184   };
185 
186   const_child_iterator child_begin() const {
187     return const_child_iterator{Children.begin()};
188   }
189   const_child_iterator child_end() const {
190     return const_child_iterator{Children.end()};
191   }
192   size_t getNumChildren() const { return Children.size(); }
193   iterator_range<const_child_iterator> children() const {
194     return llvm::make_range(const_child_iterator{Children.begin()},
195                             const_child_iterator{Children.end()});
196   }
197   //@}
198 
199   /// Iteration over blocks in the cycle (including entry blocks).
200   //@{
201   using const_block_iterator = typename BlockSetVectorT::const_iterator;
202 
203   const_block_iterator block_begin() const {
204     return const_block_iterator{Blocks.begin()};
205   }
206   const_block_iterator block_end() const {
207     return const_block_iterator{Blocks.end()};
208   }
209   size_t getNumBlocks() const { return Blocks.size(); }
210   iterator_range<const_block_iterator> blocks() const {
211     return llvm::make_range(block_begin(), block_end());
212   }
213   //@}
214 
215   /// Iteration over entry blocks.
216   //@{
217   using const_entry_iterator =
218       typename SmallVectorImpl<BlockT *>::const_iterator;
219   const_entry_iterator entry_begin() const { return Entries.begin(); }
220   const_entry_iterator entry_end() const { return Entries.end(); }
221   size_t getNumEntries() const { return Entries.size(); }
222   iterator_range<const_entry_iterator> entries() const {
223     return llvm::make_range(entry_begin(), entry_end());
224   }
225   using const_reverse_entry_iterator =
226       typename SmallVectorImpl<BlockT *>::const_reverse_iterator;
227   const_reverse_entry_iterator entry_rbegin() const { return Entries.rbegin(); }
228   const_reverse_entry_iterator entry_rend() const { return Entries.rend(); }
229   //@}
230 
231   Printable printEntries(const ContextT &Ctx) const {
232     return Printable([this, &Ctx](raw_ostream &Out) {
233       bool First = true;
234       for (auto *Entry : Entries) {
235         if (!First)
236           Out << ' ';
237         First = false;
238         Out << Ctx.print(Entry);
239       }
240     });
241   }
242 
243   Printable print(const ContextT &Ctx) const {
244     return Printable([this, &Ctx](raw_ostream &Out) {
245       Out << "depth=" << Depth << ": entries(" << printEntries(Ctx) << ')';
246 
247       for (auto *Block : Blocks) {
248         if (isEntry(Block))
249           continue;
250 
251         Out << ' ' << Ctx.print(Block);
252       }
253     });
254   }
255 };
256 
257 /// \brief Cycle information for a function.
258 template <typename ContextT> class GenericCycleInfo {
259 public:
260   using BlockT = typename ContextT::BlockT;
261   using CycleT = GenericCycle<ContextT>;
262   using FunctionT = typename ContextT::FunctionT;
263   template <typename> friend class GenericCycle;
264   template <typename> friend class GenericCycleInfoCompute;
265 
266 private:
267   ContextT Context;
268 
269   /// Map basic blocks to their inner-most containing cycle.
270   DenseMap<BlockT *, CycleT *> BlockMap;
271 
272   /// Map basic blocks to their top level containing cycle.
273   DenseMap<BlockT *, CycleT *> BlockMapTopLevel;
274 
275   /// Top-level cycles discovered by any DFS.
276   ///
277   /// Note: The implementation treats the nullptr as the parent of
278   /// every top-level cycle. See \ref contains for an example.
279   std::vector<std::unique_ptr<CycleT>> TopLevelCycles;
280 
281   /// Move \p Child to \p NewParent by manipulating Children vectors.
282   ///
283   /// Note: This is an incomplete operation that does not update the depth of
284   /// the subtree.
285   void moveTopLevelCycleToNewParent(CycleT *NewParent, CycleT *Child);
286 
287 public:
288   GenericCycleInfo() = default;
289   GenericCycleInfo(GenericCycleInfo &&) = default;
290   GenericCycleInfo &operator=(GenericCycleInfo &&) = default;
291 
292   void clear();
293   void compute(FunctionT &F);
294   void splitCriticalEdge(BlockT *Pred, BlockT *Succ, BlockT *New);
295 
296   const FunctionT *getFunction() const { return Context.getFunction(); }
297   const ContextT &getSSAContext() const { return Context; }
298 
299   CycleT *getCycle(const BlockT *Block) const;
300   CycleT *getSmallestCommonCycle(CycleT *A, CycleT *B) const;
301   unsigned getCycleDepth(const BlockT *Block) const;
302   CycleT *getTopLevelParentCycle(BlockT *Block);
303 
304   /// Assumes that \p Cycle is the innermost cycle containing \p Block.
305   /// \p Block will be appended to \p Cycle and all of its parent cycles.
306   /// \p Block will be added to BlockMap with \p Cycle and
307   /// BlockMapTopLevel with \p Cycle's top level parent cycle.
308   void addBlockToCycle(BlockT *Block, CycleT *Cycle);
309 
310   /// Methods for debug and self-test.
311   //@{
312   void verifyCycleNest(bool VerifyFull = false) const;
313   void verify() const;
314   void print(raw_ostream &Out) const;
315   void dump() const { print(dbgs()); }
316   Printable print(const CycleT *Cycle) { return Cycle->print(Context); }
317   //@}
318 
319   /// Iteration over top-level cycles.
320   //@{
321   using const_toplevel_iterator_base =
322       typename std::vector<std::unique_ptr<CycleT>>::const_iterator;
323   struct const_toplevel_iterator
324       : iterator_adaptor_base<const_toplevel_iterator,
325                               const_toplevel_iterator_base> {
326     using Base = iterator_adaptor_base<const_toplevel_iterator,
327                                        const_toplevel_iterator_base>;
328 
329     const_toplevel_iterator() = default;
330     explicit const_toplevel_iterator(const_toplevel_iterator_base I)
331         : Base(I) {}
332 
333     const const_toplevel_iterator_base &wrapped() { return Base::wrapped(); }
334     CycleT *operator*() const { return Base::I->get(); }
335   };
336 
337   const_toplevel_iterator toplevel_begin() const {
338     return const_toplevel_iterator{TopLevelCycles.begin()};
339   }
340   const_toplevel_iterator toplevel_end() const {
341     return const_toplevel_iterator{TopLevelCycles.end()};
342   }
343 
344   iterator_range<const_toplevel_iterator> toplevel_cycles() const {
345     return llvm::make_range(const_toplevel_iterator{TopLevelCycles.begin()},
346                             const_toplevel_iterator{TopLevelCycles.end()});
347   }
348   //@}
349 };
350 
351 /// \brief GraphTraits for iterating over a sub-tree of the CycleT tree.
352 template <typename CycleRefT, typename ChildIteratorT> struct CycleGraphTraits {
353   using NodeRef = CycleRefT;
354 
355   using nodes_iterator = ChildIteratorT;
356   using ChildIteratorType = nodes_iterator;
357 
358   static NodeRef getEntryNode(NodeRef Graph) { return Graph; }
359 
360   static ChildIteratorType child_begin(NodeRef Ref) {
361     return Ref->child_begin();
362   }
363   static ChildIteratorType child_end(NodeRef Ref) { return Ref->child_end(); }
364 
365   // Not implemented:
366   // static nodes_iterator nodes_begin(GraphType *G)
367   // static nodes_iterator nodes_end  (GraphType *G)
368   //    nodes_iterator/begin/end - Allow iteration over all nodes in the graph
369 
370   // typedef EdgeRef           - Type of Edge token in the graph, which should
371   //                             be cheap to copy.
372   // typedef ChildEdgeIteratorType - Type used to iterate over children edges in
373   //                             graph, dereference to a EdgeRef.
374 
375   // static ChildEdgeIteratorType child_edge_begin(NodeRef)
376   // static ChildEdgeIteratorType child_edge_end(NodeRef)
377   //     Return iterators that point to the beginning and ending of the
378   //     edge list for the given callgraph node.
379   //
380   // static NodeRef edge_dest(EdgeRef)
381   //     Return the destination node of an edge.
382   // static unsigned       size       (GraphType *G)
383   //    Return total number of nodes in the graph
384 };
385 
386 template <typename BlockT>
387 struct GraphTraits<const GenericCycle<BlockT> *>
388     : CycleGraphTraits<const GenericCycle<BlockT> *,
389                        typename GenericCycle<BlockT>::const_child_iterator> {};
390 template <typename BlockT>
391 struct GraphTraits<GenericCycle<BlockT> *>
392     : CycleGraphTraits<GenericCycle<BlockT> *,
393                        typename GenericCycle<BlockT>::const_child_iterator> {};
394 
395 } // namespace llvm
396 
397 #endif // LLVM_ADT_GENERICCYCLEINFO_H
398