mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-09-08 23:55:03 +00:00
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:
parent
2ade22835e
commit
d85340f4ec
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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,25 +128,27 @@ 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)))
|
||||
CallSite CS = CallSite::get(Inst);
|
||||
if (isOnlyADirectCall(F, CS))
|
||||
getOrInsertFunction(Inst->getParent()->getParent())
|
||||
->addCalledFunction(Node);
|
||||
->addCalledFunction(CS, Node);
|
||||
else
|
||||
isUsedExternally = true;
|
||||
} else {
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
/// 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,10 +223,15 @@ 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.
|
||||
Function::iterator FirstNewBlock = LastBlock; ++FirstNewBlock;
|
||||
FirstNewBlock = LastBlock; ++FirstNewBlock;
|
||||
|
||||
// Update the callgraph if requested.
|
||||
if (CG)
|
||||
UpdateCallGraphAfterInlining(Caller, CalledFunc, FirstNewBlock, ValueMap,
|
||||
*CG);
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -253,14 +270,26 @@ bool llvm::InlineFunction(CallSite CS, CallGraph *CG) {
|
||||
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",
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user