From d85340f4ec587e22b0239617f3b747a6df113894 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Wed, 12 Jul 2006 18:29:36 +0000 Subject: [PATCH] Change the callgraph representation to store the callsite along with the target CG node. This allows the inliner to properly update the callgraph when using the pruning inliner. The pruning inliner may not copy over all call sites from a callee to a caller, so the edges corresponding to those call sites should not be copied over either. This fixes PR827 and Transforms/Inline/2006-07-12-InlinePruneCGUpdate.ll git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@29120 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Analysis/CallGraph.h | 43 +++++++++---- lib/Analysis/IPA/CallGraph.cpp | 36 ++++++----- lib/Analysis/IPA/GlobalsModRef.cpp | 2 +- lib/Transforms/IPO/Inliner.cpp | 4 +- lib/Transforms/Utils/InlineFunction.cpp | 83 ++++++++++++++----------- 5 files changed, 98 insertions(+), 70 deletions(-) diff --git a/include/llvm/Analysis/CallGraph.h b/include/llvm/Analysis/CallGraph.h index 94cea100485..b567bab474f 100644 --- a/include/llvm/Analysis/CallGraph.h +++ b/include/llvm/Analysis/CallGraph.h @@ -54,6 +54,7 @@ #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Pass.h" +#include "llvm/Support/CallSite.h" namespace llvm { @@ -167,7 +168,8 @@ protected: // class CallGraphNode { Function *F; - std::vector CalledFunctions; + typedef std::pair CallRecord; + std::vector CalledFunctions; CallGraphNode(const CallGraphNode &); // Do not implement public: @@ -175,8 +177,8 @@ public: // Accessor methods... // - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; // getFunction - Return the function that this call graph node represents... Function *getFunction() const { return F; } @@ -189,7 +191,9 @@ public: // Subscripting operator - Return the i'th called function... // - CallGraphNode *operator[](unsigned i) const { return CalledFunctions[i];} + CallGraphNode *operator[](unsigned i) const { + return CalledFunctions[i].second; + } /// dump - Print out this call graph node. /// @@ -209,8 +213,8 @@ public: /// addCalledFunction add a function to the list of functions called by this /// one. - void addCalledFunction(CallGraphNode *M) { - CalledFunctions.push_back(M); + void addCalledFunction(CallSite CS, CallGraphNode *M) { + CalledFunctions.push_back(std::make_pair(CS, M)); } /// removeCallEdgeTo - This method removes a *single* edge to the specified @@ -225,24 +229,38 @@ public: friend class CallGraph; - // CallGraphNode ctor - Create a node for the specified function... + // CallGraphNode ctor - Create a node for the specified function. inline CallGraphNode(Function *f) : F(f) {} }; //===----------------------------------------------------------------------===// // GraphTraits specializations for call graphs so that they can be treated as -// graphs by the generic graph algorithms... +// graphs by the generic graph algorithms. // // Provide graph traits for tranversing call graphs using standard graph // traversals. template <> struct GraphTraits { typedef CallGraphNode NodeType; - typedef NodeType::iterator ChildIteratorType; + typedef std::pair CGNPairTy; + typedef std::pointer_to_unary_function CGNDerefFun; + static NodeType *getEntryNode(CallGraphNode *CGN) { return CGN; } - static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();} - static inline ChildIteratorType child_end (NodeType *N) { return N->end(); } + + typedef mapped_iterator ChildIteratorType; + + static inline ChildIteratorType child_begin(NodeType *N) { + return map_iterator(N->begin(), CGNDerefFun(CGNDeref)); + } + static inline ChildIteratorType child_end (NodeType *N) { + return map_iterator(N->end(), CGNDerefFun(CGNDeref)); + } + + static CallGraphNode *CGNDeref(CGNPairTy P) { + return P.second; + } + }; template <> struct GraphTraits { @@ -270,8 +288,7 @@ template<> struct GraphTraits : public GraphTraits { return map_iterator(CG->end(), DerefFun(CGdereference)); } - static CallGraphNode &CGdereference (std::pair P) { + static CallGraphNode &CGdereference(PairTy P) { return *P.second; } }; diff --git a/lib/Analysis/IPA/CallGraph.cpp b/lib/Analysis/IPA/CallGraph.cpp index 78bb735ffa2..23a7599ce57 100644 --- a/lib/Analysis/IPA/CallGraph.cpp +++ b/lib/Analysis/IPA/CallGraph.cpp @@ -112,9 +112,9 @@ private: void addToCallGraph(Function *F) { CallGraphNode *Node = getOrInsertFunction(F); - // If this function has external linkage, anything could call it... + // If this function has external linkage, anything could call it. if (!F->hasInternalLinkage()) { - ExternalCallingNode->addCalledFunction(Node); + ExternalCallingNode->addCalledFunction(CallSite(), Node); // Found the entry point? if (F->getName() == "main") { @@ -128,27 +128,29 @@ private: // If this function is not defined in this translation unit, it could call // anything. if (F->isExternal() && !F->getIntrinsicID()) - Node->addCalledFunction(CallsExternalNode); + Node->addCalledFunction(CallSite(), CallsExternalNode); // Loop over all of the users of the function... looking for callers... // bool isUsedExternally = false; for (Value::use_iterator I = F->use_begin(), E = F->use_end(); I != E; ++I){ if (Instruction *Inst = dyn_cast(*I)) { - if (isOnlyADirectCall(F, CallSite::get(Inst))) + CallSite CS = CallSite::get(Inst); + if (isOnlyADirectCall(F, CS)) getOrInsertFunction(Inst->getParent()->getParent()) - ->addCalledFunction(Node); + ->addCalledFunction(CS, Node); else isUsedExternally = true; } else if (GlobalValue *GV = dyn_cast(*I)) { for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I != E; ++I) if (Instruction *Inst = dyn_cast(*I)) { - if (isOnlyADirectCall(F, CallSite::get(Inst))) - getOrInsertFunction(Inst->getParent()->getParent()) - ->addCalledFunction(Node); - else - isUsedExternally = true; + CallSite CS = CallSite::get(Inst); + if (isOnlyADirectCall(F, CS)) + getOrInsertFunction(Inst->getParent()->getParent()) + ->addCalledFunction(CS, Node); + else + isUsedExternally = true; } else { isUsedExternally = true; } @@ -157,15 +159,15 @@ private: } } if (isUsedExternally) - ExternalCallingNode->addCalledFunction(Node); + ExternalCallingNode->addCalledFunction(CallSite(), Node); - // Look for an indirect function call... + // Look for an indirect function call. for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB) for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II) { CallSite CS = CallSite::get(II); if (CS.getInstruction() && !CS.getCalledFunction()) - Node->addCalledFunction(CallsExternalNode); + Node->addCalledFunction(CS, CallsExternalNode); } } @@ -261,8 +263,8 @@ void CallGraphNode::print(std::ostream &OS) const { OS << "Call graph node <>:\n"; for (const_iterator I = begin(), E = end(); I != E; ++I) - if ((*I)->getFunction()) - OS << " Calls function '" << (*I)->getFunction()->getName() << "'\n"; + if (I->second->getFunction()) + OS << " Calls function '" << I->second->getFunction()->getName() <<"'\n"; else OS << " Calls external node\n"; OS << "\n"; @@ -273,7 +275,7 @@ void CallGraphNode::dump() const { print(std::cerr); } void CallGraphNode::removeCallEdgeTo(CallGraphNode *Callee) { for (unsigned i = CalledFunctions.size(); ; --i) { assert(i && "Cannot find callee to remove!"); - if (CalledFunctions[i-1] == Callee) { + if (CalledFunctions[i-1].second == Callee) { CalledFunctions.erase(CalledFunctions.begin()+i-1); return; } @@ -285,7 +287,7 @@ void CallGraphNode::removeCallEdgeTo(CallGraphNode *Callee) { // removeCallEdgeTo, so it should not be used unless necessary. void CallGraphNode::removeAnyCallEdgeTo(CallGraphNode *Callee) { for (unsigned i = 0, e = CalledFunctions.size(); i != e; ++i) - if (CalledFunctions[i] == Callee) { + if (CalledFunctions[i].second == Callee) { CalledFunctions[i] = CalledFunctions.back(); CalledFunctions.pop_back(); --i; --e; diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp index 5b3c953bcdf..4765b096b38 100644 --- a/lib/Analysis/IPA/GlobalsModRef.cpp +++ b/lib/Analysis/IPA/GlobalsModRef.cpp @@ -263,7 +263,7 @@ void GlobalsModRef::AnalyzeSCC(std::vector &SCC) { for (unsigned i = 0, e = SCC.size(); i != e && !CallsExternal; ++i) for (CallGraphNode::iterator CI = SCC[i]->begin(), E = SCC[i]->end(); CI != E; ++CI) - if (Function *Callee = (*CI)->getFunction()) { + if (Function *Callee = CI->second->getFunction()) { if (FunctionRecord *CalleeFR = getFunctionInfo(Callee)) { // Propagate function effect up. FunctionEffect |= CalleeFR->FunctionEffect; diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index 89999bb4425..ae4032bbfb3 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -54,7 +54,7 @@ static bool InlineCallIfPossible(CallSite CS, CallGraph &CG, // Remove any call graph edges from the callee to its callees. CallGraphNode *CalleeNode = CG[Callee]; while (CalleeNode->begin() != CalleeNode->end()) - CalleeNode->removeCallEdgeTo(*(CalleeNode->end()-1)); + CalleeNode->removeCallEdgeTo((CalleeNode->end()-1)->second); // Removing the node for callee from the call graph and delete it. delete CG.removeFunctionFromModule(CalleeNode); @@ -168,7 +168,7 @@ bool Inliner::doFinalization(CallGraph &CG) { // Remove any call graph edges from the function to its callees. while (CGN->begin() != CGN->end()) - CGN->removeCallEdgeTo(*(CGN->end()-1)); + CGN->removeCallEdgeTo((CGN->end()-1)->second); // Remove any edges from the external node to the function's call graph // node. These edges might have been made irrelegant due to diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index 37ba3ba6d49..277b10a767f 100644 --- a/lib/Transforms/Utils/InlineFunction.cpp +++ b/lib/Transforms/Utils/InlineFunction.cpp @@ -136,22 +136,32 @@ static void HandleInlinedInvoke(InvokeInst *II, BasicBlock *FirstNewBlock, InvokeDest->removePredecessor(II->getParent()); } -/// UpdateCallGraphAfterInlining - Once we have finished inlining a call from -/// caller to callee, update the specified callgraph to reflect the changes we -/// made. -static void UpdateCallGraphAfterInlining(const Function *Caller, +/// UpdateCallGraphAfterInlining - Once we have cloned code over from a callee +/// into the caller, update the specified callgraph to reflect the changes we +/// made. Note that it's possible that not all code was copied over, so only +/// some edges of the callgraph will be remain. +static void UpdateCallGraphAfterInlining(const Function *Caller, const Function *Callee, + Function::iterator FirstNewBlock, + std::map &ValueMap, CallGraph &CG) { // Update the call graph by deleting the edge from Callee to Caller CallGraphNode *CalleeNode = CG[Callee]; CallGraphNode *CallerNode = CG[Caller]; CallerNode->removeCallEdgeTo(CalleeNode); - // Since we inlined all uninlined call sites in the callee into the caller, + // Since we inlined some uninlined call sites in the callee into the caller, // add edges from the caller to all of the callees of the callee. for (CallGraphNode::iterator I = CalleeNode->begin(), - E = CalleeNode->end(); I != E; ++I) - CallerNode->addCalledFunction(*I); + E = CalleeNode->end(); I != E; ++I) { + const Instruction *OrigCall = I->first.getInstruction(); + + std::map::iterator VMI = ValueMap.find(OrigCall); + if (VMI != ValueMap.end()) { // Only copy the edge if the call was inlined! + Instruction *NewCall = cast(VMI->second); + CallerNode->addCalledFunction(CallSite::get(NewCall), I->second); + } + } } @@ -192,6 +202,8 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) { // function. std::vector Returns; ClonedCodeInfo InlinedFunctionInfo; + Function::iterator FirstNewBlock; + { // Scope to destroy ValueMap after cloning. std::map ValueMap; @@ -211,11 +223,16 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) { // happy with whatever the cloner can do. CloneAndPruneFunctionInto(Caller, CalledFunc, ValueMap, Returns, ".i", &InlinedFunctionInfo); + + // Remember the first block that is newly cloned over. + FirstNewBlock = LastBlock; ++FirstNewBlock; + + // Update the callgraph if requested. + if (CG) + UpdateCallGraphAfterInlining(Caller, CalledFunc, FirstNewBlock, ValueMap, + *CG); } - - // Remember the first block that is newly cloned over. - Function::iterator FirstNewBlock = LastBlock; ++FirstNewBlock; - + // If there are any alloca instructions in the block that used to be the entry // block for the callee, move them to the entry block of the caller. First // calculate which instruction they should be inserted before. We insert the @@ -252,15 +269,27 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) { StackSave = M->getOrInsertFunction("llvm.stacksave", SBytePtr, NULL); StackRestore = M->getOrInsertFunction("llvm.stackrestore", Type::VoidTy, SBytePtr, NULL); - + + // If we are preserving the callgraph, add edges to the stacksave/restore + // functions for the calls we insert. + CallGraphNode *StackSaveCGN, *StackRestoreCGN, *CallerNode; + if (CG) { + StackSaveCGN = CG->getOrInsertFunction(StackSave); + StackRestoreCGN = CG->getOrInsertFunction(StackRestore); + CallerNode = (*CG)[Caller]; + } + // Insert the llvm.stacksave. - Value *SavedPtr = new CallInst(StackSave, "savedstack", - FirstNewBlock->begin()); - + CallInst *SavedPtr = new CallInst(StackSave, "savedstack", + FirstNewBlock->begin()); + if (CG) CallerNode->addCalledFunction(SavedPtr, StackSaveCGN); + // Insert a call to llvm.stackrestore before any return instructions in the // inlined function. - for (unsigned i = 0, e = Returns.size(); i != e; ++i) - new CallInst(StackRestore, SavedPtr, "", Returns[i]); + for (unsigned i = 0, e = Returns.size(); i != e; ++i) { + CallInst *CI = new CallInst(StackRestore, SavedPtr, "", Returns[i]); + if (CG) CallerNode->addCalledFunction(CI, StackRestoreCGN); + } // Count the number of StackRestore calls we insert. unsigned NumStackRestores = Returns.size(); @@ -275,20 +304,6 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) { ++NumStackRestores; } } - - // If we are supposed to update the callgraph, do so now. - if (CG) { - CallGraphNode *StackSaveCGN = CG->getOrInsertFunction(StackSave); - CallGraphNode *StackRestoreCGN = CG->getOrInsertFunction(StackRestore); - CallGraphNode *CallerNode = (*CG)[Caller]; - - // 'Caller' now calls llvm.stacksave one more time. - CallerNode->addCalledFunction(StackSaveCGN); - - // 'Caller' now calls llvm.stackrestore the appropriate number of times. - for (unsigned i = 0; i != NumStackRestores; ++i) - CallerNode->addCalledFunction(StackRestoreCGN); - } } // If we are inlining tail call instruction through a call site that isn't @@ -334,9 +349,6 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) { // Since we are now done with the return instruction, delete it also. Returns[0]->getParent()->getInstList().erase(Returns[0]); - // Update the callgraph if requested. - if (CG) UpdateCallGraphAfterInlining(Caller, CalledFunc, *CG); - // We are now done with the inlining. return true; } @@ -463,8 +475,5 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) { // Now we can remove the CalleeEntry block, which is now empty. Caller->getBasicBlockList().erase(CalleeEntry); - // Update the callgraph if requested. - if (CG) UpdateCallGraphAfterInlining(Caller, CalledFunc, *CG); - return true; }