summaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/ArgumentPromotion.cpp
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
commit5095e3d1d1caef8d573534d369e37277c623064c (patch)
treef6801c8985931a1d161538b2daa7961923a4f15d /lib/Transforms/IPO/ArgumentPromotion.cpp
parent52248ff682e13315e5be08824bdd1d340e02d610 (diff)
downloadllvm-5095e3d1d1caef8d573534d369e37277c623064c.tar.gz
llvm-5095e3d1d1caef8d573534d369e37277c623064c.tar.bz2
llvm-5095e3d1d1caef8d573534d369e37277c623064c.tar.xz
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/Transforms/IPO/ArgumentPromotion.cpp')
-rw-r--r--lib/Transforms/IPO/ArgumentPromotion.cpp52
1 files changed, 30 insertions, 22 deletions
diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp
index 75843e84d2..18bd39afce 100644
--- a/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -65,7 +65,7 @@ namespace {
CallGraphSCCPass::getAnalysisUsage(AU);
}
- virtual bool runOnSCC(const std::vector<CallGraphNode *> &SCC);
+ virtual bool runOnSCC(std::vector<CallGraphNode *> &SCC);
static char ID; // Pass identification, replacement for typeid
explicit ArgPromotion(unsigned maxElements = 3)
: CallGraphSCCPass(&ID), maxElements(maxElements) {}
@@ -74,11 +74,11 @@ namespace {
typedef std::vector<uint64_t> IndicesVector;
private:
- bool PromoteArguments(CallGraphNode *CGN);
+ CallGraphNode *PromoteArguments(CallGraphNode *CGN);
bool isSafeToPromoteArgument(Argument *Arg, bool isByVal) const;
- Function *DoPromotion(Function *F,
- SmallPtrSet<Argument*, 8> &ArgsToPromote,
- SmallPtrSet<Argument*, 8> &ByValArgsToTransform);
+ CallGraphNode *DoPromotion(Function *F,
+ SmallPtrSet<Argument*, 8> &ArgsToPromote,
+ SmallPtrSet<Argument*, 8> &ByValArgsToTransform);
/// The maximum number of elements to expand, or 0 for unlimited.
unsigned maxElements;
};
@@ -92,14 +92,17 @@ Pass *llvm::createArgumentPromotionPass(unsigned maxElements) {
return new ArgPromotion(maxElements);
}
-bool ArgPromotion::runOnSCC(const std::vector<CallGraphNode *> &SCC) {
+bool ArgPromotion::runOnSCC(std::vector<CallGraphNode *> &SCC) {
bool Changed = false, LocalChange;
do { // Iterate until we stop promoting from this SCC.
LocalChange = false;
// Attempt to promote arguments from all functions in this SCC.
for (unsigned i = 0, e = SCC.size(); i != e; ++i)
- LocalChange |= PromoteArguments(SCC[i]);
+ if (CallGraphNode *CGN = PromoteArguments(SCC[i])) {
+ LocalChange = true;
+ SCC[i] = CGN;
+ }
Changed |= LocalChange; // Remember that we changed something.
} while (LocalChange);
@@ -111,11 +114,11 @@ bool ArgPromotion::runOnSCC(const std::vector<CallGraphNode *> &SCC) {
/// example, all callers are direct). If safe to promote some arguments, it
/// calls the DoPromotion method.
///
-bool ArgPromotion::PromoteArguments(CallGraphNode *CGN) {
+CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) {
Function *F = CGN->getFunction();
// Make sure that it is local to this module.
- if (!F || !F->hasLocalLinkage()) return false;
+ if (!F || !F->hasLocalLinkage()) return 0;
// First check: see if there are any pointer arguments! If not, quick exit.
SmallVector<std::pair<Argument*, unsigned>, 16> PointerArgs;
@@ -124,12 +127,12 @@ bool ArgPromotion::PromoteArguments(CallGraphNode *CGN) {
I != E; ++I, ++ArgNo)
if (isa<PointerType>(I->getType()))
PointerArgs.push_back(std::pair<Argument*, unsigned>(I, ArgNo));
- if (PointerArgs.empty()) return false;
+ if (PointerArgs.empty()) return 0;
// Second check: make sure that all callers are direct callers. We can't
// transform functions that have indirect callers.
if (F->hasAddressTaken())
- return false;
+ return 0;
// Check to see which arguments are promotable. If an argument is promotable,
// add it to ArgsToPromote.
@@ -174,13 +177,10 @@ bool ArgPromotion::PromoteArguments(CallGraphNode *CGN) {
}
// No promotable pointer arguments.
- if (ArgsToPromote.empty() && ByValArgsToTransform.empty()) return false;
+ if (ArgsToPromote.empty() && ByValArgsToTransform.empty())
+ return 0;
- Function *NewF = DoPromotion(F, ArgsToPromote, ByValArgsToTransform);
-
- // Update the call graph to know that the function has been transformed.
- getAnalysis<CallGraph>().changeFunction(F, NewF);
- return true;
+ return DoPromotion(F, ArgsToPromote, ByValArgsToTransform);
}
/// IsAlwaysValidPointer - Return true if the specified pointer is always legal
@@ -469,8 +469,8 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, bool isByVal) const {
/// DoPromotion - This method actually performs the promotion of the specified
/// arguments, and returns the new function. At this point, we know that it's
/// safe to do so.
-Function *ArgPromotion::DoPromotion(Function *F,
- SmallPtrSet<Argument*, 8> &ArgsToPromote,
+CallGraphNode *ArgPromotion::DoPromotion(Function *F,
+ SmallPtrSet<Argument*, 8> &ArgsToPromote,
SmallPtrSet<Argument*, 8> &ByValArgsToTransform) {
// Start by computing a new prototype for the function, which is the same as
@@ -608,6 +608,10 @@ Function *ArgPromotion::DoPromotion(Function *F,
// Get the callgraph information that we need to update to reflect our
// changes.
CallGraph &CG = getAnalysis<CallGraph>();
+
+ // Get a new callgraph node for NF.
+ CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF);
+
// Loop over all of the callers of the function, transforming the call sites
// to pass in the loaded pointers.
@@ -720,7 +724,7 @@ Function *ArgPromotion::DoPromotion(Function *F,
AA.replaceWithNewValue(Call, New);
// Update the callgraph to know that the callsite has been transformed.
- CG[Call->getParent()->getParent()]->replaceCallSite(Call, New);
+ CG[Call->getParent()->getParent()]->replaceCallSite(Call, New, NF_CGN);
if (!Call->use_empty()) {
Call->replaceAllUsesWith(New);
@@ -856,7 +860,11 @@ Function *ArgPromotion::DoPromotion(Function *F,
// Tell the alias analysis that the old function is about to disappear.
AA.replaceWithNewValue(F, NF);
+
+ NF_CGN->stealCalledFunctionsFrom(CG[F]);
+
// Now that the old function is dead, delete it.
- F->eraseFromParent();
- return NF;
+ delete CG.removeFunctionFromModule(F);
+
+ return NF_CGN;
}