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
This commit is contained in:
Chris Lattner 2006-07-12 18:29:36 +00:00
parent 2ade22835e
commit d85340f4ec
5 changed files with 98 additions and 70 deletions

View File

@ -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<CallGraphNode*> CalledFunctions;
typedef std::pair<CallSite,CallGraphNode*> CallRecord;
std::vector<CallRecord> CalledFunctions;
CallGraphNode(const CallGraphNode &); // Do not implement
public:
@ -175,8 +177,8 @@ public:
// Accessor methods...
//
typedef std::vector<CallGraphNode*>::iterator iterator;
typedef std::vector<CallGraphNode*>::const_iterator const_iterator;
typedef std::vector<CallRecord>::iterator iterator;
typedef std::vector<CallRecord>::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<CallGraphNode*> {
typedef CallGraphNode NodeType;
typedef NodeType::iterator ChildIteratorType;
typedef std::pair<CallSite, CallGraphNode*> CGNPairTy;
typedef std::pointer_to_unary_function<CGNPairTy, CallGraphNode*> 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<NodeType::iterator, CGNDerefFun> 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<const CallGraphNode*> {
@ -270,8 +288,7 @@ template<> struct GraphTraits<CallGraph*> : public GraphTraits<CallGraphNode*> {
return map_iterator(CG->end(), DerefFun(CGdereference));
}
static CallGraphNode &CGdereference (std::pair<const Function*,
CallGraphNode*> P) {
static CallGraphNode &CGdereference(PairTy P) {
return *P.second;
}
};

View File

@ -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<Instruction>(*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<GlobalValue>(*I)) {
for (Value::use_iterator I = GV->use_begin(), E = GV->use_end();
I != E; ++I)
if (Instruction *Inst = dyn_cast<Instruction>(*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 <<null function: 0x" << this << ">>:\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;

View File

@ -263,7 +263,7 @@ void GlobalsModRef::AnalyzeSCC(std::vector<CallGraphNode *> &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;

View File

@ -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

View File

@ -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<const Value*, Value*> &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<const Value*, Value*>::iterator VMI = ValueMap.find(OrigCall);
if (VMI != ValueMap.end()) { // Only copy the edge if the call was inlined!
Instruction *NewCall = cast<Instruction>(VMI->second);
CallerNode->addCalledFunction(CallSite::get(NewCall), I->second);
}
}
}
@ -192,6 +202,8 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) {
// function.
std::vector<ReturnInst*> Returns;
ClonedCodeInfo InlinedFunctionInfo;
Function::iterator FirstNewBlock;
{ // Scope to destroy ValueMap after cloning.
std::map<const Value*, Value*> 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;
}