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 |