diff options
Diffstat (limited to 'llvm/lib/Analysis/LazyCallGraph.cpp')
-rw-r--r-- | llvm/lib/Analysis/LazyCallGraph.cpp | 293 |
1 files changed, 160 insertions, 133 deletions
diff --git a/llvm/lib/Analysis/LazyCallGraph.cpp b/llvm/lib/Analysis/LazyCallGraph.cpp index 0f0f31e62ac..11e1166001a 100644 --- a/llvm/lib/Analysis/LazyCallGraph.cpp +++ b/llvm/lib/Analysis/LazyCallGraph.cpp @@ -20,30 +20,36 @@ using namespace llvm; #define DEBUG_TYPE "lcg" -static void findCallees( - SmallVectorImpl<Constant *> &Worklist, SmallPtrSetImpl<Constant *> &Visited, - SmallVectorImpl<PointerUnion<Function *, LazyCallGraph::Node *>> &Callees, - DenseMap<Function *, size_t> &CalleeIndexMap) { +static void addEdge(SmallVectorImpl<LazyCallGraph::Edge> &Edges, + DenseMap<Function *, size_t> &EdgeIndexMap, Function &F, + LazyCallGraph::Edge::Kind EK) { + // Note that we consider *any* function with a definition to be a viable + // edge. Even if the function's definition is subject to replacement by + // some other module (say, a weak definition) there may still be + // optimizations which essentially speculate based on the definition and + // a way to check that the specific definition is in fact the one being + // used. For example, this could be done by moving the weak definition to + // a strong (internal) definition and making the weak definition be an + // alias. Then a test of the address of the weak function against the new + // strong definition's address would be an effective way to determine the + // safety of optimizing a direct call edge. + if (!F.isDeclaration() && + EdgeIndexMap.insert(std::make_pair(&F, Edges.size())).second) { + DEBUG(dbgs() << " Added callable function: " << F.getName() << "\n"); + Edges.emplace_back(LazyCallGraph::Edge(F, EK)); + } +} + +static void findReferences( + SmallVectorImpl<Constant *> &Worklist, + SmallPtrSetImpl<Constant *> &Visited, + SmallVectorImpl<LazyCallGraph::Edge> &Edges, + DenseMap<Function *, size_t> &EdgeIndexMap) { while (!Worklist.empty()) { Constant *C = Worklist.pop_back_val(); if (Function *F = dyn_cast<Function>(C)) { - // Note that we consider *any* function with a definition to be a viable - // edge. Even if the function's definition is subject to replacement by - // some other module (say, a weak definition) there may still be - // optimizations which essentially speculate based on the definition and - // a way to check that the specific definition is in fact the one being - // used. For example, this could be done by moving the weak definition to - // a strong (internal) definition and making the weak definition be an - // alias. Then a test of the address of the weak function against the new - // strong definition's address would be an effective way to determine the - // safety of optimizing a direct call edge. - if (!F->isDeclaration() && - CalleeIndexMap.insert(std::make_pair(F, Callees.size())).second) { - DEBUG(dbgs() << " Added callable function: " << F->getName() - << "\n"); - Callees.push_back(F); - } + addEdge(Edges, EdgeIndexMap, *F, LazyCallGraph::Edge::Ref); continue; } @@ -59,42 +65,55 @@ LazyCallGraph::Node::Node(LazyCallGraph &G, Function &F) << "' to the graph.\n"); SmallVector<Constant *, 16> Worklist; + SmallPtrSet<Function *, 4> Callees; SmallPtrSet<Constant *, 16> Visited; - // Find all the potential callees in this function. First walk the - // instructions and add every operand which is a constant to the worklist. + + // Find all the potential call graph edges in this function. We track both + // actual call edges and indirect references to functions. The direct calls + // are trivially added, but to accumulate the latter we walk the instructions + // and add every operand which is a constant to the worklist to process + // afterward. for (BasicBlock &BB : F) - for (Instruction &I : BB) + for (Instruction &I : BB) { + if (auto CS = CallSite(&I)) + if (Function *Callee = CS.getCalledFunction()) + if (Callees.insert(Callee).second) { + Visited.insert(Callee); + addEdge(Edges, EdgeIndexMap, *Callee, LazyCallGraph::Edge::Call); + } + for (Value *Op : I.operand_values()) if (Constant *C = dyn_cast<Constant>(Op)) if (Visited.insert(C).second) Worklist.push_back(C); + } // We've collected all the constant (and thus potentially function or // function containing) operands to all of the instructions in the function. // Process them (recursively) collecting every function found. - findCallees(Worklist, Visited, Callees, CalleeIndexMap); + findReferences(Worklist, Visited, Edges, EdgeIndexMap); } -void LazyCallGraph::Node::insertEdgeInternal(Function &Callee) { - if (Node *N = G->lookup(Callee)) - return insertEdgeInternal(*N); +void LazyCallGraph::Node::insertEdgeInternal(Function &Child, Edge::Kind EK) { + if (Node *N = G->lookup(Child)) + return insertEdgeInternal(*N, EK); - CalleeIndexMap.insert(std::make_pair(&Callee, Callees.size())); - Callees.push_back(&Callee); + EdgeIndexMap.insert(std::make_pair(&Child, Edges.size())); + Edges.emplace_back(Child, EK); } -void LazyCallGraph::Node::insertEdgeInternal(Node &CalleeN) { - CalleeIndexMap.insert(std::make_pair(&CalleeN.getFunction(), Callees.size())); - Callees.push_back(&CalleeN); +void LazyCallGraph::Node::insertEdgeInternal(Node &ChildN, Edge::Kind EK) { + EdgeIndexMap.insert(std::make_pair(&ChildN.getFunction(), Edges.size())); + Edges.emplace_back(ChildN, EK); } -void LazyCallGraph::Node::removeEdgeInternal(Function &Callee) { - auto IndexMapI = CalleeIndexMap.find(&Callee); - assert(IndexMapI != CalleeIndexMap.end() && - "Callee not in the callee set for this caller?"); +void LazyCallGraph::Node::removeEdgeInternal(Function &Child) { + auto IndexMapI = EdgeIndexMap.find(&Child); + assert(IndexMapI != EdgeIndexMap.end() && + "Child not in the edge set for this caller?"); - Callees[IndexMapI->second] = nullptr; - CalleeIndexMap.erase(IndexMapI); + Edges[IndexMapI->second] = Edge(); + EdgeIndexMap.erase(IndexMapI); } LazyCallGraph::LazyCallGraph(Module &M) : NextDFSNumber(0) { @@ -102,10 +121,10 @@ LazyCallGraph::LazyCallGraph(Module &M) : NextDFSNumber(0) { << "\n"); for (Function &F : M) if (!F.isDeclaration() && !F.hasLocalLinkage()) - if (EntryIndexMap.insert(std::make_pair(&F, EntryNodes.size())).second) { + if (EntryIndexMap.insert(std::make_pair(&F, EntryEdges.size())).second) { DEBUG(dbgs() << " Adding '" << F.getName() << "' to entry set of the graph.\n"); - EntryNodes.push_back(&F); + EntryEdges.emplace_back(F, Edge::Ref); } // Now add entry nodes for functions reachable via initializers to globals. @@ -118,21 +137,15 @@ LazyCallGraph::LazyCallGraph(Module &M) : NextDFSNumber(0) { DEBUG(dbgs() << " Adding functions referenced by global initializers to the " "entry set.\n"); - findCallees(Worklist, Visited, EntryNodes, EntryIndexMap); - - for (auto &Entry : EntryNodes) { - assert(!Entry.isNull() && - "We can't have removed edges before we finish the constructor!"); - if (Function *F = Entry.dyn_cast<Function *>()) - SCCEntryNodes.push_back(F); - else - SCCEntryNodes.push_back(&Entry.get<Node *>()->getFunction()); - } + findReferences(Worklist, Visited, EntryEdges, EntryIndexMap); + + for (const Edge &E : EntryEdges) + SCCEntryNodes.push_back(&E.getFunction()); } LazyCallGraph::LazyCallGraph(LazyCallGraph &&G) : BPA(std::move(G.BPA)), NodeMap(std::move(G.NodeMap)), - EntryNodes(std::move(G.EntryNodes)), + EntryEdges(std::move(G.EntryEdges)), EntryIndexMap(std::move(G.EntryIndexMap)), SCCBPA(std::move(G.SCCBPA)), SCCMap(std::move(G.SCCMap)), LeafSCCs(std::move(G.LeafSCCs)), DFSStack(std::move(G.DFSStack)), @@ -144,7 +157,7 @@ LazyCallGraph::LazyCallGraph(LazyCallGraph &&G) LazyCallGraph &LazyCallGraph::operator=(LazyCallGraph &&G) { BPA = std::move(G.BPA); NodeMap = std::move(G.NodeMap); - EntryNodes = std::move(G.EntryNodes); + EntryEdges = std::move(G.EntryEdges); EntryIndexMap = std::move(G.EntryIndexMap); SCCBPA = std::move(G.SCCBPA); SCCMap = std::move(G.SCCMap); @@ -177,43 +190,46 @@ bool LazyCallGraph::SCC::isDescendantOf(const SCC &C) const { return false; } -void LazyCallGraph::SCC::insertIntraSCCEdge(Node &CallerN, Node &CalleeN) { +void LazyCallGraph::SCC::insertIntraSCCEdge(Node &ParentN, Node &ChildN, + Edge::Kind EK) { // First insert it into the caller. - CallerN.insertEdgeInternal(CalleeN); + ParentN.insertEdgeInternal(ChildN, EK); - assert(G->SCCMap.lookup(&CallerN) == this && "Caller must be in this SCC."); - assert(G->SCCMap.lookup(&CalleeN) == this && "Callee must be in this SCC."); + assert(G->SCCMap.lookup(&ParentN) == this && "Parent must be in this SCC."); + assert(G->SCCMap.lookup(&ChildN) == this && "Child must be in this SCC."); // Nothing changes about this SCC or any other. } -void LazyCallGraph::SCC::insertOutgoingEdge(Node &CallerN, Node &CalleeN) { +void LazyCallGraph::SCC::insertOutgoingEdge(Node &ParentN, Node &ChildN, + Edge::Kind EK) { // First insert it into the caller. - CallerN.insertEdgeInternal(CalleeN); + ParentN.insertEdgeInternal(ChildN, EK); - assert(G->SCCMap.lookup(&CallerN) == this && "Caller must be in this SCC."); + assert(G->SCCMap.lookup(&ParentN) == this && "Parent must be in this SCC."); - SCC &CalleeC = *G->SCCMap.lookup(&CalleeN); - assert(&CalleeC != this && "Callee must not be in this SCC."); - assert(CalleeC.isDescendantOf(*this) && - "Callee must be a descendant of the Caller."); + SCC &ChildC = *G->SCCMap.lookup(&ChildN); + assert(&ChildC != this && "Child must not be in this SCC."); + assert(ChildC.isDescendantOf(*this) && + "Child must be a descendant of the Parent."); // The only change required is to add this SCC to the parent set of the // callee. - CalleeC.ParentSCCs.insert(this); + ChildC.ParentSCCs.insert(this); } SmallVector<LazyCallGraph::SCC *, 1> -LazyCallGraph::SCC::insertIncomingEdge(Node &CallerN, Node &CalleeN) { +LazyCallGraph::SCC::insertIncomingEdge(Node &ParentN, Node &ChildN, + Edge::Kind EK) { // First insert it into the caller. - CallerN.insertEdgeInternal(CalleeN); + ParentN.insertEdgeInternal(ChildN, EK); - assert(G->SCCMap.lookup(&CalleeN) == this && "Callee must be in this SCC."); + assert(G->SCCMap.lookup(&ChildN) == this && "Child must be in this SCC."); - SCC &CallerC = *G->SCCMap.lookup(&CallerN); - assert(&CallerC != this && "Caller must not be in this SCC."); - assert(CallerC.isDescendantOf(*this) && - "Caller must be a descendant of the Callee."); + SCC &ParentC = *G->SCCMap.lookup(&ParentN); + assert(&ParentC != this && "Parent must not be in this SCC."); + assert(ParentC.isDescendantOf(*this) && + "Parent must be a descendant of the Child."); // The algorithm we use for merging SCCs based on the cycle introduced here // is to walk the SCC inverted DAG formed by the parent SCC sets. The inverse @@ -231,7 +247,7 @@ LazyCallGraph::SCC::insertIncomingEdge(Node &CallerN, Node &CalleeN) { // participate in the merged connected component. SmallPtrSet<SCC *, 8> ConnectedSCCs; ConnectedSCCs.insert(this); - ConnectedSCCs.insert(&CallerC); + ConnectedSCCs.insert(&ParentC); // We build up a DFS stack of the parents chains. SmallVector<std::pair<SCC *, SCC::parent_iterator>, 8> DFSSCCs; @@ -298,8 +314,9 @@ LazyCallGraph::SCC::insertIncomingEdge(Node &CallerN, Node &CalleeN) { C->ParentSCCs.clear(); for (Node *N : *C) { - for (Node &ChildN : *N) { - SCC &ChildC = *G->SCCMap.lookup(&ChildN); + for (Edge &E : *N) { + assert(E.getNode() && "Cannot have a null node within a visited SCC!"); + SCC &ChildC = *G->SCCMap.lookup(E.getNode()); if (&ChildC != C) ChildC.ParentSCCs.erase(C); } @@ -309,8 +326,9 @@ LazyCallGraph::SCC::insertIncomingEdge(Node &CallerN, Node &CalleeN) { C->Nodes.clear(); } for (auto I = Nodes.begin() + NewNodeBeginIdx, E = Nodes.end(); I != E; ++I) - for (Node &ChildN : **I) { - SCC &ChildC = *G->SCCMap.lookup(&ChildN); + for (Edge &E : **I) { + assert(E.getNode() && "Cannot have a null node within a visited SCC!"); + SCC &ChildC = *G->SCCMap.lookup(E.getNode()); if (&ChildC != this) ChildC.ParentSCCs.insert(this); } @@ -322,64 +340,65 @@ LazyCallGraph::SCC::insertIncomingEdge(Node &CallerN, Node &CalleeN) { return SmallVector<SCC *, 1>(ConnectedSCCs.begin(), ConnectedSCCs.end()); } -void LazyCallGraph::SCC::removeInterSCCEdge(Node &CallerN, Node &CalleeN) { +void LazyCallGraph::SCC::removeInterSCCEdge(Node &ParentN, Node &ChildN) { // First remove it from the node. - CallerN.removeEdgeInternal(CalleeN.getFunction()); + ParentN.removeEdgeInternal(ChildN.getFunction()); - assert(G->SCCMap.lookup(&CallerN) == this && + assert(G->SCCMap.lookup(&ParentN) == this && "The caller must be a member of this SCC."); - SCC &CalleeC = *G->SCCMap.lookup(&CalleeN); - assert(&CalleeC != this && + SCC &ChildC = *G->SCCMap.lookup(&ChildN); + assert(&ChildC != this && "This API only supports the rmoval of inter-SCC edges."); assert(std::find(G->LeafSCCs.begin(), G->LeafSCCs.end(), this) == G->LeafSCCs.end() && "Cannot have a leaf SCC caller with a different SCC callee."); - bool HasOtherCallToCalleeC = false; - bool HasOtherCallOutsideSCC = false; + bool HasOtherEdgeToChildC = false; + bool HasOtherChildC = false; for (Node *N : *this) { - for (Node &OtherCalleeN : *N) { - SCC &OtherCalleeC = *G->SCCMap.lookup(&OtherCalleeN); - if (&OtherCalleeC == &CalleeC) { - HasOtherCallToCalleeC = true; + for (Edge &E : *N) { + assert(E.getNode() && "Cannot have a missing node in a visited SCC!"); + SCC &OtherChildC = *G->SCCMap.lookup(E.getNode()); + if (&OtherChildC == &ChildC) { + HasOtherEdgeToChildC = true; break; } - if (&OtherCalleeC != this) - HasOtherCallOutsideSCC = true; + if (&OtherChildC != this) + HasOtherChildC = true; } - if (HasOtherCallToCalleeC) + if (HasOtherEdgeToChildC) break; } // Because the SCCs form a DAG, deleting such an edge cannot change the set // of SCCs in the graph. However, it may cut an edge of the SCC DAG, making - // the caller no longer a parent of the callee. Walk the other call edges - // in the caller to tell. - if (!HasOtherCallToCalleeC) { - bool Removed = CalleeC.ParentSCCs.erase(this); + // the parent SCC no longer connected to the child SCC. If so, we need to + // update the child SCC's map of its parents. + if (!HasOtherEdgeToChildC) { + bool Removed = ChildC.ParentSCCs.erase(this); (void)Removed; assert(Removed && - "Did not find the caller SCC in the callee SCC's parent list!"); + "Did not find the parent SCC in the child SCC's parent list!"); // It may orphan an SCC if it is the last edge reaching it, but that does // not violate any invariants of the graph. - if (CalleeC.ParentSCCs.empty()) - DEBUG(dbgs() << "LCG: Update removing " << CallerN.getFunction().getName() - << " -> " << CalleeN.getFunction().getName() + if (ChildC.ParentSCCs.empty()) + DEBUG(dbgs() << "LCG: Update removing " << ParentN.getFunction().getName() + << " -> " << ChildN.getFunction().getName() << " edge orphaned the callee's SCC!\n"); } - // It may make the Caller SCC a leaf SCC. - if (!HasOtherCallOutsideSCC) + // It may make the Parent SCC a leaf SCC. + if (!HasOtherChildC) G->LeafSCCs.push_back(this); } void LazyCallGraph::SCC::internalDFS( - SmallVectorImpl<std::pair<Node *, Node::iterator>> &DFSStack, + SmallVectorImpl<std::pair<Node *, Node::edge_iterator>> &DFSStack, SmallVectorImpl<Node *> &PendingSCCStack, Node *N, SmallVectorImpl<SCC *> &ResultSCCs) { - Node::iterator I = N->begin(); + auto I = N->begin(); N->LowLink = N->DFSNumber = 1; int NextDFSNumber = 2; for (;;) { @@ -387,9 +406,9 @@ void LazyCallGraph::SCC::internalDFS( "before processing a node."); // We simulate recursion by popping out of the nested loop and continuing. - Node::iterator E = N->end(); + auto E = N->end(); while (I != E) { - Node &ChildN = *I; + Node &ChildN = I->getNode(*G); if (SCC *ChildSCC = G->SCCMap.lookup(&ChildN)) { // Check if we have reached a node in the new (known connected) set of // this SCC. If so, the entire stack is necessarily in that set and we @@ -455,15 +474,15 @@ void LazyCallGraph::SCC::internalDFS( } SmallVector<LazyCallGraph::SCC *, 1> -LazyCallGraph::SCC::removeIntraSCCEdge(Node &CallerN, Node &CalleeN) { +LazyCallGraph::SCC::removeIntraSCCEdge(Node &ParentN, Node &ChildN) { // First remove it from the node. - CallerN.removeEdgeInternal(CalleeN.getFunction()); + ParentN.removeEdgeInternal(ChildN.getFunction()); // We return a list of the resulting *new* SCCs in postorder. SmallVector<SCC *, 1> ResultSCCs; // Direct recursion doesn't impact the SCC graph at all. - if (&CallerN == &CalleeN) + if (&ParentN == &ChildN) return ResultSCCs; // The worklist is every node in the original SCC. @@ -478,16 +497,16 @@ LazyCallGraph::SCC::removeIntraSCCEdge(Node &CallerN, Node &CalleeN) { assert(Worklist.size() > 1 && "We have to have at least two nodes to have an " "edge between them that is within the SCC."); - // The callee can already reach every node in this SCC (by definition). It is + // The child can already reach every node in this SCC (by definition). It is // the only node we know will stay inside this SCC. Everything which - // transitively reaches Callee will also remain in the SCC. To model this we + // transitively reaches Child will also remain in the SCC. To model this we // incrementally add any chain of nodes which reaches something in the new // node set to the new node set. This short circuits one side of the Tarjan's // walk. - insert(CalleeN); + insert(ChildN); // We're going to do a full mini-Tarjan's walk using a local stack here. - SmallVector<std::pair<Node *, Node::iterator>, 4> DFSStack; + SmallVector<std::pair<Node *, Node::edge_iterator>, 4> DFSStack; SmallVector<Node *, 4> PendingSCCStack; do { Node *N = Worklist.pop_back_val(); @@ -501,8 +520,9 @@ LazyCallGraph::SCC::removeIntraSCCEdge(Node &CallerN, Node &CalleeN) { // Now we need to reconnect the current SCC to the graph. bool IsLeafSCC = true; for (Node *N : Nodes) { - for (Node &ChildN : *N) { - SCC &ChildSCC = *G->SCCMap.lookup(&ChildN); + for (Edge &E : *N) { + assert(E.getNode() && "Cannot have a missing node in a visited SCC!"); + SCC &ChildSCC = *G->SCCMap.lookup(E.getNode()); if (&ChildSCC == this) continue; ChildSCC.ParentSCCs.insert(this); @@ -528,18 +548,18 @@ LazyCallGraph::SCC::removeIntraSCCEdge(Node &CallerN, Node &CalleeN) { return ResultSCCs; } -void LazyCallGraph::insertEdge(Node &CallerN, Function &Callee) { +void LazyCallGraph::insertEdge(Node &ParentN, Function &Child, Edge::Kind EK) { assert(SCCMap.empty() && DFSStack.empty() && "This method cannot be called after SCCs have been formed!"); - return CallerN.insertEdgeInternal(Callee); + return ParentN.insertEdgeInternal(Child, EK); } -void LazyCallGraph::removeEdge(Node &CallerN, Function &Callee) { +void LazyCallGraph::removeEdge(Node &ParentN, Function &Child) { assert(SCCMap.empty() && DFSStack.empty() && "This method cannot be called after SCCs have been formed!"); - return CallerN.removeEdgeInternal(Callee); + return ParentN.removeEdgeInternal(Child); } LazyCallGraph::Node &LazyCallGraph::insertInto(Function &F, Node *&MappedN) { @@ -550,17 +570,16 @@ void LazyCallGraph::updateGraphPtrs() { // Process all nodes updating the graph pointers. { SmallVector<Node *, 16> Worklist; - for (auto &Entry : EntryNodes) - if (Node *EntryN = Entry.dyn_cast<Node *>()) + for (Edge &E : EntryEdges) + if (Node *EntryN = E.getNode()) Worklist.push_back(EntryN); while (!Worklist.empty()) { Node *N = Worklist.pop_back_val(); N->G = this; - for (auto &Callee : N->Callees) - if (!Callee.isNull()) - if (Node *CalleeN = Callee.dyn_cast<Node *>()) - Worklist.push_back(CalleeN); + for (Edge &E : N->Edges) + if (Node *ChildN = E.getNode()) + Worklist.push_back(ChildN); } } @@ -596,8 +615,9 @@ LazyCallGraph::SCC *LazyCallGraph::formSCC(Node *RootN, // its children. bool IsLeafSCC = true; for (Node *SCCN : NewSCC->Nodes) - for (Node &SCCChildN : *SCCN) { - SCC &ChildSCC = *SCCMap.lookup(&SCCChildN); + for (Edge &E : *SCCN) { + assert(E.getNode() && "Cannot have a missing node in a visited SCC!"); + SCC &ChildSCC = *SCCMap.lookup(E.getNode()); if (&ChildSCC == NewSCC) continue; ChildSCC.ParentSCCs.insert(NewSCC); @@ -613,7 +633,7 @@ LazyCallGraph::SCC *LazyCallGraph::formSCC(Node *RootN, LazyCallGraph::SCC *LazyCallGraph::getNextSCCInPostOrder() { Node *N; - Node::iterator I; + Node::edge_iterator I; if (!DFSStack.empty()) { N = DFSStack.back().first; I = DFSStack.back().second; @@ -635,9 +655,9 @@ LazyCallGraph::SCC *LazyCallGraph::getNextSCCInPostOrder() { assert(N->DFSNumber != 0 && "We should always assign a DFS number " "before placing a node onto the stack."); - Node::iterator E = N->end(); + auto E = N->end(); while (I != E) { - Node &ChildN = *I; + Node &ChildN = I->getNode(*this); if (ChildN.DFSNumber == 0) { // Mark that we should start at this child when next this node is the // top of the stack. We don't start at the next child to ensure this @@ -686,14 +706,19 @@ LazyCallGraphPrinterPass::LazyCallGraphPrinterPass(raw_ostream &OS) : OS(OS) {} static void printNodes(raw_ostream &OS, LazyCallGraph::Node &N, SmallPtrSetImpl<LazyCallGraph::Node *> &Printed) { + LazyCallGraph &G = N.getGraph(); + // Recurse depth first through the nodes. - for (LazyCallGraph::Node &ChildN : N) + for (LazyCallGraph::Edge &E : N) { + LazyCallGraph::Node &ChildN = E.getNode(G); if (Printed.insert(&ChildN).second) printNodes(OS, ChildN, Printed); + } - OS << " Call edges in function: " << N.getFunction().getName() << "\n"; - for (LazyCallGraph::iterator I = N.begin(), E = N.end(); I != E; ++I) - OS << " -> " << I->getFunction().getName() << "\n"; + OS << " Edges in function: " << N.getFunction().getName() << "\n"; + for (const LazyCallGraph::Edge &E : N) + OS << " " << (E.isCall() ? "call" : "ref ") << " -> " + << E.getFunction().getName() << "\n"; OS << "\n"; } @@ -716,9 +741,11 @@ PreservedAnalyses LazyCallGraphPrinterPass::run(Module &M, << "\n\n"; SmallPtrSet<LazyCallGraph::Node *, 16> Printed; - for (LazyCallGraph::Node &N : G) + for (LazyCallGraph::Edge &E : G) { + LazyCallGraph::Node &N = E.getNode(G); if (Printed.insert(&N).second) printNodes(OS, N, Printed); + } for (LazyCallGraph::SCC &SCC : G.postorder_sccs()) printSCC(OS, SCC); |