1 //===- IntervalIterator.h - Interval Iterator Declaration -------*- 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 // This file defines an iterator that enumerates the intervals in a control flow
10 // graph of some sort.  This iterator is parametric, allowing iterator over the
11 // following types of graphs:
12 //
13 //  1. A Function* object, composed of BasicBlock nodes.
14 //  2. An IntervalPartition& object, composed of Interval nodes.
15 //
16 // This iterator is defined to walk the control flow graph, returning intervals
17 // in depth first order.  These intervals are completely filled in except for
18 // the predecessor fields (the successor information is filled in however).
19 //
20 // By default, the intervals created by this iterator are deleted after they
21 // are no longer any use to the iterator.  This behavior can be changed by
22 // passing a false value into the intervals_begin() function. This causes the
23 // IOwnMem member to be set, and the intervals to not be deleted.
24 //
25 // It is only safe to use this if all of the intervals are deleted by the caller
26 // and all of the intervals are processed.  However, the user of the iterator is
27 // not allowed to modify or delete the intervals until after the iterator has
28 // been used completely.  The IntervalPartition class uses this functionality.
29 //
30 //===----------------------------------------------------------------------===//
31 
32 #ifndef LLVM_ANALYSIS_INTERVALITERATOR_H
33 #define LLVM_ANALYSIS_INTERVALITERATOR_H
34 
35 #include "llvm/ADT/GraphTraits.h"
36 #include "llvm/Analysis/Interval.h"
37 #include "llvm/Analysis/IntervalPartition.h"
38 #include "llvm/IR/CFG.h"
39 #include <algorithm>
40 #include <cassert>
41 #include <iterator>
42 #include <set>
43 #include <utility>
44 #include <vector>
45 
46 namespace llvm {
47 
48 class BasicBlock;
49 class Function;
50 
51 // getNodeHeader - Given a source graph node and the source graph, return the
52 // BasicBlock that is the header node.  This is the opposite of
53 // getSourceGraphNode.
54 inline BasicBlock *getNodeHeader(BasicBlock *BB) { return BB; }
55 inline BasicBlock *getNodeHeader(Interval *I) { return I->getHeaderNode(); }
56 
57 // getSourceGraphNode - Given a BasicBlock and the source graph, return the
58 // source graph node that corresponds to the BasicBlock.  This is the opposite
59 // of getNodeHeader.
60 inline BasicBlock *getSourceGraphNode(Function *, BasicBlock *BB) {
61   return BB;
62 }
63 inline Interval *getSourceGraphNode(IntervalPartition *IP, BasicBlock *BB) {
64   return IP->getBlockInterval(BB);
65 }
66 
67 // addNodeToInterval - This method exists to assist the generic ProcessNode
68 // with the task of adding a node to the new interval, depending on the
69 // type of the source node.  In the case of a CFG source graph (BasicBlock
70 // case), the BasicBlock itself is added to the interval.
71 inline void addNodeToInterval(Interval *Int, BasicBlock *BB) {
72   Int->Nodes.push_back(BB);
73 }
74 
75 // addNodeToInterval - This method exists to assist the generic ProcessNode
76 // with the task of adding a node to the new interval, depending on the
77 // type of the source node.  In the case of a CFG source graph (BasicBlock
78 // case), the BasicBlock itself is added to the interval.  In the case of
79 // an IntervalPartition source graph (Interval case), all of the member
80 // BasicBlocks are added to the interval.
81 inline void addNodeToInterval(Interval *Int, Interval *I) {
82   // Add all of the nodes in I as new nodes in Int.
83   llvm::append_range(Int->Nodes, I->Nodes);
84 }
85 
86 template<class NodeTy, class OrigContainer_t, class GT = GraphTraits<NodeTy *>,
87          class IGT = GraphTraits<Inverse<NodeTy *>>>
88 class IntervalIterator {
89   std::vector<std::pair<Interval *, typename Interval::succ_iterator>> IntStack;
90   std::set<BasicBlock *> Visited;
91   OrigContainer_t *OrigContainer;
92   bool IOwnMem;     // If True, delete intervals when done with them
93                     // See file header for conditions of use
94 
95 public:
96   using iterator_category = std::forward_iterator_tag;
97 
98   IntervalIterator() = default; // End iterator, empty stack
99 
100   IntervalIterator(Function *M, bool OwnMemory) : IOwnMem(OwnMemory) {
101     OrigContainer = M;
102     if (!ProcessInterval(&M->front())) {
103       llvm_unreachable("ProcessInterval should never fail for first interval!");
104     }
105   }
106 
107   IntervalIterator(IntervalIterator &&x)
108       : IntStack(std::move(x.IntStack)), Visited(std::move(x.Visited)),
109         OrigContainer(x.OrigContainer), IOwnMem(x.IOwnMem) {
110     x.IOwnMem = false;
111   }
112 
113   IntervalIterator(IntervalPartition &IP, bool OwnMemory) : IOwnMem(OwnMemory) {
114     OrigContainer = &IP;
115     if (!ProcessInterval(IP.getRootInterval())) {
116       llvm_unreachable("ProcessInterval should never fail for first interval!");
117     }
118   }
119 
120   ~IntervalIterator() {
121     if (IOwnMem)
122       while (!IntStack.empty()) {
123         delete operator*();
124         IntStack.pop_back();
125       }
126   }
127 
128   bool operator==(const IntervalIterator &x) const {
129     return IntStack == x.IntStack;
130   }
131   bool operator!=(const IntervalIterator &x) const { return !(*this == x); }
132 
133   const Interval *operator*() const { return IntStack.back().first; }
134   Interval *operator*() { return IntStack.back().first; }
135   const Interval *operator->() const { return operator*(); }
136   Interval *operator->() { return operator*(); }
137 
138   IntervalIterator &operator++() { // Preincrement
139     assert(!IntStack.empty() && "Attempting to use interval iterator at end!");
140     do {
141       // All of the intervals on the stack have been visited.  Try visiting
142       // their successors now.
143       Interval::succ_iterator &SuccIt = IntStack.back().second,
144                                 EndIt = succ_end(IntStack.back().first);
145       while (SuccIt != EndIt) {                 // Loop over all interval succs
146         bool Done = ProcessInterval(getSourceGraphNode(OrigContainer, *SuccIt));
147         ++SuccIt;                               // Increment iterator
148         if (Done) return *this;                 // Found a new interval! Use it!
149       }
150 
151       // Free interval memory... if necessary
152       if (IOwnMem) delete IntStack.back().first;
153 
154       // We ran out of successors for this interval... pop off the stack
155       IntStack.pop_back();
156     } while (!IntStack.empty());
157 
158     return *this;
159   }
160 
161   IntervalIterator operator++(int) { // Postincrement
162     IntervalIterator tmp = *this;
163     ++*this;
164     return tmp;
165   }
166 
167 private:
168   // ProcessInterval - This method is used during the construction of the
169   // interval graph.  It walks through the source graph, recursively creating
170   // an interval per invocation until the entire graph is covered.  This uses
171   // the ProcessNode method to add all of the nodes to the interval.
172   //
173   // This method is templated because it may operate on two different source
174   // graphs: a basic block graph, or a preexisting interval graph.
175   bool ProcessInterval(NodeTy *Node) {
176     BasicBlock *Header = getNodeHeader(Node);
177     if (!Visited.insert(Header).second)
178       return false;
179 
180     Interval *Int = new Interval(Header);
181 
182     // Check all of our successors to see if they are in the interval...
183     for (typename GT::ChildIteratorType I = GT::child_begin(Node),
184            E = GT::child_end(Node); I != E; ++I)
185       ProcessNode(Int, getSourceGraphNode(OrigContainer, *I));
186 
187     IntStack.push_back(std::make_pair(Int, succ_begin(Int)));
188     return true;
189   }
190 
191   // ProcessNode - This method is called by ProcessInterval to add nodes to the
192   // interval being constructed, and it is also called recursively as it walks
193   // the source graph.  A node is added to the current interval only if all of
194   // its predecessors are already in the graph.  This also takes care of keeping
195   // the successor set of an interval up to date.
196   //
197   // This method is templated because it may operate on two different source
198   // graphs: a basic block graph, or a preexisting interval graph.
199   void ProcessNode(Interval *Int, NodeTy *Node) {
200     assert(Int && "Null interval == bad!");
201     assert(Node && "Null Node == bad!");
202 
203     BasicBlock *NodeHeader = getNodeHeader(Node);
204 
205     if (Visited.count(NodeHeader)) {     // Node already been visited?
206       if (Int->contains(NodeHeader)) {   // Already in this interval...
207         return;
208       } else {                           // In other interval, add as successor
209         if (!Int->isSuccessor(NodeHeader)) // Add only if not already in set
210           Int->Successors.push_back(NodeHeader);
211       }
212     } else {                             // Otherwise, not in interval yet
213       for (typename IGT::ChildIteratorType I = IGT::child_begin(Node),
214              E = IGT::child_end(Node); I != E; ++I) {
215         if (!Int->contains(*I)) {        // If pred not in interval, we can't be
216           if (!Int->isSuccessor(NodeHeader)) // Add only if not already in set
217             Int->Successors.push_back(NodeHeader);
218           return;                        // See you later
219         }
220       }
221 
222       // If we get here, then all of the predecessors of BB are in the interval
223       // already.  In this case, we must add BB to the interval!
224       addNodeToInterval(Int, Node);
225       Visited.insert(NodeHeader);     // The node has now been visited!
226 
227       if (Int->isSuccessor(NodeHeader)) {
228         // If we were in the successor list from before... remove from succ list
229         llvm::erase_value(Int->Successors, NodeHeader);
230       }
231 
232       // Now that we have discovered that Node is in the interval, perhaps some
233       // of its successors are as well?
234       for (typename GT::ChildIteratorType It = GT::child_begin(Node),
235              End = GT::child_end(Node); It != End; ++It)
236         ProcessNode(Int, getSourceGraphNode(OrigContainer, *It));
237     }
238   }
239 };
240 
241 using function_interval_iterator = IntervalIterator<BasicBlock, Function>;
242 using interval_part_interval_iterator =
243     IntervalIterator<Interval, IntervalPartition>;
244 
245 inline function_interval_iterator intervals_begin(Function *F,
246                                                   bool DeleteInts = true) {
247   return function_interval_iterator(F, DeleteInts);
248 }
249 inline function_interval_iterator intervals_end(Function *) {
250   return function_interval_iterator();
251 }
252 
253 inline interval_part_interval_iterator
254    intervals_begin(IntervalPartition &IP, bool DeleteIntervals = true) {
255   return interval_part_interval_iterator(IP, DeleteIntervals);
256 }
257 
258 inline interval_part_interval_iterator intervals_end(IntervalPartition &IP) {
259   return interval_part_interval_iterator();
260 }
261 
262 } // end namespace llvm
263 
264 #endif // LLVM_ANALYSIS_INTERVALITERATOR_H
265