ArgumentPromotion.cpp [plain text]
#include "llvm/Transforms/IPO.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <set>
using namespace llvm;
#define DEBUG_TYPE "argpromotion"
STATISTIC(NumArgumentsPromoted , "Number of pointer arguments promoted");
STATISTIC(NumAggregatesPromoted, "Number of aggregate arguments promoted");
STATISTIC(NumByValArgsPromoted , "Number of byval arguments promoted");
STATISTIC(NumArgumentsDead , "Number of dead pointer args eliminated");
namespace {
struct ArgPromotion : public CallGraphSCCPass {
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<AssumptionCacheTracker>();
AU.addRequired<TargetLibraryInfoWrapperPass>();
CallGraphSCCPass::getAnalysisUsage(AU);
}
bool runOnSCC(CallGraphSCC &SCC) override;
static char ID; explicit ArgPromotion(unsigned maxElements = 3)
: CallGraphSCCPass(ID), maxElements(maxElements) {
initializeArgPromotionPass(*PassRegistry::getPassRegistry());
}
typedef std::vector<uint64_t> IndicesVector;
private:
bool isDenselyPacked(Type *type, const DataLayout &DL);
bool canPaddingBeAccessed(Argument *Arg);
CallGraphNode *PromoteArguments(CallGraphNode *CGN);
bool isSafeToPromoteArgument(Argument *Arg, bool isByVal,
AAResults &AAR) const;
CallGraphNode *DoPromotion(Function *F,
SmallPtrSetImpl<Argument*> &ArgsToPromote,
SmallPtrSetImpl<Argument*> &ByValArgsToTransform);
using llvm::Pass::doInitialization;
bool doInitialization(CallGraph &CG) override;
unsigned maxElements;
};
}
char ArgPromotion::ID = 0;
INITIALIZE_PASS_BEGIN(ArgPromotion, "argpromotion",
"Promote 'by reference' arguments to scalars", false, false)
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
INITIALIZE_PASS_END(ArgPromotion, "argpromotion",
"Promote 'by reference' arguments to scalars", false, false)
Pass *llvm::createArgumentPromotionPass(unsigned maxElements) {
return new ArgPromotion(maxElements);
}
bool ArgPromotion::runOnSCC(CallGraphSCC &SCC) {
bool Changed = false, LocalChange;
do { LocalChange = false;
for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
if (CallGraphNode *CGN = PromoteArguments(*I)) {
LocalChange = true;
SCC.ReplaceNode(*I, CGN);
}
}
Changed |= LocalChange; } while (LocalChange);
return Changed;
}
bool ArgPromotion::isDenselyPacked(Type *type, const DataLayout &DL) {
if (!type->isSized())
return false;
if (DL.getTypeSizeInBits(type) != DL.getTypeAllocSizeInBits(type))
return false;
if (!isa<CompositeType>(type))
return true;
if (SequentialType *seqTy = dyn_cast<SequentialType>(type))
return isa<PointerType>(seqTy) ||
isDenselyPacked(seqTy->getElementType(), DL);
StructType *StructTy = cast<StructType>(type);
const StructLayout *Layout = DL.getStructLayout(StructTy);
uint64_t StartPos = 0;
for (unsigned i = 0, E = StructTy->getNumElements(); i < E; ++i) {
Type *ElTy = StructTy->getElementType(i);
if (!isDenselyPacked(ElTy, DL))
return false;
if (StartPos != Layout->getElementOffsetInBits(i))
return false;
StartPos += DL.getTypeAllocSizeInBits(ElTy);
}
return true;
}
bool ArgPromotion::canPaddingBeAccessed(Argument *arg) {
assert(arg->hasByValAttr());
SmallPtrSet<Value *, 16> PtrValues;
PtrValues.insert(arg);
SmallVector<StoreInst *, 16> Stores;
SmallVector<Value *, 16> WorkList;
WorkList.insert(WorkList.end(), arg->user_begin(), arg->user_end());
while (!WorkList.empty()) {
Value *V = WorkList.back();
WorkList.pop_back();
if (isa<GetElementPtrInst>(V) || isa<PHINode>(V)) {
if (PtrValues.insert(V).second)
WorkList.insert(WorkList.end(), V->user_begin(), V->user_end());
} else if (StoreInst *Store = dyn_cast<StoreInst>(V)) {
Stores.push_back(Store);
} else if (!isa<LoadInst>(V)) {
return true;
}
}
for (StoreInst *Store : Stores)
if (PtrValues.count(Store->getValueOperand()))
return true;
return false;
}
CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) {
Function *F = CGN->getFunction();
if (!F || !F->hasLocalLinkage()) return nullptr;
if (F->isVarArg()) return nullptr;
SmallVector<Argument*, 16> PointerArgs;
for (Argument &I : F->args())
if (I.getType()->isPointerTy())
PointerArgs.push_back(&I);
if (PointerArgs.empty()) return nullptr;
bool isSelfRecursive = false;
for (Use &U : F->uses()) {
CallSite CS(U.getUser());
if (CS.getInstruction() == nullptr || !CS.isCallee(&U)) return nullptr;
if (CS.getInstruction()->getParent()->getParent() == F)
isSelfRecursive = true;
}
const DataLayout &DL = F->getParent()->getDataLayout();
BasicAAResult BAR(createLegacyPMBasicAAResult(*this, *F));
AAResults AAR(createLegacyPMAAResults(*this, *F, BAR));
SmallPtrSet<Argument*, 8> ArgsToPromote;
SmallPtrSet<Argument*, 8> ByValArgsToTransform;
for (unsigned i = 0, e = PointerArgs.size(); i != e; ++i) {
Argument *PtrArg = PointerArgs[i];
Type *AgTy = cast<PointerType>(PtrArg->getType())->getElementType();
if (PtrArg->hasStructRetAttr()) {
unsigned ArgNo = PtrArg->getArgNo();
F->setAttributes(
F->getAttributes()
.removeAttribute(F->getContext(), ArgNo + 1, Attribute::StructRet)
.addAttribute(F->getContext(), ArgNo + 1, Attribute::NoAlias));
for (Use &U : F->uses()) {
CallSite CS(U.getUser());
CS.setAttributes(
CS.getAttributes()
.removeAttribute(F->getContext(), ArgNo + 1,
Attribute::StructRet)
.addAttribute(F->getContext(), ArgNo + 1, Attribute::NoAlias));
}
}
bool isSafeToPromote =
PtrArg->hasByValAttr() &&
(isDenselyPacked(AgTy, DL) || !canPaddingBeAccessed(PtrArg));
if (isSafeToPromote) {
if (StructType *STy = dyn_cast<StructType>(AgTy)) {
if (maxElements > 0 && STy->getNumElements() > maxElements) {
DEBUG(dbgs() << "argpromotion disable promoting argument '"
<< PtrArg->getName() << "' because it would require adding more"
<< " than " << maxElements << " arguments to the function.\n");
continue;
}
bool AllSimple = true;
for (const auto *EltTy : STy->elements()) {
if (!EltTy->isSingleValueType()) {
AllSimple = false;
break;
}
}
if (AllSimple) {
ByValArgsToTransform.insert(PtrArg);
continue;
}
}
}
if (isSelfRecursive) {
if (StructType *STy = dyn_cast<StructType>(AgTy)) {
bool RecursiveType = false;
for (const auto *EltTy : STy->elements()) {
if (EltTy == PtrArg->getType()) {
RecursiveType = true;
break;
}
}
if (RecursiveType)
continue;
}
}
if (isSafeToPromoteArgument(PtrArg, PtrArg->hasByValOrInAllocaAttr(), AAR))
ArgsToPromote.insert(PtrArg);
}
if (ArgsToPromote.empty() && ByValArgsToTransform.empty())
return nullptr;
return DoPromotion(F, ArgsToPromote, ByValArgsToTransform);
}
static bool AllCallersPassInValidPointerForArgument(Argument *Arg) {
Function *Callee = Arg->getParent();
const DataLayout &DL = Callee->getParent()->getDataLayout();
unsigned ArgNo = Arg->getArgNo();
for (User *U : Callee->users()) {
CallSite CS(U);
assert(CS && "Should only have direct calls!");
if (!isDereferenceablePointer(CS.getArgument(ArgNo), DL))
return false;
}
return true;
}
static bool IsPrefix(const ArgPromotion::IndicesVector &Prefix,
const ArgPromotion::IndicesVector &Longer) {
if (Prefix.size() > Longer.size())
return false;
return std::equal(Prefix.begin(), Prefix.end(), Longer.begin());
}
static bool PrefixIn(const ArgPromotion::IndicesVector &Indices,
std::set<ArgPromotion::IndicesVector> &Set) {
std::set<ArgPromotion::IndicesVector>::iterator Low;
Low = Set.upper_bound(Indices);
if (Low != Set.begin())
Low--;
return Low != Set.end() && IsPrefix(*Low, Indices);
}
static void MarkIndicesSafe(const ArgPromotion::IndicesVector &ToMark,
std::set<ArgPromotion::IndicesVector> &Safe) {
std::set<ArgPromotion::IndicesVector>::iterator Low;
Low = Safe.upper_bound(ToMark);
if (Low != Safe.begin())
Low--;
if (Low != Safe.end()) {
if (IsPrefix(*Low, ToMark))
return;
++Low;
}
Low = Safe.insert(Low, ToMark);
++Low;
std::set<ArgPromotion::IndicesVector>::iterator End = Safe.end();
while (Low != End && IsPrefix(ToMark, *Low)) {
std::set<ArgPromotion::IndicesVector>::iterator Remove = Low;
++Low;
Safe.erase(Remove);
}
}
bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg,
bool isByValOrInAlloca,
AAResults &AAR) const {
typedef std::set<IndicesVector> GEPIndicesSet;
if (Arg->use_empty())
return true;
GEPIndicesSet SafeToUnconditionallyLoad;
GEPIndicesSet ToPromote;
if (isByValOrInAlloca || AllCallersPassInValidPointerForArgument(Arg))
SafeToUnconditionallyLoad.insert(IndicesVector(1, 0));
BasicBlock &EntryBlock = Arg->getParent()->front();
IndicesVector Indices;
for (Instruction &I : EntryBlock)
if (LoadInst *LI = dyn_cast<LoadInst>(&I)) {
Value *V = LI->getPointerOperand();
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(V)) {
V = GEP->getPointerOperand();
if (V == Arg) {
Indices.reserve(GEP->getNumIndices());
for (User::op_iterator II = GEP->idx_begin(), IE = GEP->idx_end();
II != IE; ++II)
if (ConstantInt *CI = dyn_cast<ConstantInt>(*II))
Indices.push_back(CI->getSExtValue());
else
return false;
MarkIndicesSafe(Indices, SafeToUnconditionallyLoad);
Indices.clear();
}
} else if (V == Arg) {
MarkIndicesSafe(IndicesVector(1, 0), SafeToUnconditionallyLoad);
}
}
SmallVector<LoadInst*, 16> Loads;
IndicesVector Operands;
for (Use &U : Arg->uses()) {
User *UR = U.getUser();
Operands.clear();
if (LoadInst *LI = dyn_cast<LoadInst>(UR)) {
if (!LI->isSimple()) return false;
Loads.push_back(LI);
Operands.push_back(0);
} else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(UR)) {
if (GEP->use_empty()) {
GEP->eraseFromParent();
return isSafeToPromoteArgument(Arg, isByValOrInAlloca, AAR);
}
for (User::op_iterator i = GEP->idx_begin(), e = GEP->idx_end();
i != e; ++i)
if (ConstantInt *C = dyn_cast<ConstantInt>(*i))
Operands.push_back(C->getSExtValue());
else
return false;
for (User *GEPU : GEP->users())
if (LoadInst *LI = dyn_cast<LoadInst>(GEPU)) {
if (!LI->isSimple()) return false;
Loads.push_back(LI);
} else {
return false;
}
} else {
return false; }
if (!PrefixIn(Operands, SafeToUnconditionallyLoad))
return false;
if (ToPromote.find(Operands) == ToPromote.end()) {
if (maxElements > 0 && ToPromote.size() == maxElements) {
DEBUG(dbgs() << "argpromotion not promoting argument '"
<< Arg->getName() << "' because it would require adding more "
<< "than " << maxElements << " arguments to the function.\n");
return false;
}
ToPromote.insert(std::move(Operands));
}
}
if (Loads.empty()) return true;
SmallPtrSet<BasicBlock*, 16> TranspBlocks;
for (unsigned i = 0, e = Loads.size(); i != e; ++i) {
LoadInst *Load = Loads[i];
BasicBlock *BB = Load->getParent();
MemoryLocation Loc = MemoryLocation::get(Load);
if (AAR.canInstructionRangeModRef(BB->front(), *Load, Loc, MRI_Mod))
return false;
for (BasicBlock *P : predecessors(BB)) {
for (BasicBlock *TranspBB : inverse_depth_first_ext(P, TranspBlocks))
if (AAR.canBasicBlockModify(*TranspBB, Loc))
return false;
}
}
return true;
}
CallGraphNode *ArgPromotion::DoPromotion(Function *F,
SmallPtrSetImpl<Argument*> &ArgsToPromote,
SmallPtrSetImpl<Argument*> &ByValArgsToTransform) {
FunctionType *FTy = F->getFunctionType();
std::vector<Type*> Params;
typedef std::set<std::pair<Type *, IndicesVector>> ScalarizeTable;
std::map<Argument*, ScalarizeTable> ScalarizedElements;
std::map<std::pair<Argument*, IndicesVector>, LoadInst*> OriginalLoads;
SmallVector<AttributeSet, 8> AttributesVec;
const AttributeSet &PAL = F->getAttributes();
if (PAL.hasAttributes(AttributeSet::ReturnIndex))
AttributesVec.push_back(AttributeSet::get(F->getContext(),
PAL.getRetAttributes()));
unsigned ArgIndex = 1;
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E;
++I, ++ArgIndex) {
if (ByValArgsToTransform.count(&*I)) {
Type *AgTy = cast<PointerType>(I->getType())->getElementType();
StructType *STy = cast<StructType>(AgTy);
Params.insert(Params.end(), STy->element_begin(), STy->element_end());
++NumByValArgsPromoted;
} else if (!ArgsToPromote.count(&*I)) {
Params.push_back(I->getType());
AttributeSet attrs = PAL.getParamAttributes(ArgIndex);
if (attrs.hasAttributes(ArgIndex)) {
AttrBuilder B(attrs, ArgIndex);
AttributesVec.
push_back(AttributeSet::get(F->getContext(), Params.size(), B));
}
} else if (I->use_empty()) {
++NumArgumentsDead;
} else {
ScalarizeTable &ArgIndices = ScalarizedElements[&*I];
for (User *U : I->users()) {
Instruction *UI = cast<Instruction>(U);
Type *SrcTy;
if (LoadInst *L = dyn_cast<LoadInst>(UI))
SrcTy = L->getType();
else
SrcTy = cast<GetElementPtrInst>(UI)->getSourceElementType();
IndicesVector Indices;
Indices.reserve(UI->getNumOperands() - 1);
for (User::op_iterator II = UI->op_begin() + 1, IE = UI->op_end();
II != IE; ++II)
Indices.push_back(cast<ConstantInt>(*II)->getSExtValue());
if (Indices.size() == 1 && Indices.front() == 0)
Indices.clear();
ArgIndices.insert(std::make_pair(SrcTy, Indices));
LoadInst *OrigLoad;
if (LoadInst *L = dyn_cast<LoadInst>(UI))
OrigLoad = L;
else
OrigLoad = cast<LoadInst>(UI->user_back());
OriginalLoads[std::make_pair(&*I, Indices)] = OrigLoad;
}
for (ScalarizeTable::iterator SI = ArgIndices.begin(),
E = ArgIndices.end(); SI != E; ++SI) {
Params.push_back(GetElementPtrInst::getIndexedType(
cast<PointerType>(I->getType()->getScalarType())->getElementType(),
SI->second));
assert(Params.back());
}
if (ArgIndices.size() == 1 && ArgIndices.begin()->second.empty())
++NumArgumentsPromoted;
else
++NumAggregatesPromoted;
}
}
if (PAL.hasAttributes(AttributeSet::FunctionIndex))
AttributesVec.push_back(AttributeSet::get(FTy->getContext(),
PAL.getFnAttributes()));
Type *RetTy = FTy->getReturnType();
FunctionType *NFTy = FunctionType::get(RetTy, Params, FTy->isVarArg());
Function *NF = Function::Create(NFTy, F->getLinkage(), F->getName());
NF->copyAttributesFrom(F);
NF->setSubprogram(F->getSubprogram());
F->setSubprogram(nullptr);
DEBUG(dbgs() << "ARG PROMOTION: Promoting to:" << *NF << "\n"
<< "From: " << *F);
NF->setAttributes(AttributeSet::get(F->getContext(), AttributesVec));
AttributesVec.clear();
F->getParent()->getFunctionList().insert(F->getIterator(), NF);
NF->takeName(F);
CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph();
CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF);
SmallVector<Value*, 16> Args;
while (!F->use_empty()) {
CallSite CS(F->user_back());
assert(CS.getCalledFunction() == F);
Instruction *Call = CS.getInstruction();
const AttributeSet &CallPAL = CS.getAttributes();
if (CallPAL.hasAttributes(AttributeSet::ReturnIndex))
AttributesVec.push_back(AttributeSet::get(F->getContext(),
CallPAL.getRetAttributes()));
CallSite::arg_iterator AI = CS.arg_begin();
ArgIndex = 1;
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
I != E; ++I, ++AI, ++ArgIndex)
if (!ArgsToPromote.count(&*I) && !ByValArgsToTransform.count(&*I)) {
Args.push_back(*AI);
if (CallPAL.hasAttributes(ArgIndex)) {
AttrBuilder B(CallPAL, ArgIndex);
AttributesVec.
push_back(AttributeSet::get(F->getContext(), Args.size(), B));
}
} else if (ByValArgsToTransform.count(&*I)) {
Type *AgTy = cast<PointerType>(I->getType())->getElementType();
StructType *STy = cast<StructType>(AgTy);
Value *Idxs[2] = {
ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), nullptr };
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i);
Value *Idx = GetElementPtrInst::Create(
STy, *AI, Idxs, (*AI)->getName() + "." + Twine(i), Call);
Args.push_back(new LoadInst(Idx, Idx->getName()+".val", Call));
}
} else if (!I->use_empty()) {
ScalarizeTable &ArgIndices = ScalarizedElements[&*I];
std::vector<Value*> Ops;
for (ScalarizeTable::iterator SI = ArgIndices.begin(),
E = ArgIndices.end(); SI != E; ++SI) {
Value *V = *AI;
LoadInst *OrigLoad = OriginalLoads[std::make_pair(&*I, SI->second)];
if (!SI->second.empty()) {
Ops.reserve(SI->second.size());
Type *ElTy = V->getType();
for (IndicesVector::const_iterator II = SI->second.begin(),
IE = SI->second.end();
II != IE; ++II) {
Type *IdxTy = (ElTy->isStructTy() ?
Type::getInt32Ty(F->getContext()) :
Type::getInt64Ty(F->getContext()));
Ops.push_back(ConstantInt::get(IdxTy, *II));
ElTy = cast<CompositeType>(ElTy)->getTypeAtIndex(*II);
}
V = GetElementPtrInst::Create(SI->first, V, Ops,
V->getName() + ".idx", Call);
Ops.clear();
}
LoadInst *newLoad = new LoadInst(V, V->getName()+".val", Call);
newLoad->setAlignment(OrigLoad->getAlignment());
AAMDNodes AAInfo;
OrigLoad->getAAMetadata(AAInfo);
newLoad->setAAMetadata(AAInfo);
Args.push_back(newLoad);
}
}
for (; AI != CS.arg_end(); ++AI, ++ArgIndex) {
Args.push_back(*AI);
if (CallPAL.hasAttributes(ArgIndex)) {
AttrBuilder B(CallPAL, ArgIndex);
AttributesVec.
push_back(AttributeSet::get(F->getContext(), Args.size(), B));
}
}
if (CallPAL.hasAttributes(AttributeSet::FunctionIndex))
AttributesVec.push_back(AttributeSet::get(Call->getContext(),
CallPAL.getFnAttributes()));
Instruction *New;
if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(),
Args, "", Call);
cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv());
cast<InvokeInst>(New)->setAttributes(AttributeSet::get(II->getContext(),
AttributesVec));
} else {
New = CallInst::Create(NF, Args, "", Call);
cast<CallInst>(New)->setCallingConv(CS.getCallingConv());
cast<CallInst>(New)->setAttributes(AttributeSet::get(New->getContext(),
AttributesVec));
if (cast<CallInst>(Call)->isTailCall())
cast<CallInst>(New)->setTailCall();
}
New->setDebugLoc(Call->getDebugLoc());
Args.clear();
AttributesVec.clear();
CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()];
CalleeNode->replaceCallEdge(CS, CallSite(New), NF_CGN);
if (!Call->use_empty()) {
Call->replaceAllUsesWith(New);
New->takeName(Call);
}
Call->eraseFromParent();
}
NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList());
for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(),
I2 = NF->arg_begin(); I != E; ++I) {
if (!ArgsToPromote.count(&*I) && !ByValArgsToTransform.count(&*I)) {
I->replaceAllUsesWith(&*I2);
I2->takeName(&*I);
++I2;
continue;
}
if (ByValArgsToTransform.count(&*I)) {
Instruction *InsertPt = &NF->begin()->front();
Type *AgTy = cast<PointerType>(I->getType())->getElementType();
Value *TheAlloca = new AllocaInst(AgTy, nullptr, "", InsertPt);
StructType *STy = cast<StructType>(AgTy);
Value *Idxs[2] = {
ConstantInt::get(Type::getInt32Ty(F->getContext()), 0), nullptr };
for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
Idxs[1] = ConstantInt::get(Type::getInt32Ty(F->getContext()), i);
Value *Idx = GetElementPtrInst::Create(
AgTy, TheAlloca, Idxs, TheAlloca->getName() + "." + Twine(i),
InsertPt);
I2->setName(I->getName()+"."+Twine(i));
new StoreInst(&*I2++, Idx, InsertPt);
}
I->replaceAllUsesWith(TheAlloca);
TheAlloca->takeName(&*I);
for (User *U : TheAlloca->users()) {
CallInst *Call = dyn_cast<CallInst>(U);
if (!Call)
continue;
Call->setTailCall(false);
}
continue;
}
if (I->use_empty())
continue;
ScalarizeTable &ArgIndices = ScalarizedElements[&*I];
while (!I->use_empty()) {
if (LoadInst *LI = dyn_cast<LoadInst>(I->user_back())) {
assert(ArgIndices.begin()->second.empty() &&
"Load element should sort to front!");
I2->setName(I->getName()+".val");
LI->replaceAllUsesWith(&*I2);
LI->eraseFromParent();
DEBUG(dbgs() << "*** Promoted load of argument '" << I->getName()
<< "' in function '" << F->getName() << "'\n");
} else {
GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->user_back());
IndicesVector Operands;
Operands.reserve(GEP->getNumIndices());
for (User::op_iterator II = GEP->idx_begin(), IE = GEP->idx_end();
II != IE; ++II)
Operands.push_back(cast<ConstantInt>(*II)->getSExtValue());
if (Operands.size() == 1 && Operands.front() == 0)
Operands.clear();
Function::arg_iterator TheArg = I2;
for (ScalarizeTable::iterator It = ArgIndices.begin();
It->second != Operands; ++It, ++TheArg) {
assert(It != ArgIndices.end() && "GEP not handled??");
}
std::string NewName = I->getName();
for (unsigned i = 0, e = Operands.size(); i != e; ++i) {
NewName += "." + utostr(Operands[i]);
}
NewName += ".val";
TheArg->setName(NewName);
DEBUG(dbgs() << "*** Promoted agg argument '" << TheArg->getName()
<< "' of function '" << NF->getName() << "'\n");
while (!GEP->use_empty()) {
LoadInst *L = cast<LoadInst>(GEP->user_back());
L->replaceAllUsesWith(&*TheArg);
L->eraseFromParent();
}
GEP->eraseFromParent();
}
}
std::advance(I2, ArgIndices.size());
}
NF_CGN->stealCalledFunctionsFrom(CG[F]);
CallGraphNode *CGN = CG[F];
if (CGN->getNumReferences() == 0)
delete CG.removeFunctionFromModule(CGN);
else
F->setLinkage(Function::ExternalLinkage);
return NF_CGN;
}
bool ArgPromotion::doInitialization(CallGraph &CG) {
return CallGraphSCCPass::doInitialization(CG);
}