summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Analysis/CallGraph.h40
-rw-r--r--lib/Analysis/IPA/CallGraph.cpp37
-rw-r--r--lib/Transforms/IPO/Inliner.cpp15
-rw-r--r--test/Transforms/Inline/indirect_resolve.ll16
4 files changed, 76 insertions, 32 deletions
diff --git a/include/llvm/Analysis/CallGraph.h b/include/llvm/Analysis/CallGraph.h
index 59dc3449b7..bc022e3417 100644
--- a/include/llvm/Analysis/CallGraph.h
+++ b/include/llvm/Analysis/CallGraph.h
@@ -77,7 +77,7 @@ protected:
public:
static char ID; // Class identification, replacement for typeinfo
//===---------------------------------------------------------------------
- // Accessors...
+ // Accessors.
//
typedef FunctionMapTy::iterator iterator;
typedef FunctionMapTy::const_iterator const_iterator;
@@ -136,7 +136,7 @@ public:
CallGraphNode *getOrInsertFunction(const Function *F);
//===---------------------------------------------------------------------
- // Pass infrastructure interface glue code...
+ // Pass infrastructure interface glue code.
//
protected:
CallGraph() {}
@@ -163,19 +163,31 @@ class CallGraphNode {
Function *F;
typedef std::pair<CallSite,CallGraphNode*> CallRecord;
std::vector<CallRecord> CalledFunctions;
+
+ /// NumReferences - This is the number of times that this CallGraphNode occurs
+ /// in the CalledFunctions array of this or other CallGraphNodes.
+ unsigned NumReferences;
- CallGraphNode(const CallGraphNode &); // Do not implement
+ CallGraphNode(const CallGraphNode &); // DO NOT IMPLEMENT
+ void operator=(const CallGraphNode &); // DO NOT IMPLEMENT
+
+ void DropRef() { --NumReferences; }
+ void AddRef() { ++NumReferences; }
public:
typedef std::vector<CallRecord> CalledFunctionsVector;
+
+ // CallGraphNode ctor - Create a node for the specified function.
+ inline CallGraphNode(Function *f) : F(f), NumReferences(0) {}
+
//===---------------------------------------------------------------------
- // Accessor methods...
+ // Accessor methods.
//
typedef std::vector<CallRecord>::iterator iterator;
typedef std::vector<CallRecord>::const_iterator const_iterator;
- // getFunction - Return the function that this call graph node represents...
+ // getFunction - Return the function that this call graph node represents.
Function *getFunction() const { return F; }
inline iterator begin() { return CalledFunctions.begin(); }
@@ -185,9 +197,14 @@ public:
inline bool empty() const { return CalledFunctions.empty(); }
inline unsigned size() const { return (unsigned)CalledFunctions.size(); }
- // Subscripting operator - Return the i'th called function...
+ /// getNumReferences - Return the number of other CallGraphNodes in this
+ /// CallGraph that reference this node in their callee list.
+ unsigned getNumReferences() const { return NumReferences; }
+
+ // Subscripting operator - Return the i'th called function.
//
CallGraphNode *operator[](unsigned i) const {
+ assert(i < CalledFunctions.size() && "Invalid index");
return CalledFunctions[i].second;
}
@@ -204,7 +221,10 @@ public:
/// removeAllCalledFunctions - As the name implies, this removes all edges
/// from this CallGraphNode to any functions it calls.
void removeAllCalledFunctions() {
- CalledFunctions.clear();
+ while (!CalledFunctions.empty()) {
+ CalledFunctions.back().second->DropRef();
+ CalledFunctions.pop_back();
+ }
}
/// stealCalledFunctionsFrom - Move all the callee information from N to this
@@ -220,6 +240,7 @@ public:
/// one.
void addCalledFunction(CallSite CS, CallGraphNode *M) {
CalledFunctions.push_back(std::make_pair(CS, M));
+ M->AddRef();
}
/// removeCallEdgeFor - This method removes the edge in the node for the
@@ -240,11 +261,6 @@ public:
/// New CallSite instead. Note that this method takes linear time, so it
/// should be used sparingly.
void replaceCallSite(CallSite Old, CallSite New, CallGraphNode *NewCallee);
-
- friend class CallGraph;
-
- // CallGraphNode ctor - Create a node for the specified function.
- inline CallGraphNode(Function *f) : F(f) {}
};
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/IPA/CallGraph.cpp b/lib/Analysis/IPA/CallGraph.cpp
index 152add93ef..9711013bea 100644
--- a/lib/Analysis/IPA/CallGraph.cpp
+++ b/lib/Analysis/IPA/CallGraph.cpp
@@ -53,7 +53,7 @@ public:
CallsExternalNode = new CallGraphNode(0);
Root = 0;
- // Add every function to the call graph...
+ // Add every function to the call graph.
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
addToCallGraph(I);
@@ -169,12 +169,12 @@ void CallGraph::initialize(Module &M) {
}
void CallGraph::destroy() {
- if (!FunctionMap.empty()) {
- for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
- I != E; ++I)
- delete I->second;
- FunctionMap.clear();
- }
+ if (FunctionMap.empty()) return;
+
+ for (FunctionMapTy::iterator I = FunctionMap.begin(), E = FunctionMap.end();
+ I != E; ++I)
+ delete I->second;
+ FunctionMap.clear();
}
void CallGraph::print(raw_ostream &OS, Module*) const {
@@ -219,10 +219,11 @@ CallGraphNode *CallGraph::getOrInsertFunction(const Function *F) {
void CallGraphNode::print(raw_ostream &OS) const {
if (Function *F = getFunction())
- OS << "Call graph node for function: '" << F->getName()
- << "'<<0x" << this << ">>\n";
+ OS << "Call graph node for function: '" << F->getName() << "'";
else
- OS << "Call graph node <<null function: 0x" << this << ">>:\n";
+ OS << "Call graph node <<null function>>";
+
+ OS << "<<0x" << this << ">> #uses=" << getNumReferences() << '\n';
for (const_iterator I = begin(), E = end(); I != E; ++I)
if (Function *FI = I->second->getFunction())
@@ -241,7 +242,9 @@ void CallGraphNode::removeCallEdgeFor(CallSite CS) {
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
assert(I != CalledFunctions.end() && "Cannot find callsite to remove!");
if (I->first == CS) {
- CalledFunctions.erase(I);
+ I->second->DropRef();
+ *I = CalledFunctions.back();
+ CalledFunctions.pop_back();
return;
}
}
@@ -254,6 +257,7 @@ void CallGraphNode::removeCallEdgeFor(CallSite CS) {
void CallGraphNode::removeAnyCallEdgeTo(CallGraphNode *Callee) {
for (unsigned i = 0, e = CalledFunctions.size(); i != e; ++i)
if (CalledFunctions[i].second == Callee) {
+ Callee->DropRef();
CalledFunctions[i] = CalledFunctions.back();
CalledFunctions.pop_back();
--i; --e;
@@ -266,8 +270,10 @@ void CallGraphNode::removeOneAbstractEdgeTo(CallGraphNode *Callee) {
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
assert(I != CalledFunctions.end() && "Cannot find callee to remove!");
CallRecord &CR = *I;
- if (CR.second == Callee && !CR.first.getInstruction()) {
- CalledFunctions.erase(I);
+ if (CR.second == Callee && CR.first.getInstruction() == 0) {
+ Callee->DropRef();
+ *I = CalledFunctions.back();
+ CalledFunctions.pop_back();
return;
}
}
@@ -285,8 +291,11 @@ void CallGraphNode::replaceCallSite(CallSite Old, CallSite New,
// If the callee is changing, not just the callsite, then update it as
// well.
- if (NewCallee)
+ if (NewCallee) {
+ I->second->DropRef();
I->second = NewCallee;
+ I->second->AddRef();
+ }
return;
}
}
diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp
index d5967fb11c..9b8e0a1fc4 100644
--- a/lib/Transforms/IPO/Inliner.cpp
+++ b/lib/Transforms/IPO/Inliner.cpp
@@ -293,10 +293,12 @@ bool Inliner::runOnSCC(std::vector<CallGraphNode*> &SCC) {
// If we inlined the last possible call site to the function, delete the
// function body now.
- if (Callee->use_empty() &&
- (Callee->hasLocalLinkage() ||
- Callee->hasAvailableExternallyLinkage()) &&
- !SCCFunctions.count(Callee)) {
+ if (Callee->use_empty() && Callee->hasLocalLinkage() &&
+ !SCCFunctions.count(Callee) &&
+ // The function may be apparently dead, but if there are indirect
+ // callgraph references to the node, we cannot delete it yet, this
+ // could invalidate the CGSCC iterator.
+ CG[Callee]->getNumReferences() == 0) {
DEBUG(errs() << " -> Deleting dead function: "
<< Callee->getName() << "\n");
CallGraphNode *CalleeNode = CG[Callee];
@@ -353,7 +355,7 @@ bool Inliner::removeDeadFunctions(CallGraph &CG,
// 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;
- if (CGN == 0 || CGN->getFunction() == 0)
+ if (CGN->getFunction() == 0)
continue;
Function *F = CGN->getFunction();
@@ -364,7 +366,8 @@ bool Inliner::removeDeadFunctions(CallGraph &CG,
if (DNR && DNR->count(F))
continue;
- if (!F->hasLinkOnceLinkage() && !F->hasLocalLinkage())
+ if (!F->hasLinkOnceLinkage() && !F->hasLocalLinkage() &&
+ !F->hasAvailableExternallyLinkage())
continue;
if (!F->use_empty())
continue;
diff --git a/test/Transforms/Inline/indirect_resolve.ll b/test/Transforms/Inline/indirect_resolve.ll
new file mode 100644
index 0000000000..4be55d4342
--- /dev/null
+++ b/test/Transforms/Inline/indirect_resolve.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as < %s | opt -inline | llvm-dis
+; PR4834
+
+define i32 @main() {
+ %funcall1_ = call fastcc i32 ()* ()* @f1()
+ %executecommandptr1_ = call i32 %funcall1_()
+ ret i32 %executecommandptr1_
+}
+
+define internal fastcc i32 ()* @f1() nounwind readnone {
+ ret i32 ()* @f2
+}
+
+define internal i32 @f2() nounwind readnone {
+ ret i32 1
+}