aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Analysis
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2009-08-31 00:19:58 +0000
committerChris Lattner <sabre@nondot.org>2009-08-31 00:19:58 +0000
commit3dab7152eedc0d822a9499102303eba526026021 (patch)
treef6801c8985931a1d161538b2daa7961923a4f15d /lib/Analysis
parent637d133ffeaa961837ebc87ee6934be5ef401b8f (diff)
downloadexternal_llvm-3dab7152eedc0d822a9499102303eba526026021.zip
external_llvm-3dab7152eedc0d822a9499102303eba526026021.tar.gz
external_llvm-3dab7152eedc0d822a9499102303eba526026021.tar.bz2
Fix some nasty callgraph dangling pointer problems in
argpromotion and structretpromote. Basically, when replacing a function, they used the 'changeFunction' api which changes the entry in the function map (and steals/reuses the callgraph node). This has some interesting effects: first, the problem is that it doesn't update the "callee" edges in any callees of the function in the call graph. Second, this covers for a major problem in all the CGSCC pass stuff, which is that it is completely broken when functions are deleted if they *don't* reuse a CGN. (there is a cute little fixme about this though :). This patch changes the protocol that CGSCC passes must obey: now the CGSCC pass manager copies the SCC and preincrements its iterator to avoid passes invalidating it. This allows CGSCC passes to mutate the current SCC. However multiple passes may be run on that SCC, so if passes do this, they are now required to *update* the SCC to be current when they return. Other less interesting parts of this patch are that it makes passes update the CG more directly, eliminates changeFunction, and requires clients of replaceCallSite to specify the new callee CGN if they are changing it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80527 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis')
-rw-r--r--lib/Analysis/IPA/CallGraph.cpp25
-rw-r--r--lib/Analysis/IPA/CallGraphSCCPass.cpp20
2 files changed, 21 insertions, 24 deletions
diff --git a/lib/Analysis/IPA/CallGraph.cpp b/lib/Analysis/IPA/CallGraph.cpp
index 453f4c2..08687df 100644
--- a/lib/Analysis/IPA/CallGraph.cpp
+++ b/lib/Analysis/IPA/CallGraph.cpp
@@ -206,20 +206,6 @@ Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) {
return F;
}
-// changeFunction - This method changes the function associated with this
-// CallGraphNode, for use by transformations that need to change the prototype
-// of a Function (thus they must create a new Function and move the old code
-// over).
-void CallGraph::changeFunction(Function *OldF, Function *NewF) {
- iterator I = FunctionMap.find(OldF);
- CallGraphNode *&New = FunctionMap[NewF];
- assert(I != FunctionMap.end() && I->second && !New &&
- "OldF didn't exist in CG or NewF already does!");
- New = I->second;
- New->F = NewF;
- FunctionMap.erase(I);
-}
-
// getOrInsertFunction - This method is identical to calling operator[], but
// it will insert a new CallGraphNode for the specified function if one does
// not already exist.
@@ -233,7 +219,8 @@ 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() <<"'\n";
+ OS << "Call graph node for function: '" << F->getName()
+ << "'<<0x" << this << ">>\n";
else
OS << "Call graph node <<null function: 0x" << this << ">>:\n";
@@ -289,11 +276,17 @@ void CallGraphNode::removeOneAbstractEdgeTo(CallGraphNode *Callee) {
/// replaceCallSite - Make the edge in the node for Old CallSite be for
/// New CallSite instead. Note that this method takes linear time, so it
/// should be used sparingly.
-void CallGraphNode::replaceCallSite(CallSite Old, CallSite New) {
+void CallGraphNode::replaceCallSite(CallSite Old, CallSite New,
+ CallGraphNode *NewCallee) {
for (CalledFunctionsVector::iterator I = CalledFunctions.begin(); ; ++I) {
assert(I != CalledFunctions.end() && "Cannot find callsite to replace!");
if (I->first == Old) {
I->first = New;
+
+ // If the callee is changing, not just the callsite, then update it as
+ // well.
+ if (NewCallee)
+ I->second = NewCallee;
return;
}
}
diff --git a/lib/Analysis/IPA/CallGraphSCCPass.cpp b/lib/Analysis/IPA/CallGraphSCCPass.cpp
index 00eddc4..4a9bf9f 100644
--- a/lib/Analysis/IPA/CallGraphSCCPass.cpp
+++ b/lib/Analysis/IPA/CallGraphSCCPass.cpp
@@ -84,10 +84,16 @@ bool CGPassManager::runOnModule(Module &M) {
CallGraph &CG = getAnalysis<CallGraph>();
bool Changed = doInitialization(CG);
+ std::vector<CallGraphNode*> CurSCC;
+
// Walk SCC
- for (scc_iterator<CallGraph*> I = scc_begin(&CG), E = scc_end(&CG);
- I != E; ++I) {
-
+ for (scc_iterator<CallGraph*> CGI = scc_begin(&CG), E = scc_end(&CG);
+ CGI != E;) {
+ // Copy the current SCC and increment past it so that the pass can hack
+ // on the SCC if it wants to without invalidating our iterator.
+ CurSCC = *CGI;
+ ++CGI;
+
// Run all passes on current SCC
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
Pass *P = getContainedPass(Index);
@@ -99,16 +105,14 @@ bool CGPassManager::runOnModule(Module &M) {
StartPassTimer(P);
if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P))
- Changed |= CGSP->runOnSCC(*I); // TODO : What if CG is changed ?
+ Changed |= CGSP->runOnSCC(CurSCC);
else {
FPPassManager *FPP = dynamic_cast<FPPassManager *>(P);
assert (FPP && "Invalid CGPassManager member");
// Run pass P on all functions current SCC
- std::vector<CallGraphNode*> &SCC = *I;
- for (unsigned i = 0, e = SCC.size(); i != e; ++i) {
- Function *F = SCC[i]->getFunction();
- if (F) {
+ for (unsigned i = 0, e = CurSCC.size(); i != e; ++i) {
+ if (Function *F = CurSCC[i]->getFunction()) {
dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());
Changed |= FPP->runOnFunction(*F);
}