private:
bool PromoteArguments(CallGraphNode *CGN);
- bool isSafeToPromoteArgument(Argument *Arg) const;
- Function *DoPromotion(Function *F, std::vector<Argument*> &ArgsToPromote);
+ bool isSafeToPromoteArgument(Argument *Arg, bool isByVal) const;
+ Function *DoPromotion(Function *F,
+ SmallPtrSet<Argument*, 8> &ArgsToPromote);
};
char ArgPromotion::ID = 0;
if (!F || !F->hasInternalLinkage()) return false;
// First check: see if there are any pointer arguments! If not, quick exit.
- std::vector<Argument*> PointerArgs;
- for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I)
+ SmallVector<std::pair<Argument*, unsigned>, 16> PointerArgs;
+ unsigned ArgNo = 0;
+ for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
+ I != E; ++I, ++ArgNo)
if (isa<PointerType>(I->getType()))
- PointerArgs.push_back(I);
+ PointerArgs.push_back(std::pair<Argument*, unsigned>(I, ArgNo));
if (PointerArgs.empty()) return false;
// Second check: make sure that all callers are direct callers. We can't
// 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!
+ if (UI.getOperandNo() != 0)
+ return false;
}
- // Check to see which arguments are promotable. If an argument is not
- // promotable, remove it from the PointerArgs vector.
- for (unsigned i = 0; i != PointerArgs.size(); ++i)
- if (!isSafeToPromoteArgument(PointerArgs[i])) {
- std::swap(PointerArgs[i--], PointerArgs.back());
- PointerArgs.pop_back();
- }
-
+ // Check to see which arguments are promotable. If an argument is promotable,
+ // add it to ArgsToPromote.
+ SmallPtrSet<Argument*, 8> ArgsToPromote;
+ for (unsigned i = 0; i != PointerArgs.size(); ++i) {
+ bool isByVal = F->paramHasAttr(PointerArgs[i].second, ParamAttr::ByVal);
+ if (isSafeToPromoteArgument(PointerArgs[i].first, isByVal))
+ ArgsToPromote.insert(PointerArgs[i].first);
+ }
+
// No promotable pointer arguments.
- if (PointerArgs.empty()) return false;
+ if (ArgsToPromote.empty()) return false;
- // Okay, promote all of the arguments and rewrite the callees!
- Function *NewF = DoPromotion(F, PointerArgs);
+ Function *NewF = DoPromotion(F, ArgsToPromote);
// Update the call graph to know that the function has been transformed.
getAnalysis<CallGraph>().changeFunction(F, NewF);
/// 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 {
+bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, bool isByVal) 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.
- bool HasLoadInEntryBlock = false;
+
+ // We can also only promote the load if we can guarantee that it will happen.
+ // Promoting a load causes the load to be unconditionally executed in the
+ // caller, so we can't turn a conditional load into an unconditional load in
+ // general.
+ bool SafeToUnconditionallyLoad = false;
+ if (isByVal) // ByVal arguments are always safe to load from.
+ SafeToUnconditionallyLoad = true;
+
BasicBlock *EntryBlock = Arg->getParent()->begin();
- std::vector<LoadInst*> Loads;
- std::vector<std::vector<ConstantInt*> > GEPIndices;
+ SmallVector<LoadInst*, 16> Loads;
+ std::vector<SmallVector<ConstantInt*, 8> > GEPIndices;
for (Value::use_iterator UI = Arg->use_begin(), E = Arg->use_end();
UI != E; ++UI)
if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
if (LI->isVolatile()) return false; // Don't hack volatile loads
Loads.push_back(LI);
- HasLoadInEntryBlock |= LI->getParent() == EntryBlock;
+
+ // If this load occurs in the entry block, then the pointer is
+ // unconditionally loaded.
+ SafeToUnconditionallyLoad |= LI->getParent() == EntryBlock;
} else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(*UI)) {
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);
+ GEP->eraseFromParent();
+ return isSafeToPromoteArgument(Arg, isByVal);
}
// Ensure that all of the indices are constants.
- std::vector<ConstantInt*> Operands;
+ SmallVector<ConstantInt*, 8> Operands;
for (unsigned i = 1, e = GEP->getNumOperands(); i != e; ++i)
if (ConstantInt *C = dyn_cast<ConstantInt>(GEP->getOperand(i)))
Operands.push_back(C);
if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
if (LI->isVolatile()) return false; // Don't hack volatile loads
Loads.push_back(LI);
- HasLoadInEntryBlock |= LI->getParent() == EntryBlock;
+
+ // If this load occurs in the entry block, then the pointer is
+ // unconditionally loaded.
+ SafeToUnconditionallyLoad |= LI->getParent() == EntryBlock;
} else {
return false;
}
// of the pointer in the entry block of the function) or if we can prove that
// all pointers passed in are always to legal locations (for example, no null
// pointers are passed in, no pointers to free'd memory, etc).
- if (!HasLoadInEntryBlock && !AllCalleesPassInValidPointerForArgument(Arg))
+ if (!SafeToUnconditionallyLoad &&
+ !AllCalleesPassInValidPointerForArgument(Arg))
return false; // Cannot prove that this is safe!!
// Okay, now we know that the argument is only used by load instructions and
/// arguments, and returns the new function. At this point, we know that it's
/// safe to do so.
Function *ArgPromotion::DoPromotion(Function *F,
- std::vector<Argument*> &Args2Prom) {
- std::set<Argument*> ArgsToPromote(Args2Prom.begin(), Args2Prom.end());
+ SmallPtrSet<Argument*, 8> &ArgsToPromote) {
// Start by computing a new prototype for the function, which is the same as
// the old function, but has modified arguments.
// Finally, remove the old call from the program, reducing the use-count of
// F.
- Call->getParent()->getInstList().erase(Call);
+ Call->eraseFromParent();
}
// Since we have now created the new function, splice the body of the old
I2->setName(I->getName()+".val");
LI->replaceAllUsesWith(I2);
AA.replaceWithNewValue(LI, I2);
- LI->getParent()->getInstList().erase(LI);
+ LI->eraseFromParent();
DOUT << "*** Promoted load of argument '" << I->getName()
<< "' in function '" << F->getName() << "'\n";
} else {
LoadInst *L = cast<LoadInst>(GEP->use_back());
L->replaceAllUsesWith(TheArg);
AA.replaceWithNewValue(L, TheArg);
- L->getParent()->getInstList().erase(L);
+ L->eraseFromParent();
}
AA.deleteValue(GEP);
- GEP->getParent()->getInstList().erase(GEP);
+ GEP->eraseFromParent();
}
}
AA.replaceWithNewValue(F, NF);
// Now that the old function is dead, delete it.
- F->getParent()->getFunctionList().erase(F);
+ F->eraseFromParent();
return NF;
}