From cf1760aff017655543c801e242b2c436bcc0021a Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 24 Jun 2001 03:22:59 +0000 Subject: [PATCH] Addition of IntervalIterator. Preparing for rename of Intervals.h to Interval.h, IntervalPartition.h, and IntervalIterator.h git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@59 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/Interval.h | 203 ++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 6 deletions(-) diff --git a/include/llvm/Analysis/Interval.h b/include/llvm/Analysis/Interval.h index ca6db9a3124..e22e9e251d8 100644 --- a/include/llvm/Analysis/Interval.h +++ b/include/llvm/Analysis/Interval.h @@ -7,19 +7,21 @@ // In this way, the interval partition may be used to reduce a flow graph down // to its degenerate single node interval partition (unless it is irreducible). // -// TODO: Provide an interval iterator that codifies the internals of -// IntervalPartition. Inside, it would have a stack of Interval*'s, and would -// walk the interval partition in depth first order. IntervalPartition would -// then be a client of this iterator. The iterator should work on Method*, -// const Method*, IntervalPartition*, and const IntervalPartition*. +// TODO: The IntervalPartition class should take a bool parameter that tells +// whether it should add the "tails" of an interval to an interval itself or if +// they should be represented as distinct intervals. // //===----------------------------------------------------------------------===// #ifndef LLVM_INTERVALS_H #define LLVM_INTERVALS_H +#include "llvm/Method.h" +#include "llvm/CFG.h" #include #include +#include +#include #include class Method; @@ -77,7 +79,7 @@ public: // isLoop - Find out if there is a back edge in this interval... bool isLoop() const; -private: // Only accessable by IntervalPartition class + //private: // Only accessable by IntervalPartition class inline Interval(BasicBlock *Header) : HeaderNode(Header) { Nodes.push_back(Header); } @@ -105,6 +107,141 @@ inline Interval::pred_iterator pred_end(Interval *I) { } +//===----------------------------------------------------------------------===// +// IntervalIterator +// +// TODO: Provide an interval iterator that codifies the internals of +// IntervalPartition. Inside, it would have a stack of Interval*'s, and would +// walk the interval partition in depth first order. IntervalPartition would +// then be a client of this iterator. The iterator should work on Method*, +// const Method*, IntervalPartition*, and const IntervalPartition*. +// + +template +class IntervalIterator { + stack > IntStack; + set Visited; + OrigContainer_t *OrigContainer; +public: + typedef BasicBlock* _BB; + + typedef IntervalIterator _Self; + typedef forward_iterator_tag iterator_category; + + IntervalIterator() {} // End iterator, empty stack + IntervalIterator(Method *M) { + OrigContainer = M; + if (!ProcessInterval(M->getBasicBlocks().front())) { + assert(0 && "ProcessInterval should never fail for first interval!"); + } + } + + inline bool operator==(const _Self& x) const { return IntStack == x.IntStack; } + inline bool operator!=(const _Self& x) const { return !operator==(x); } + + inline Interval &operator*() const { return IntStack.top(); } + inline Interval *operator->() const { return &(operator*()); } + + inline _Self& operator++() { // Preincrement + do { + // All of the intervals on the stack have been visited. Try visiting their + // successors now. + Interval &CurInt = IntStack.top().first; + Interval::iterator &SuccIt = IntStack.top().second,End = succ_end(&CurInt); + + for (; SuccIt != End; ++SuccIt) // Loop over all interval successors + if (ProcessInterval(*SuccIt)) // Found a new interval! + return *this; // Use it! + + // We ran out of successors for this interval... pop off the stack + IntStack.pop(); + } while (!IntStack.empty()); + + return *this; + } + inline _Self operator++(int) { // Postincrement + _Self tmp = *this; ++*this; return tmp; + } + +private: + // ProcessInterval - This method is used during the construction of the + // interval graph. It walks through the source graph, recursively creating + // an interval per invokation until the entire graph is covered. This uses + // the ProcessNode method to add all of the nodes to the interval. + // + // This method is templated because it may operate on two different source + // graphs: a basic block graph, or a preexisting interval graph. + // + bool ProcessInterval(NodeTy *Node) { + BasicBlock *Header = getNodeHeader(Node); + if (Visited.count(Header)) return false; + + Interval Int(Header); + Visited.insert(Header); // The header has now been visited! + + // Check all of our successors to see if they are in the interval... + for (typename NodeTy::succ_iterator I = succ_begin(Node), E = succ_end(Node); + I != E; ++I) + ProcessNode(&Int, getSourceGraphNode(OrigContainer, *I)); + + IntStack.push(make_pair(Int, succ_begin(&Int))); + return true; + } + + // ProcessNode - This method is called by ProcessInterval to add nodes to the + // interval being constructed, and it is also called recursively as it walks + // the source graph. A node is added to the current interval only if all of + // its predecessors are already in the graph. This also takes care of keeping + // the successor set of an interval up to date. + // + // This method is templated because it may operate on two different source + // graphs: a basic block graph, or a preexisting interval graph. + // + void ProcessNode(Interval *Int, NodeTy *Node) { + assert(Int && "Null interval == bad!"); + assert(Node && "Null Node == bad!"); + + BasicBlock *NodeHeader = getNodeHeader(Node); + + if (Visited.count(NodeHeader)) { // Node already been visited? + if (Int->contains(NodeHeader)) { // Already in this interval... + return; + } else { // In another interval, add as successor + if (!Int->isSuccessor(NodeHeader)) // Add only if not already in set + Int->Successors.push_back(NodeHeader); + } + } else { // Otherwise, not in interval yet + for (typename NodeTy::pred_iterator I = pred_begin(Node), + E = pred_end(Node); I != E; ++I) { + if (!Int->contains(*I)) { // If pred not in interval, we can't be + if (!Int->isSuccessor(NodeHeader)) // Add only if not already in set + Int->Successors.push_back(NodeHeader); + return; // See you later + } + } + + // If we get here, then all of the predecessors of BB are in the interval + // already. In this case, we must add BB to the interval! + addNodeToInterval(Int, Node); + Visited.insert(NodeHeader); // The node has now been visited! + + if (Int->isSuccessor(NodeHeader)) { + // If we were in the successor list from before... remove from succ list + Int->Successors.erase(remove(Int->Successors.begin(), + Int->Successors.end(), NodeHeader), + Int->Successors.end()); + } + + // Now that we have discovered that Node is in the interval, perhaps some + // of its successors are as well? + for (typename NodeTy::succ_iterator It = succ_begin(Node), + End = succ_end(Node); It != End; ++It) + ProcessNode(Int, getSourceGraphNode(OrigContainer, *It)); + } + } +}; + + //===----------------------------------------------------------------------===// // // IntervalPartition - This class builds and holds an "interval partition" for @@ -200,6 +337,60 @@ private: void updatePredecessors(Interval *Int); }; + + +// getNodeHeader - Given a source graph node and the source graph, return the +// BasicBlock that is the header node. This is the opposite of +// getSourceGraphNode. +// +inline BasicBlock *getNodeHeader(BasicBlock *BB) { return BB; } +inline BasicBlock *getNodeHeader(Interval *I) { return I->getHeaderNode(); } + +// getSourceGraphNode - Given a BasicBlock and the source graph, return the +// source graph node that corresponds to the BasicBlock. This is the opposite +// of getNodeHeader. +// +inline BasicBlock *getSourceGraphNode(Method *, BasicBlock *BB) { + return BB; +} +inline Interval *getSourceGraphNode(IntervalPartition *IP, BasicBlock *BB) { + return IP->getBlockInterval(BB); +} + +// addNodeToInterval - This method exists to assist the generic ProcessNode +// with the task of adding a node to the new interval, depending on the +// type of the source node. In the case of a CFG source graph (BasicBlock +// case), the BasicBlock itself is added to the interval. +// +inline void addNodeToInterval(Interval *Int, BasicBlock *BB){ + Int->Nodes.push_back(BB); +} + +// addNodeToInterval - This method exists to assist the generic ProcessNode +// with the task of adding a node to the new interval, depending on the +// type of the source node. In the case of a CFG source graph (BasicBlock +// case), the BasicBlock itself is added to the interval. In the case of +// an IntervalPartition source graph (Interval case), all of the member +// BasicBlocks are added to the interval. +// +inline void addNodeToInterval(Interval *Int, Interval *I) { + // Add all of the nodes in I as new nodes in Int. + copy(I->Nodes.begin(), I->Nodes.end(), back_inserter(Int->Nodes)); +} + + + + +typedef IntervalIterator method_interval_iterator; + + +method_interval_iterator intervals_begin(Method *M) { + return method_interval_iterator(M); +} +method_interval_iterator intervals_end(Method *M) { + return method_interval_iterator(); +} + } // End namespace cfg #endif