From 3e1358a9fa1ebd3f51c94eb69da55d693895fe7c Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 21 Apr 2004 20:44:33 +0000 Subject: [PATCH] Fix an incredibly nasty iterator invalidation problem. I am too spoiled by ilists :) Eventually it would be nice if CallGraph maintained an ilist of CallGraphNode's instead of a vector of pointers to them, but today is not that day. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@13100 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/IPO/Inliner.cpp | 56 +++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index fdea3736259..0eaf67509c2 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -105,14 +105,6 @@ bool Inliner::runOnSCC(const std::vector &SCC) { for (CallGraphNode::iterator I = CalleeNode->begin(), E = CalleeNode->end(); I != E; ++I) CallerNode->addCalledFunction(*I); - - // If the only remaining use of the function is a dead constant - // pointer ref, remove it. - if (Callee->hasOneUse()) - if (ConstantPointerRef *CPR = - dyn_cast(Callee->use_back())) - if (CPR->use_empty()) - CPR->destroyConstant(); // If we inlined the last possible call site to the function, // delete the function body now. @@ -142,27 +134,55 @@ bool Inliner::runOnSCC(const std::vector &SCC) { // doFinalization - Remove now-dead linkonce functions at the end of // processing to avoid breaking the SCC traversal. bool Inliner::doFinalization(CallGraph &CG) { - bool Changed = false; - for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ) { - CallGraphNode *CGN = (I++)->second; + std::set FunctionsToRemove; + + // Scan for all of the functions, looking for ones that should now be removed + // from the program. Insert the dead ones in the FunctionsToRemove set. + for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) { + CallGraphNode *CGN = I->second; Function *F = CGN ? CGN->getFunction() : 0; + + // If the only remaining use of the function is a dead constant + // pointer ref, remove it. + if (F && F->hasOneUse()) + if (ConstantPointerRef *CPR = dyn_cast(F->use_back())) + if (CPR->use_empty()) { + CPR->destroyConstant(); + if (F->hasInternalLinkage()) { + // There *MAY* be an edge from the external call node to this + // function. If so, remove it. + CallGraphNode *EN = CG.getExternalCallingNode(); + CallGraphNode::iterator I = std::find(EN->begin(), EN->end(), CGN); + if (I != EN->end()) EN->removeCallEdgeTo(CGN); + } + } + if (F && (F->hasLinkOnceLinkage() || F->hasInternalLinkage()) && F->use_empty()) { - // Remove any call graph edges from the callee to its callees. + // Remove any call graph edges from the function to its callees. while (CGN->begin() != CGN->end()) CGN->removeCallEdgeTo(*(CGN->end()-1)); - // If the function has external linkage (basically if it's a - // linkonce function) remove the edge from the external node to the - // callee node. + // If the function has external linkage (basically if it's a linkonce + // function) remove the edge from the external node to the callee node. if (!F->hasInternalLinkage()) CG.getExternalCallingNode()->removeCallEdgeTo(CGN); // Removing the node for callee from the call graph and delete it. - delete CG.removeFunctionFromModule(CGN); - ++NumDeleted; - Changed = true; + FunctionsToRemove.insert(CGN); } } + + // Now that we know which functions to delete, do so. We didn't want to do + // this inline, because that would invalidate our CallGraph::iterator + // objects. :( + bool Changed = false; + for (std::set::iterator I = FunctionsToRemove.begin(), + E = FunctionsToRemove.end(); I != E; ++I) { + delete CG.removeFunctionFromModule(*I); + ++NumDeleted; + Changed = true; + } + return Changed; }