aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/Analysis/LazyCallGraph.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Analysis/LazyCallGraph.h')
-rw-r--r--include/llvm/Analysis/LazyCallGraph.h493
1 files changed, 259 insertions, 234 deletions
diff --git a/include/llvm/Analysis/LazyCallGraph.h b/include/llvm/Analysis/LazyCallGraph.h
index bca0aebe2eef..ad7f5c80549f 100644
--- a/include/llvm/Analysis/LazyCallGraph.h
+++ b/include/llvm/Analysis/LazyCallGraph.h
@@ -106,6 +106,7 @@ class raw_ostream;
class LazyCallGraph {
public:
class Node;
+ class EdgeSequence;
class SCC;
class RefSCC;
class edge_iterator;
@@ -121,16 +122,6 @@ public:
/// inherently reference edges, and so the reference graph forms a superset
/// of the formal call graph.
///
- /// Furthermore, edges also may point to raw \c Function objects when those
- /// functions have not been scanned and incorporated into the graph (yet).
- /// This is one of the primary ways in which the graph can be lazy. When
- /// functions are scanned and fully incorporated into the graph, all of the
- /// edges referencing them are updated to point to the graph \c Node objects
- /// instead of to the raw \c Function objects. This class even provides
- /// methods to trigger this scan on-demand by attempting to get the target
- /// node of the graph and providing a reference back to the graph in order to
- /// lazily build it if necessary.
- ///
/// All of these forms of edges are fundamentally represented as outgoing
/// edges. The edges are stored in the source node and point at the target
/// node. This allows the edge structure itself to be a very compact data
@@ -141,7 +132,6 @@ public:
enum Kind : bool { Ref = false, Call = true };
Edge();
- explicit Edge(Function &F, Kind K);
explicit Edge(Node &N, Kind K);
/// Test whether the edge is null.
@@ -158,197 +148,251 @@ public:
/// This requires that the edge is not null.
bool isCall() const;
- /// Get the function referenced by this edge.
- ///
- /// This requires that the edge is not null, but will succeed whether we
- /// have built a graph node for the function yet or not.
- Function &getFunction() const;
-
- /// Get the call graph node referenced by this edge if one exists.
+ /// Get the call graph node referenced by this edge.
///
- /// This requires that the edge is not null. If we have built a graph node
- /// for the function this edge points to, this will return that node,
- /// otherwise it will return null.
- Node *getNode() const;
+ /// This requires that the edge is not null.
+ Node &getNode() const;
- /// Get the call graph node for this edge, building it if necessary.
+ /// Get the function referenced by this edge.
///
- /// This requires that the edge is not null. If we have not yet built
- /// a graph node for the function this edge points to, this will first ask
- /// the graph to build that node, inserting it into all the relevant
- /// structures.
- Node &getNode(LazyCallGraph &G);
+ /// This requires that the edge is not null.
+ Function &getFunction() const;
private:
- friend class LazyCallGraph::Node;
+ friend class LazyCallGraph::EdgeSequence;
friend class LazyCallGraph::RefSCC;
- PointerIntPair<PointerUnion<Function *, Node *>, 1, Kind> Value;
+ PointerIntPair<Node *, 1, Kind> Value;
void setKind(Kind K) { Value.setInt(K); }
};
- typedef SmallVector<Edge, 4> EdgeVectorT;
- typedef SmallVectorImpl<Edge> EdgeVectorImplT;
-
- /// A node in the call graph.
+ /// The edge sequence object.
///
- /// This represents a single node. It's primary roles are to cache the list of
- /// callees, de-duplicate and provide fast testing of whether a function is
- /// a callee, and facilitate iteration of child nodes in the graph.
- class Node {
+ /// This typically exists entirely within the node but is exposed as
+ /// a separate type because a node doesn't initially have edges. An explicit
+ /// population step is required to produce this sequence at first and it is
+ /// then cached in the node. It is also used to represent edges entering the
+ /// graph from outside the module to model the graph's roots.
+ ///
+ /// The sequence itself both iterable and indexable. The indexes remain
+ /// stable even as the sequence mutates (including removal).
+ class EdgeSequence {
friend class LazyCallGraph;
- friend class LazyCallGraph::SCC;
+ friend class LazyCallGraph::Node;
friend class LazyCallGraph::RefSCC;
- LazyCallGraph *G;
- Function &F;
+ typedef SmallVector<Edge, 4> VectorT;
+ typedef SmallVectorImpl<Edge> VectorImplT;
- // We provide for the DFS numbering and Tarjan walk lowlink numbers to be
- // stored directly within the node. These are both '-1' when nodes are part
- // of an SCC (or RefSCC), or '0' when not yet reached in a DFS walk.
- int DFSNumber;
- int LowLink;
+ public:
+ /// An iterator used for the edges to both entry nodes and child nodes.
+ class iterator
+ : public iterator_adaptor_base<iterator, VectorImplT::iterator,
+ std::forward_iterator_tag> {
+ friend class LazyCallGraph;
+ friend class LazyCallGraph::Node;
+
+ VectorImplT::iterator E;
+
+ // Build the iterator for a specific position in the edge list.
+ iterator(VectorImplT::iterator BaseI, VectorImplT::iterator E)
+ : iterator_adaptor_base(BaseI), E(E) {
+ while (I != E && !*I)
+ ++I;
+ }
- mutable EdgeVectorT Edges;
- DenseMap<Function *, int> EdgeIndexMap;
+ public:
+ iterator() {}
- /// Basic constructor implements the scanning of F into Edges and
- /// EdgeIndexMap.
- Node(LazyCallGraph &G, Function &F);
+ using iterator_adaptor_base::operator++;
+ iterator &operator++() {
+ do {
+ ++I;
+ } while (I != E && !*I);
+ return *this;
+ }
+ };
- /// Internal helper to insert an edge to a function.
- void insertEdgeInternal(Function &ChildF, Edge::Kind EK);
+ /// An iterator over specifically call edges.
+ ///
+ /// This has the same iteration properties as the \c iterator, but
+ /// restricts itself to edges which represent actual calls.
+ class call_iterator
+ : public iterator_adaptor_base<call_iterator, VectorImplT::iterator,
+ std::forward_iterator_tag> {
+ friend class LazyCallGraph;
+ friend class LazyCallGraph::Node;
+
+ VectorImplT::iterator E;
+
+ /// Advance the iterator to the next valid, call edge.
+ void advanceToNextEdge() {
+ while (I != E && (!*I || !I->isCall()))
+ ++I;
+ }
- /// Internal helper to insert an edge to a node.
- void insertEdgeInternal(Node &ChildN, Edge::Kind EK);
+ // Build the iterator for a specific position in the edge list.
+ call_iterator(VectorImplT::iterator BaseI, VectorImplT::iterator E)
+ : iterator_adaptor_base(BaseI), E(E) {
+ advanceToNextEdge();
+ }
- /// Internal helper to change an edge kind.
- void setEdgeKind(Function &ChildF, Edge::Kind EK);
+ public:
+ call_iterator() {}
- /// Internal helper to remove the edge to the given function.
- void removeEdgeInternal(Function &ChildF);
+ using iterator_adaptor_base::operator++;
+ call_iterator &operator++() {
+ ++I;
+ advanceToNextEdge();
+ return *this;
+ }
+ };
- void clear() {
- Edges.clear();
- EdgeIndexMap.clear();
- }
+ iterator begin() { return iterator(Edges.begin(), Edges.end()); }
+ iterator end() { return iterator(Edges.end(), Edges.end()); }
- /// Print the name of this node's function.
- friend raw_ostream &operator<<(raw_ostream &OS, const Node &N) {
- return OS << N.F.getName();
+ Edge &operator[](int i) { return Edges[i]; }
+ Edge &operator[](Node &N) {
+ assert(EdgeIndexMap.find(&N) != EdgeIndexMap.end() && "No such edge!");
+ return Edges[EdgeIndexMap.find(&N)->second];
}
-
- /// Dump the name of this node's function to stderr.
- void dump() const;
-
- public:
- LazyCallGraph &getGraph() const { return *G; }
-
- Function &getFunction() const { return F; }
-
- edge_iterator begin() const {
- return edge_iterator(Edges.begin(), Edges.end());
+ Edge *lookup(Node &N) {
+ auto EI = EdgeIndexMap.find(&N);
+ return EI != EdgeIndexMap.end() ? &Edges[EI->second] : nullptr;
}
- edge_iterator end() const { return edge_iterator(Edges.end(), Edges.end()); }
- const Edge &operator[](int i) const { return Edges[i]; }
- const Edge &operator[](Function &F) const {
- assert(EdgeIndexMap.find(&F) != EdgeIndexMap.end() && "No such edge!");
- return Edges[EdgeIndexMap.find(&F)->second];
+ call_iterator call_begin() {
+ return call_iterator(Edges.begin(), Edges.end());
}
- const Edge &operator[](Node &N) const { return (*this)[N.getFunction()]; }
+ call_iterator call_end() { return call_iterator(Edges.end(), Edges.end()); }
- const Edge *lookup(Function &F) const {
- auto EI = EdgeIndexMap.find(&F);
- return EI != EdgeIndexMap.end() ? &Edges[EI->second] : nullptr;
+ iterator_range<call_iterator> calls() {
+ return make_range(call_begin(), call_end());
}
- call_edge_iterator call_begin() const {
- return call_edge_iterator(Edges.begin(), Edges.end());
- }
- call_edge_iterator call_end() const {
- return call_edge_iterator(Edges.end(), Edges.end());
- }
+ bool empty() {
+ for (auto &E : Edges)
+ if (E)
+ return false;
- iterator_range<call_edge_iterator> calls() const {
- return make_range(call_begin(), call_end());
+ return true;
}
- /// Equality is defined as address equality.
- bool operator==(const Node &N) const { return this == &N; }
- bool operator!=(const Node &N) const { return !operator==(N); }
- };
+ private:
+ VectorT Edges;
+ DenseMap<Node *, int> EdgeIndexMap;
- /// A lazy iterator used for both the entry nodes and child nodes.
- ///
- /// When this iterator is dereferenced, if not yet available, a function will
- /// be scanned for "calls" or uses of functions and its child information
- /// will be constructed. All of these results are accumulated and cached in
- /// the graph.
- class edge_iterator
- : public iterator_adaptor_base<edge_iterator, EdgeVectorImplT::iterator,
- std::forward_iterator_tag> {
- friend class LazyCallGraph;
- friend class LazyCallGraph::Node;
+ EdgeSequence() = default;
- EdgeVectorImplT::iterator E;
+ /// Internal helper to insert an edge to a node.
+ void insertEdgeInternal(Node &ChildN, Edge::Kind EK);
- // Build the iterator for a specific position in the edge list.
- edge_iterator(EdgeVectorImplT::iterator BaseI,
- EdgeVectorImplT::iterator E)
- : iterator_adaptor_base(BaseI), E(E) {
- while (I != E && !*I)
- ++I;
- }
+ /// Internal helper to change an edge kind.
+ void setEdgeKind(Node &ChildN, Edge::Kind EK);
- public:
- edge_iterator() {}
+ /// Internal helper to remove the edge to the given function.
+ bool removeEdgeInternal(Node &ChildN);
- using iterator_adaptor_base::operator++;
- edge_iterator &operator++() {
- do {
- ++I;
- } while (I != E && !*I);
- return *this;
- }
+ /// Internal helper to replace an edge key with a new one.
+ ///
+ /// This should be used when the function for a particular node in the
+ /// graph gets replaced and we are updating all of the edges to that node
+ /// to use the new function as the key.
+ void replaceEdgeKey(Function &OldTarget, Function &NewTarget);
};
- /// A lazy iterator over specifically call edges.
+ /// A node in the call graph.
+ ///
+ /// This represents a single node. It's primary roles are to cache the list of
+ /// callees, de-duplicate and provide fast testing of whether a function is
+ /// a callee, and facilitate iteration of child nodes in the graph.
///
- /// This has the same iteration properties as the \c edge_iterator, but
- /// restricts itself to edges which represent actual calls.
- class call_edge_iterator
- : public iterator_adaptor_base<call_edge_iterator,
- EdgeVectorImplT::iterator,
- std::forward_iterator_tag> {
+ /// The node works much like an optional in order to lazily populate the
+ /// edges of each node. Until populated, there are no edges. Once populated,
+ /// you can access the edges by dereferencing the node or using the `->`
+ /// operator as if the node was an `Optional<EdgeSequence>`.
+ class Node {
friend class LazyCallGraph;
- friend class LazyCallGraph::Node;
+ friend class LazyCallGraph::RefSCC;
- EdgeVectorImplT::iterator E;
+ public:
+ LazyCallGraph &getGraph() const { return *G; }
- /// Advance the iterator to the next valid, call edge.
- void advanceToNextEdge() {
- while (I != E && (!*I || !I->isCall()))
- ++I;
+ Function &getFunction() const { return *F; }
+
+ StringRef getName() const { return F->getName(); }
+
+ /// Equality is defined as address equality.
+ bool operator==(const Node &N) const { return this == &N; }
+ bool operator!=(const Node &N) const { return !operator==(N); }
+
+ /// Tests whether the node has been populated with edges.
+ operator bool() const { return Edges.hasValue(); }
+
+ // We allow accessing the edges by dereferencing or using the arrow
+ // operator, essentially wrapping the internal optional.
+ EdgeSequence &operator*() const {
+ // Rip const off because the node itself isn't changing here.
+ return const_cast<EdgeSequence &>(*Edges);
}
+ EdgeSequence *operator->() const { return &**this; }
- // Build the iterator for a specific position in the edge list.
- call_edge_iterator(EdgeVectorImplT::iterator BaseI,
- EdgeVectorImplT::iterator E)
- : iterator_adaptor_base(BaseI), E(E) {
- advanceToNextEdge();
+ /// Populate the edges of this node if necessary.
+ ///
+ /// The first time this is called it will populate the edges for this node
+ /// in the graph. It does this by scanning the underlying function, so once
+ /// this is done, any changes to that function must be explicitly reflected
+ /// in updates to the graph.
+ ///
+ /// \returns the populated \c EdgeSequence to simplify walking it.
+ ///
+ /// This will not update or re-scan anything if called repeatedly. Instead,
+ /// the edge sequence is cached and returned immediately on subsequent
+ /// calls.
+ EdgeSequence &populate() {
+ if (Edges)
+ return *Edges;
+
+ return populateSlow();
}
- public:
- call_edge_iterator() {}
+ private:
+ LazyCallGraph *G;
+ Function *F;
- using iterator_adaptor_base::operator++;
- call_edge_iterator &operator++() {
- ++I;
- advanceToNextEdge();
- return *this;
+ // We provide for the DFS numbering and Tarjan walk lowlink numbers to be
+ // stored directly within the node. These are both '-1' when nodes are part
+ // of an SCC (or RefSCC), or '0' when not yet reached in a DFS walk.
+ int DFSNumber;
+ int LowLink;
+
+ Optional<EdgeSequence> Edges;
+
+ /// Basic constructor implements the scanning of F into Edges and
+ /// EdgeIndexMap.
+ Node(LazyCallGraph &G, Function &F)
+ : G(&G), F(&F), DFSNumber(0), LowLink(0) {}
+
+ /// Implementation of the scan when populating.
+ EdgeSequence &populateSlow();
+
+ /// Internal helper to directly replace the function with a new one.
+ ///
+ /// This is used to facilitate tranfsormations which need to replace the
+ /// formal Function object but directly move the body and users from one to
+ /// the other.
+ void replaceFunction(Function &NewF);
+
+ void clear() { Edges.reset(); }
+
+ /// Print the name of this node's function.
+ friend raw_ostream &operator<<(raw_ostream &OS, const Node &N) {
+ return OS << N.F->getName();
}
+
+ /// Dump the name of this node's function to stderr.
+ void dump() const;
};
/// An SCC of the call graph.
@@ -789,19 +833,26 @@ public:
/// already existing edges.
void insertTrivialRefEdge(Node &SourceN, Node &TargetN);
+ /// Directly replace a node's function with a new function.
+ ///
+ /// This should be used when moving the body and users of a function to
+ /// a new formal function object but not otherwise changing the call graph
+ /// structure in any way.
+ ///
+ /// It requires that the old function in the provided node have zero uses
+ /// and the new function must have calls and references to it establishing
+ /// an equivalent graph.
+ void replaceNodeFunction(Node &N, Function &NewF);
+
///@}
};
/// A post-order depth-first RefSCC iterator over the call graph.
///
- /// This iterator triggers the Tarjan DFS-based formation of the RefSCC (and
- /// SCC) DAG for the call graph, walking it lazily in depth-first post-order.
- /// That is, it always visits RefSCCs for the target of a reference edge
- /// prior to visiting the RefSCC for a source of the edge (when they are in
- /// different RefSCCs).
- ///
- /// When forming each RefSCC, the call edges within it are used to form SCCs
- /// within it, so iterating this also controls the lazy formation of SCCs.
+ /// This iterator walks the cached post-order sequence of RefSCCs. However,
+ /// it trades stability for flexibility. It is restricted to a forward
+ /// iterator but will survive mutations which insert new RefSCCs and continue
+ /// to point to the same RefSCC even if it moves in the post-order sequence.
class postorder_ref_scc_iterator
: public iterator_facade_base<postorder_ref_scc_iterator,
std::forward_iterator_tag, RefSCC> {
@@ -825,12 +876,9 @@ public:
/// populating it if necessary.
static RefSCC *getRC(LazyCallGraph &G, int Index) {
if (Index == (int)G.PostOrderRefSCCs.size())
- if (!G.buildNextRefSCCInPostOrder())
- // We're at the end.
- return nullptr;
+ // We're at the end.
+ return nullptr;
- assert(Index < (int)G.PostOrderRefSCCs.size() &&
- "Built the next post-order RefSCC without growing list!");
return G.PostOrderRefSCCs[Index];
}
@@ -859,17 +907,21 @@ public:
LazyCallGraph(LazyCallGraph &&G);
LazyCallGraph &operator=(LazyCallGraph &&RHS);
- edge_iterator begin() {
- return edge_iterator(EntryEdges.begin(), EntryEdges.end());
- }
- edge_iterator end() {
- return edge_iterator(EntryEdges.end(), EntryEdges.end());
- }
+ EdgeSequence::iterator begin() { return EntryEdges.begin(); }
+ EdgeSequence::iterator end() { return EntryEdges.end(); }
+
+ void buildRefSCCs();
postorder_ref_scc_iterator postorder_ref_scc_begin() {
+ if (!EntryEdges.empty())
+ assert(!PostOrderRefSCCs.empty() &&
+ "Must form RefSCCs before iterating them!");
return postorder_ref_scc_iterator(*this);
}
postorder_ref_scc_iterator postorder_ref_scc_end() {
+ if (!EntryEdges.empty())
+ assert(!PostOrderRefSCCs.empty() &&
+ "Must form RefSCCs before iterating them!");
return postorder_ref_scc_iterator(*this,
postorder_ref_scc_iterator::IsAtEndT());
}
@@ -920,19 +972,19 @@ public:
/// below.
/// Update the call graph after inserting a new edge.
- void insertEdge(Node &Caller, Function &Callee, Edge::Kind EK);
+ void insertEdge(Node &SourceN, Node &TargetN, Edge::Kind EK);
/// Update the call graph after inserting a new edge.
- void insertEdge(Function &Caller, Function &Callee, Edge::Kind EK) {
- return insertEdge(get(Caller), Callee, EK);
+ void insertEdge(Function &Source, Function &Target, Edge::Kind EK) {
+ return insertEdge(get(Source), get(Target), EK);
}
/// Update the call graph after deleting an edge.
- void removeEdge(Node &Caller, Function &Callee);
+ void removeEdge(Node &SourceN, Node &TargetN);
/// Update the call graph after deleting an edge.
- void removeEdge(Function &Caller, Function &Callee) {
- return removeEdge(get(Caller), Callee);
+ void removeEdge(Function &Source, Function &Target) {
+ return removeEdge(get(Source), get(Target));
}
///@}
@@ -1013,14 +1065,11 @@ private:
/// Maps function->node for fast lookup.
DenseMap<const Function *, Node *> NodeMap;
- /// The entry nodes to the graph.
+ /// The entry edges into the graph.
///
- /// These nodes are reachable through "external" means. Put another way, they
+ /// These edges are from "external" sources. Put another way, they
/// escape at the module scope.
- EdgeVectorT EntryEdges;
-
- /// Map of the entry nodes in the graph to their indices in \c EntryEdges.
- DenseMap<Function *, int> EntryIndexMap;
+ EdgeSequence EntryEdges;
/// Allocator that holds all the call graph SCCs.
SpecificBumpPtrAllocator<SCC> SCCBPA;
@@ -1045,18 +1094,6 @@ private:
/// These are all of the RefSCCs which have no children.
SmallVector<RefSCC *, 4> LeafRefSCCs;
- /// Stack of nodes in the DFS walk.
- SmallVector<std::pair<Node *, edge_iterator>, 4> DFSStack;
-
- /// Set of entry nodes not-yet-processed into RefSCCs.
- SmallVector<Function *, 4> RefSCCEntryNodes;
-
- /// Stack of nodes the DFS has walked but not yet put into a RefSCC.
- SmallVector<Node *, 4> PendingRefSCCStack;
-
- /// Counter for the next DFS number to assign.
- int NextDFSNumber;
-
/// Helper to insert a new function, with an already looked-up entry in
/// the NodeMap.
Node &insertInto(Function &F, Node *&MappedN);
@@ -1078,6 +1115,23 @@ private:
return new (RefSCCBPA.Allocate()) RefSCC(std::forward<Ts>(Args)...);
}
+ /// Common logic for building SCCs from a sequence of roots.
+ ///
+ /// This is a very generic implementation of the depth-first walk and SCC
+ /// formation algorithm. It uses a generic sequence of roots and generic
+ /// callbacks for each step. This is designed to be used to implement both
+ /// the RefSCC formation and SCC formation with shared logic.
+ ///
+ /// Currently this is a relatively naive implementation of Tarjan's DFS
+ /// algorithm to form the SCCs.
+ ///
+ /// FIXME: We should consider newer variants such as Nuutila.
+ template <typename RootsT, typename GetBeginT, typename GetEndT,
+ typename GetNodeT, typename FormSCCCallbackT>
+ static void buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin,
+ GetEndT &&GetEnd, GetNodeT &&GetNode,
+ FormSCCCallbackT &&FormSCC);
+
/// Build the SCCs for a RefSCC out of a list of nodes.
void buildSCCs(RefSCC &RC, node_stack_range Nodes);
@@ -1098,22 +1152,12 @@ private:
"Index does not point back at RC!");
return IndexIt->second;
}
-
- /// Builds the next node in the post-order RefSCC walk of the call graph and
- /// appends it to the \c PostOrderRefSCCs vector.
- ///
- /// Returns true if a new RefSCC was successfully constructed, and false if
- /// there are no more RefSCCs to build in the graph.
- bool buildNextRefSCCInPostOrder();
};
inline LazyCallGraph::Edge::Edge() : Value() {}
-inline LazyCallGraph::Edge::Edge(Function &F, Kind K) : Value(&F, K) {}
inline LazyCallGraph::Edge::Edge(Node &N, Kind K) : Value(&N, K) {}
-inline LazyCallGraph::Edge::operator bool() const {
- return !Value.getPointer().isNull();
-}
+inline LazyCallGraph::Edge::operator bool() const { return Value.getPointer(); }
inline LazyCallGraph::Edge::Kind LazyCallGraph::Edge::getKind() const {
assert(*this && "Queried a null edge!");
@@ -1125,51 +1169,32 @@ inline bool LazyCallGraph::Edge::isCall() const {
return getKind() == Call;
}
-inline Function &LazyCallGraph::Edge::getFunction() const {
+inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode() const {
assert(*this && "Queried a null edge!");
- auto P = Value.getPointer();
- if (auto *F = P.dyn_cast<Function *>())
- return *F;
-
- return P.get<Node *>()->getFunction();
+ return *Value.getPointer();
}
-inline LazyCallGraph::Node *LazyCallGraph::Edge::getNode() const {
- assert(*this && "Queried a null edge!");
- auto P = Value.getPointer();
- if (auto *N = P.dyn_cast<Node *>())
- return N;
-
- return nullptr;
-}
-
-inline LazyCallGraph::Node &LazyCallGraph::Edge::getNode(LazyCallGraph &G) {
+inline Function &LazyCallGraph::Edge::getFunction() const {
assert(*this && "Queried a null edge!");
- auto P = Value.getPointer();
- if (auto *N = P.dyn_cast<Node *>())
- return *N;
-
- Node &N = G.get(*P.get<Function *>());
- Value.setPointer(&N);
- return N;
+ return getNode().getFunction();
}
// Provide GraphTraits specializations for call graphs.
template <> struct GraphTraits<LazyCallGraph::Node *> {
typedef LazyCallGraph::Node *NodeRef;
- typedef LazyCallGraph::edge_iterator ChildIteratorType;
+ typedef LazyCallGraph::EdgeSequence::iterator ChildIteratorType;
static NodeRef getEntryNode(NodeRef N) { return N; }
- static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
- static ChildIteratorType child_end(NodeRef N) { return N->end(); }
+ static ChildIteratorType child_begin(NodeRef N) { return (*N)->begin(); }
+ static ChildIteratorType child_end(NodeRef N) { return (*N)->end(); }
};
template <> struct GraphTraits<LazyCallGraph *> {
typedef LazyCallGraph::Node *NodeRef;
- typedef LazyCallGraph::edge_iterator ChildIteratorType;
+ typedef LazyCallGraph::EdgeSequence::iterator ChildIteratorType;
static NodeRef getEntryNode(NodeRef N) { return N; }
- static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
- static ChildIteratorType child_end(NodeRef N) { return N->end(); }
+ static ChildIteratorType child_begin(NodeRef N) { return (*N)->begin(); }
+ static ChildIteratorType child_end(NodeRef N) { return (*N)->end(); }
};
/// An analysis pass which computes the call graph for a module.