aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2004-05-23 21:21:17 +0000
committerChris Lattner <sabre@nondot.org>2004-05-23 21:21:17 +0000
commit9e7cc2f0d42aa4127e3b8406e25907a96ce9ada0 (patch)
tree72a950a0de577d8b0a9029158975f852f01be7da
parent2741c971044d2165be572749b94398043caccfeb (diff)
Fairly substantial changes to update the alias analysis we are querying as
we make the transformation. This allows us to use interprocedural alias analyses successfully. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@13691 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/IPO/ArgumentPromotion.cpp131
1 files changed, 92 insertions, 39 deletions
diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp
index 438f48b8e1..79d19ad309 100644
--- a/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -1,4 +1,4 @@
-//===-- ArgumentPromotion.cpp - Promote 'by reference' arguments ----------===//
+//===-- ArgumentPromotion.cpp - Promote by-reference arguments ------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,14 +12,14 @@
// arguments. If we can prove, through the use of alias analysis, that that an
// argument is *only* loaded, then we can pass the value into the function
// instead of the address of the value. This can cause recursive simplification
-// of code, and lead to the elimination of allocas, especially in C++ template
-// code like the STL.
+// of code and lead to the elimination of allocas (especially in C++ template
+// code like the STL).
//
// This pass also handles aggregate arguments that are passed into a function,
// scalarizing them if the elements of the aggregate are only loaded. Note that
// we refuse to scalarize aggregates which would require passing in more than
// three operands to the function, because we don't want to pass thousands of
-// operands for a large array or something!
+// operands for a large array or structure!
//
// Note that this transformation could also be done for arguments that are only
// stored to (returning the value instead), but we do not currently handle that
@@ -28,6 +28,7 @@
//
//===----------------------------------------------------------------------===//
+#define DEBUG_TYPE "argpromotion"
#include "llvm/Transforms/IPO.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
@@ -58,7 +59,7 @@ namespace {
class ArgPromotion : public Pass {
// WorkList - The set of internal functions that we have yet to process. As
// we eliminate arguments from a function, we push all callers into this set
- // so that the by reference argument can be bubbled out as far as possible.
+ // so that the by-reference argument can be bubbled out as far as possible.
// This set contains only internal functions.
std::set<Function*> WorkList;
public:
@@ -128,7 +129,11 @@ bool ArgPromotion::run(Module &M) {
return Changed;
}
-
+/// PromoteArguments - This method checks the specified function to see if there
+/// are any promotable arguments and if it is safe to promote the function (for
+/// example, all callers are direct). If safe to promote some arguments, it
+/// calls the DoPromotion method.
+///
bool ArgPromotion::PromoteArguments(Function *F) {
assert(F->hasInternalLinkage() && "We can only process internal functions!");
@@ -144,15 +149,14 @@ bool ArgPromotion::PromoteArguments(Function *F) {
for (Value::use_iterator UI = F->use_begin(), E = F->use_end();
UI != E; ++UI) {
CallSite CS = CallSite::get(*UI);
- if (Instruction *I = CS.getInstruction()) {
- // Ensure that this call site is CALLING the function, not passing it as
- // an argument.
- for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
- AI != E; ++AI)
- if (*AI == F) return false; // Passing the function address in!
- } else {
- return false; // Cannot promote an indirect call!
- }
+ if (!CS.getInstruction()) // "Taking the address" of the function
+ return false;
+
+ // Ensure that this call site is CALLING the function, not passing it as
+ // an argument.
+ for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end();
+ AI != E; ++AI)
+ if (*AI == F) return false; // Passing the function address in!
}
// Check to see which arguments are promotable. If an argument is not
@@ -171,6 +175,12 @@ bool ArgPromotion::PromoteArguments(Function *F) {
return true;
}
+
+/// isSafeToPromoteArgument - As you might guess from the name of this method,
+/// it checks to see if it is both safe and useful to promote the argument.
+/// This method limits promotion of aggregates to only promote up to three
+/// elements of the aggregate in order to avoid exploding the number of
+/// arguments passed in.
bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg) const {
// We can only promote this argument if all of the uses are loads, or are GEP
// instructions (with constant indices) that are subsequently loaded.
@@ -185,6 +195,7 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg) const {
if (GEP->use_empty()) {
// Dead GEP's cause trouble later. Just remove them if we run into
// them.
+ getAnalysis<AliasAnalysis>().deleteValue(GEP);
GEP->getParent()->getInstList().erase(GEP);
return isSafeToPromoteArgument(Arg);
}
@@ -206,12 +217,15 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg) const {
return false;
}
- // See if there is already a GEP with these indices. If so, check to make
- // sure that we aren't promoting too many elements. If not, nothing to
- // do.
+ // See if there is already a GEP with these indices. If not, check to
+ // make sure that we aren't promoting too many elements. If so, nothing
+ // to do.
if (std::find(GEPIndices.begin(), GEPIndices.end(), Operands) ==
GEPIndices.end()) {
if (GEPIndices.size() == 3) {
+ DEBUG(std::cerr << "argpromotion disable promoting argument '"
+ << Arg->getName() << "' because it would require adding more "
+ << "than 3 arguments to the function.\n");
// We limit aggregate promotion to only promoting up to three elements
// of the aggregate.
return false;
@@ -222,11 +236,11 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg) const {
return false; // Not a load or a GEP.
}
- if (Loads.empty()) return true; // No users, dead argument.
+ if (Loads.empty()) return true; // No users, this is a dead argument.
- // Okay, now we know that the argument is only used by load instructions.
- // Check to see if the pointer is guaranteed to not be modified from entry of
- // the function to each of the load instructions.
+ // Okay, now we know that the argument is only used by load instructions. Use
+ // alias analysis to check to see if the pointer is guaranteed to not be
+ // modified from entry of the function to each of the load instructions.
Function &F = *Arg->getParent();
// Because there could be several/many load instructions, remember which
@@ -265,7 +279,8 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg) const {
return true;
}
-
+/// DoPromotion - This method actually performs the promotion of the specified
+/// arguments. At this point, we know that it's safe to do so.
void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
std::set<Argument*> ArgsToPromote(Args2Prom.begin(), Args2Prom.end());
@@ -283,10 +298,17 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
//
std::map<Argument*, std::set<std::vector<Value*> > > ScalarizedElements;
+ // OriginalLoads - Keep track of a representative load instruction from the
+ // original function so that we can tell the alias analysis implementation
+ // what the new GEP/Load instructions we are inserting look like.
+ std::map<std::vector<Value*>, LoadInst*> OriginalLoads;
+
for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I)
if (!ArgsToPromote.count(I)) {
Params.push_back(I->getType());
- } else if (!I->use_empty()) {
+ } else if (I->use_empty()) {
+ ++NumArgumentsDead;
+ } else {
// Okay, this is being promoted. Check to see if there are any GEP uses
// of the argument.
std::set<std::vector<Value*> > &ArgIndices = ScalarizedElements[I];
@@ -294,8 +316,14 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
++UI) {
Instruction *User = cast<Instruction>(*UI);
assert(isa<LoadInst>(User) || isa<GetElementPtrInst>(User));
- ArgIndices.insert(std::vector<Value*>(User->op_begin()+1,
- User->op_end()));
+ std::vector<Value*> Indices(User->op_begin()+1, User->op_end());
+ ArgIndices.insert(Indices);
+ LoadInst *OrigLoad;
+ if (LoadInst *L = dyn_cast<LoadInst>(User))
+ OrigLoad = L;
+ else
+ OrigLoad = cast<LoadInst>(User->use_back());
+ OriginalLoads[Indices] = OrigLoad;
}
// Add a parameter to the function for each element passed in.
@@ -307,8 +335,6 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
++NumArgumentsPromoted;
else
++NumAggregatesPromoted;
- } else {
- ++NumArgumentsDead;
}
const Type *RetTy = FTy->getReturnType();
@@ -325,7 +351,11 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
// Create the new function body and insert it into the module...
Function *NF = new Function(NFTy, F->getLinkage(), F->getName());
F->getParent()->getFunctionList().insert(F, NF);
-
+
+ // Get the alias analysis information that we need to update to reflect our
+ // changes.
+ AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
+
// Loop over all of the callers of the function, transforming the call sites
// to pass in the loaded pointers.
//
@@ -334,25 +364,30 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
CallSite CS = CallSite::get(F->use_back());
Instruction *Call = CS.getInstruction();
- // Make sure the caller of this function is revisited.
+ // Make sure the caller of this function is revisited now that we promoted
+ // arguments in a callee of it.
if (Call->getParent()->getParent()->hasInternalLinkage())
WorkList.insert(Call->getParent()->getParent());
- // Loop over the operands, deleting dead ones...
+ // Loop over the operands, inserting GEP and loads in the caller as
+ // appropriate.
CallSite::arg_iterator AI = CS.arg_begin();
for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I, ++AI)
if (!ArgsToPromote.count(I))
Args.push_back(*AI); // Unmodified argument
else if (!I->use_empty()) {
- // Non-dead argument.
+ // Non-dead argument: insert GEPs and loads as appropriate.
std::set<std::vector<Value*> > &ArgIndices = ScalarizedElements[I];
for (std::set<std::vector<Value*> >::iterator SI = ArgIndices.begin(),
E = ArgIndices.end(); SI != E; ++SI) {
Value *V = *AI;
- if (!SI->empty())
+ LoadInst *OrigLoad = OriginalLoads[*SI];
+ if (!SI->empty()) {
V = new GetElementPtrInst(V, *SI, V->getName()+".idx", Call);
-
+ AA.copyValue(OrigLoad->getOperand(0), V);
+ }
Args.push_back(new LoadInst(V, V->getName()+".val", Call));
+ AA.copyValue(OrigLoad, Args.back());
}
}
@@ -372,6 +407,10 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
}
Args.clear();
+ // Update the alias analysis implementation to know that we are replacing
+ // the old call with a new one.
+ AA.replaceWithNewValue(Call, New);
+
if (!Call->use_empty()) {
Call->replaceAllUsesWith(New);
std::string Name = Call->getName();
@@ -399,8 +438,11 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
// new version.
I->replaceAllUsesWith(I2);
I2->setName(I->getName());
+ AA.replaceWithNewValue(I, I2);
++I2;
- } else if (!I->use_empty()) {
+ } else if (I->use_empty()) {
+ AA.deleteValue(I);
+ } else {
// Otherwise, if we promoted this argument, then all users are load
// instructions, and all loads should be using the new argument that we
// added.
@@ -412,9 +454,10 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
"Load element should sort to front!");
I2->setName(I->getName()+".val");
LI->replaceAllUsesWith(I2);
+ AA.replaceWithNewValue(LI, I2);
LI->getParent()->getInstList().erase(LI);
- DEBUG(std::cerr << "*** Promoted argument '" << I->getName()
- << "' of function '" << F->getName() << "'\n");
+ DEBUG(std::cerr << "*** Promoted load of argument '" << I->getName()
+ << "' in function '" << F->getName() << "'\n");
} else {
GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->use_back());
std::vector<Value*> Operands(GEP->op_begin()+1, GEP->op_end());
@@ -442,20 +485,30 @@ void ArgPromotion::DoPromotion(Function *F, std::vector<Argument*> &Args2Prom) {
while (!GEP->use_empty()) {
LoadInst *L = cast<LoadInst>(GEP->use_back());
L->replaceAllUsesWith(TheArg);
+ AA.replaceWithNewValue(L, TheArg);
L->getParent()->getInstList().erase(L);
}
+ AA.deleteValue(GEP);
GEP->getParent()->getInstList().erase(GEP);
}
}
// If we inserted a new pointer type, it's possible that IT could be
- // promoted too. Also, increment I2 past all of the arguments for this
- // pointer.
+ // promoted too. Also, increment I2 past all of the arguments added for
+ // this promoted pointer.
for (unsigned i = 0, e = ArgIndices.size(); i != e; ++i, ++I2)
if (isa<PointerType>(I2->getType()))
WorkList.insert(NF);
}
+ // Notify the alias analysis implementation that we inserted a new argument.
+ if (ExtraArgHack)
+ AA.copyValue(Constant::getNullValue(Type::IntTy), NF->abegin());
+
+
+ // Tell the alias analysis that the old function is about to disappear.
+ AA.replaceWithNewValue(F, NF);
+
// Now that the old function is dead, delete it.
F->getParent()->getFunctionList().erase(F);
}