Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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 |