Home | History | Annotate | Download | only in Analysis
      1 //===- IntervalIterator.h - Interval Iterator Declaration -------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines an iterator that enumerates the intervals in a control flow
     11 // graph of some sort.  This iterator is parametric, allowing iterator over the
     12 // following types of graphs:
     13 //
     14 //  1. A Function* object, composed of BasicBlock nodes.
     15 //  2. An IntervalPartition& object, composed of Interval nodes.
     16 //
     17 // This iterator is defined to walk the control flow graph, returning intervals
     18 // in depth first order.  These intervals are completely filled in except for
     19 // the predecessor fields (the successor information is filled in however).
     20 //
     21 // By default, the intervals created by this iterator are deleted after they
     22 // are no longer any use to the iterator.  This behavior can be changed by
     23 // passing a false value into the intervals_begin() function. This causes the
     24 // IOwnMem member to be set, and the intervals to not be deleted.
     25 //
     26 // It is only safe to use this if all of the intervals are deleted by the caller
     27 // and all of the intervals are processed.  However, the user of the iterator is
     28 // not allowed to modify or delete the intervals until after the iterator has
     29 // been used completely.  The IntervalPartition class uses this functionality.
     30 //
     31 //===----------------------------------------------------------------------===//
     32 
     33 #ifndef LLVM_ANALYSIS_INTERVALITERATOR_H
     34 #define LLVM_ANALYSIS_INTERVALITERATOR_H
     35 
     36 #include "llvm/Analysis/IntervalPartition.h"
     37 #include "llvm/IR/CFG.h"
     38 #include "llvm/IR/Function.h"
     39 #include <algorithm>
     40 #include <set>
     41 #include <vector>
     42 
     43 namespace llvm {
     44 
     45 // getNodeHeader - Given a source graph node and the source graph, return the
     46 // BasicBlock that is the header node.  This is the opposite of
     47 // getSourceGraphNode.
     48 //
     49 inline BasicBlock *getNodeHeader(BasicBlock *BB) { return BB; }
     50 inline BasicBlock *getNodeHeader(Interval *I) { return I->getHeaderNode(); }
     51 
     52 // getSourceGraphNode - Given a BasicBlock and the source graph, return the
     53 // source graph node that corresponds to the BasicBlock.  This is the opposite
     54 // of getNodeHeader.
     55 //
     56 inline BasicBlock *getSourceGraphNode(Function *, BasicBlock *BB) {
     57   return BB;
     58 }
     59 inline Interval *getSourceGraphNode(IntervalPartition *IP, BasicBlock *BB) {
     60   return IP->getBlockInterval(BB);
     61 }
     62 
     63 // addNodeToInterval - This method exists to assist the generic ProcessNode
     64 // with the task of adding a node to the new interval, depending on the
     65 // type of the source node.  In the case of a CFG source graph (BasicBlock
     66 // case), the BasicBlock itself is added to the interval.
     67 //
     68 inline void addNodeToInterval(Interval *Int, BasicBlock *BB) {
     69   Int->Nodes.push_back(BB);
     70 }
     71 
     72 // addNodeToInterval - This method exists to assist the generic ProcessNode
     73 // with the task of adding a node to the new interval, depending on the
     74 // type of the source node.  In the case of a CFG source graph (BasicBlock
     75 // case), the BasicBlock itself is added to the interval.  In the case of
     76 // an IntervalPartition source graph (Interval case), all of the member
     77 // BasicBlocks are added to the interval.
     78 //
     79 inline void addNodeToInterval(Interval *Int, Interval *I) {
     80   // Add all of the nodes in I as new nodes in Int.
     81   Int->Nodes.insert(Int->Nodes.end(), I->Nodes.begin(), I->Nodes.end());
     82 }
     83 
     84 
     85 
     86 
     87 
     88 template<class NodeTy, class OrigContainer_t, class GT = GraphTraits<NodeTy*>,
     89          class IGT = GraphTraits<Inverse<NodeTy*> > >
     90 class IntervalIterator {
     91   std::vector<std::pair<Interval*, typename Interval::succ_iterator> > IntStack;
     92   std::set<BasicBlock*> Visited;
     93   OrigContainer_t *OrigContainer;
     94   bool IOwnMem;     // If True, delete intervals when done with them
     95                     // See file header for conditions of use
     96 public:
     97   typedef std::forward_iterator_tag iterator_category;
     98 
     99   IntervalIterator() {} // End iterator, empty stack
    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   IntervalIterator operator++(int) { // Postincrement
    161     IntervalIterator tmp = *this;
    162     ++*this;
    163     return tmp;
    164   }
    165 
    166 private:
    167   // ProcessInterval - This method is used during the construction of the
    168   // interval graph.  It walks through the source graph, recursively creating
    169   // an interval per invocation until the entire graph is covered.  This uses
    170   // the ProcessNode method to add all of the nodes to the interval.
    171   //
    172   // This method is templated because it may operate on two different source
    173   // graphs: a basic block graph, or a preexisting interval graph.
    174   //
    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   //
    200   void ProcessNode(Interval *Int, NodeTy *Node) {
    201     assert(Int && "Null interval == bad!");
    202     assert(Node && "Null Node == bad!");
    203 
    204     BasicBlock *NodeHeader = getNodeHeader(Node);
    205 
    206     if (Visited.count(NodeHeader)) {     // Node already been visited?
    207       if (Int->contains(NodeHeader)) {   // Already in this interval...
    208         return;
    209       } else {                           // In other interval, add as successor
    210         if (!Int->isSuccessor(NodeHeader)) // Add only if not already in set
    211           Int->Successors.push_back(NodeHeader);
    212       }
    213     } else {                             // Otherwise, not in interval yet
    214       for (typename IGT::ChildIteratorType I = IGT::child_begin(Node),
    215              E = IGT::child_end(Node); I != E; ++I) {
    216         if (!Int->contains(*I)) {        // If pred not in interval, we can't be
    217           if (!Int->isSuccessor(NodeHeader)) // Add only if not already in set
    218             Int->Successors.push_back(NodeHeader);
    219           return;                        // See you later
    220         }
    221       }
    222 
    223       // If we get here, then all of the predecessors of BB are in the interval
    224       // already.  In this case, we must add BB to the interval!
    225       addNodeToInterval(Int, Node);
    226       Visited.insert(NodeHeader);     // The node has now been visited!
    227 
    228       if (Int->isSuccessor(NodeHeader)) {
    229         // If we were in the successor list from before... remove from succ list
    230         Int->Successors.erase(std::remove(Int->Successors.begin(),
    231                                           Int->Successors.end(), NodeHeader),
    232                               Int->Successors.end());
    233       }
    234 
    235       // Now that we have discovered that Node is in the interval, perhaps some
    236       // of its successors are as well?
    237       for (typename GT::ChildIteratorType It = GT::child_begin(Node),
    238              End = GT::child_end(Node); It != End; ++It)
    239         ProcessNode(Int, getSourceGraphNode(OrigContainer, *It));
    240     }
    241   }
    242 };
    243 
    244 typedef IntervalIterator<BasicBlock, Function> function_interval_iterator;
    245 typedef IntervalIterator<Interval, IntervalPartition>
    246                                           interval_part_interval_iterator;
    247 
    248 
    249 inline function_interval_iterator intervals_begin(Function *F,
    250                                                   bool DeleteInts = true) {
    251   return function_interval_iterator(F, DeleteInts);
    252 }
    253 inline function_interval_iterator intervals_end(Function *) {
    254   return function_interval_iterator();
    255 }
    256 
    257 inline interval_part_interval_iterator
    258    intervals_begin(IntervalPartition &IP, bool DeleteIntervals = true) {
    259   return interval_part_interval_iterator(IP, DeleteIntervals);
    260 }
    261 
    262 inline interval_part_interval_iterator intervals_end(IntervalPartition &IP) {
    263   return interval_part_interval_iterator();
    264 }
    265 
    266 } // End llvm namespace
    267 
    268 #endif
    269