diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index 438f48b8e1e..79d19ad309f 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 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().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 &Args2Prom) { std::set ArgsToPromote(Args2Prom.begin(), Args2Prom.end()); @@ -283,10 +298,17 @@ void ArgPromotion::DoPromotion(Function *F, std::vector &Args2Prom) { // std::map > > 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, 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 > &ArgIndices = ScalarizedElements[I]; @@ -294,8 +316,14 @@ void ArgPromotion::DoPromotion(Function *F, std::vector &Args2Prom) { ++UI) { Instruction *User = cast(*UI); assert(isa(User) || isa(User)); - ArgIndices.insert(std::vector(User->op_begin()+1, - User->op_end())); + std::vector Indices(User->op_begin()+1, User->op_end()); + ArgIndices.insert(Indices); + LoadInst *OrigLoad; + if (LoadInst *L = dyn_cast(User)) + OrigLoad = L; + else + OrigLoad = cast(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 &Args2Prom) { ++NumArgumentsPromoted; else ++NumAggregatesPromoted; - } else { - ++NumArgumentsDead; } const Type *RetTy = FTy->getReturnType(); @@ -325,7 +351,11 @@ void ArgPromotion::DoPromotion(Function *F, std::vector &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(); + // 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 &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 > &ArgIndices = ScalarizedElements[I]; for (std::set >::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 &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 &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 &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(I->use_back()); std::vector Operands(GEP->op_begin()+1, GEP->op_end()); @@ -442,20 +485,30 @@ void ArgPromotion::DoPromotion(Function *F, std::vector &Args2Prom) { while (!GEP->use_empty()) { LoadInst *L = cast(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(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); }