diff options
Diffstat (limited to 'lib/Transforms/IPO/ArgumentPromotion.cpp')
-rw-r--r-- | lib/Transforms/IPO/ArgumentPromotion.cpp | 170 |
1 files changed, 96 insertions, 74 deletions
diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index 0e05129b52617..0716a3a9cbe90 100644 --- a/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -38,6 +38,7 @@ #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/Loads.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CFG.h" @@ -68,6 +69,7 @@ namespace { void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<AssumptionCacheTracker>(); AU.addRequired<TargetLibraryInfoWrapperPass>(); + getAAResultsAnalysisUsage(AU); CallGraphSCCPass::getAnalysisUsage(AU); } @@ -78,19 +80,8 @@ namespace { initializeArgPromotionPass(*PassRegistry::getPassRegistry()); } - /// A vector used to hold the indices of a single GEP instruction - 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; /// The maximum number of elements to expand, or 0 for unlimited. @@ -98,6 +89,21 @@ namespace { }; } +/// A vector used to hold the indices of a single GEP instruction +typedef std::vector<uint64_t> IndicesVector; + +static CallGraphNode * +PromoteArguments(CallGraphNode *CGN, CallGraph &CG, + function_ref<AAResults &(Function &F)> AARGetter, + unsigned MaxElements); +static bool isDenselyPacked(Type *type, const DataLayout &DL); +static bool canPaddingBeAccessed(Argument *Arg); +static bool isSafeToPromoteArgument(Argument *Arg, bool isByVal, AAResults &AAR, + unsigned MaxElements); +static CallGraphNode * +DoPromotion(Function *F, SmallPtrSetImpl<Argument *> &ArgsToPromote, + SmallPtrSetImpl<Argument *> &ByValArgsToTransform, CallGraph &CG); + char ArgPromotion::ID = 0; INITIALIZE_PASS_BEGIN(ArgPromotion, "argpromotion", "Promote 'by reference' arguments to scalars", false, false) @@ -111,16 +117,19 @@ Pass *llvm::createArgumentPromotionPass(unsigned maxElements) { return new ArgPromotion(maxElements); } -bool ArgPromotion::runOnSCC(CallGraphSCC &SCC) { +static bool runImpl(CallGraphSCC &SCC, CallGraph &CG, + function_ref<AAResults &(Function &F)> AARGetter, + unsigned MaxElements) { 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 (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) { - if (CallGraphNode *CGN = PromoteArguments(*I)) { + for (CallGraphNode *OldNode : SCC) { + if (CallGraphNode *NewNode = + PromoteArguments(OldNode, CG, AARGetter, MaxElements)) { LocalChange = true; - SCC.ReplaceNode(*I, CGN); + SCC.ReplaceNode(OldNode, NewNode); } } Changed |= LocalChange; // Remember that we changed something. @@ -129,8 +138,30 @@ bool ArgPromotion::runOnSCC(CallGraphSCC &SCC) { return Changed; } +bool ArgPromotion::runOnSCC(CallGraphSCC &SCC) { + if (skipSCC(SCC)) + return false; + + // Get the callgraph information that we need to update to reflect our + // changes. + CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); + + // We compute dedicated AA results for each function in the SCC as needed. We + // use a lambda referencing external objects so that they live long enough to + // be queried, but we re-use them each time. + Optional<BasicAAResult> BAR; + Optional<AAResults> AAR; + auto AARGetter = [&](Function &F) -> AAResults & { + BAR.emplace(createLegacyPMBasicAAResult(*this, F)); + AAR.emplace(createLegacyPMAAResults(*this, F, *BAR)); + return *AAR; + }; + + return runImpl(SCC, CG, AARGetter, maxElements); +} + /// \brief Checks if a type could have padding bytes. -bool ArgPromotion::isDenselyPacked(Type *type, const DataLayout &DL) { +static bool isDenselyPacked(Type *type, const DataLayout &DL) { // There is no size information, so be conservative. if (!type->isSized()) @@ -166,7 +197,7 @@ bool ArgPromotion::isDenselyPacked(Type *type, const DataLayout &DL) { } /// \brief Checks if the padding bytes of an argument could be accessed. -bool ArgPromotion::canPaddingBeAccessed(Argument *arg) { +static bool canPaddingBeAccessed(Argument *arg) { assert(arg->hasByValAttr()); @@ -207,7 +238,10 @@ bool ArgPromotion::canPaddingBeAccessed(Argument *arg) { /// example, all callers are direct). If safe to promote some arguments, it /// calls the DoPromotion method. /// -CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) { +static CallGraphNode * +PromoteArguments(CallGraphNode *CGN, CallGraph &CG, + function_ref<AAResults &(Function &F)> AARGetter, + unsigned MaxElements) { Function *F = CGN->getFunction(); // Make sure that it is local to this module. @@ -242,20 +276,13 @@ CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) { const DataLayout &DL = F->getParent()->getDataLayout(); - // We need to manually construct BasicAA directly in order to disable its use - // of other function analyses. - BasicAAResult BAR(createLegacyPMBasicAAResult(*this, *F)); - - // Construct our own AA results for this function. We do this manually to - // work around the limitations of the legacy pass manager. - AAResults AAR(createLegacyPMAAResults(*this, *F, BAR)); + AAResults &AAR = AARGetter(*F); // Check to see which arguments are promotable. If an argument is promotable, // add it to ArgsToPromote. SmallPtrSet<Argument*, 8> ArgsToPromote; SmallPtrSet<Argument*, 8> ByValArgsToTransform; - for (unsigned i = 0, e = PointerArgs.size(); i != e; ++i) { - Argument *PtrArg = PointerArgs[i]; + for (Argument *PtrArg : PointerArgs) { Type *AgTy = cast<PointerType>(PtrArg->getType())->getElementType(); // Replace sret attribute with noalias. This reduces register pressure by @@ -285,10 +312,10 @@ CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) { (isDenselyPacked(AgTy, DL) || !canPaddingBeAccessed(PtrArg)); if (isSafeToPromote) { if (StructType *STy = dyn_cast<StructType>(AgTy)) { - if (maxElements > 0 && STy->getNumElements() > maxElements) { + 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"); + << " than " << MaxElements << " arguments to the function.\n"); continue; } @@ -302,7 +329,7 @@ CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) { } // Safe to transform, don't even bother trying to "promote" it. - // Passing the elements as a scalar will allow scalarrepl to hack on + // Passing the elements as a scalar will allow sroa to hack on // the new alloca we introduce. if (AllSimple) { ByValArgsToTransform.insert(PtrArg); @@ -328,7 +355,8 @@ CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) { } // Otherwise, see if we can promote the pointer to its value. - if (isSafeToPromoteArgument(PtrArg, PtrArg->hasByValOrInAllocaAttr(), AAR)) + if (isSafeToPromoteArgument(PtrArg, PtrArg->hasByValOrInAllocaAttr(), AAR, + MaxElements)) ArgsToPromote.insert(PtrArg); } @@ -336,7 +364,7 @@ CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) { if (ArgsToPromote.empty() && ByValArgsToTransform.empty()) return nullptr; - return DoPromotion(F, ArgsToPromote, ByValArgsToTransform); + return DoPromotion(F, ArgsToPromote, ByValArgsToTransform, CG); } /// AllCallersPassInValidPointerForArgument - Return true if we can prove that @@ -364,8 +392,7 @@ static bool AllCallersPassInValidPointerForArgument(Argument *Arg) { /// elements in Prefix is the same as the corresponding elements in Longer. /// /// This means it also returns true when Prefix and Longer are equal! -static bool IsPrefix(const ArgPromotion::IndicesVector &Prefix, - const ArgPromotion::IndicesVector &Longer) { +static bool IsPrefix(const IndicesVector &Prefix, const IndicesVector &Longer) { if (Prefix.size() > Longer.size()) return false; return std::equal(Prefix.begin(), Prefix.end(), Longer.begin()); @@ -373,9 +400,9 @@ static bool IsPrefix(const ArgPromotion::IndicesVector &Prefix, /// Checks if Indices, or a prefix of Indices, is in Set. -static bool PrefixIn(const ArgPromotion::IndicesVector &Indices, - std::set<ArgPromotion::IndicesVector> &Set) { - std::set<ArgPromotion::IndicesVector>::iterator Low; +static bool PrefixIn(const IndicesVector &Indices, + std::set<IndicesVector> &Set) { + std::set<IndicesVector>::iterator Low; Low = Set.upper_bound(Indices); if (Low != Set.begin()) Low--; @@ -392,9 +419,9 @@ static bool PrefixIn(const ArgPromotion::IndicesVector &Indices, /// is already a prefix of Indices in Safe, Indices are implicitely marked safe /// already. Furthermore, any indices that Indices is itself a prefix of, are /// removed from Safe (since they are implicitely safe because of Indices now). -static void MarkIndicesSafe(const ArgPromotion::IndicesVector &ToMark, - std::set<ArgPromotion::IndicesVector> &Safe) { - std::set<ArgPromotion::IndicesVector>::iterator Low; +static void MarkIndicesSafe(const IndicesVector &ToMark, + std::set<IndicesVector> &Safe) { + std::set<IndicesVector>::iterator Low; Low = Safe.upper_bound(ToMark); // Guard against the case where Safe is empty if (Low != Safe.begin()) @@ -415,9 +442,9 @@ static void MarkIndicesSafe(const ArgPromotion::IndicesVector &ToMark, Low = Safe.insert(Low, ToMark); ++Low; // If there we're a prefix of longer index list(s), remove those - std::set<ArgPromotion::IndicesVector>::iterator End = Safe.end(); + std::set<IndicesVector>::iterator End = Safe.end(); while (Low != End && IsPrefix(ToMark, *Low)) { - std::set<ArgPromotion::IndicesVector>::iterator Remove = Low; + std::set<IndicesVector>::iterator Remove = Low; ++Low; Safe.erase(Remove); } @@ -428,9 +455,8 @@ static void MarkIndicesSafe(const ArgPromotion::IndicesVector &ToMark, /// 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, - bool isByValOrInAlloca, - AAResults &AAR) const { +static bool isSafeToPromoteArgument(Argument *Arg, bool isByValOrInAlloca, + AAResults &AAR, unsigned MaxElements) { typedef std::set<IndicesVector> GEPIndicesSet; // Quick exit for unused arguments @@ -518,7 +544,8 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, // TODO: This runs the above loop over and over again for dead GEPs // Couldn't we just do increment the UI iterator earlier and erase the // use? - return isSafeToPromoteArgument(Arg, isByValOrInAlloca, AAR); + return isSafeToPromoteArgument(Arg, isByValOrInAlloca, AAR, + MaxElements); } // Ensure that all of the indices are constants. @@ -552,10 +579,10 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, // to make sure that we aren't promoting too many elements. If so, nothing // to do. if (ToPromote.find(Operands) == ToPromote.end()) { - if (maxElements > 0 && ToPromote.size() == maxElements) { + 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"); + << "than " << MaxElements << " arguments to the function.\n"); // We limit aggregate promotion to only promoting up to a fixed number // of elements of the aggregate. return false; @@ -575,10 +602,9 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, // blocks we know to be transparent to the load. SmallPtrSet<BasicBlock*, 16> TranspBlocks; - for (unsigned i = 0, e = Loads.size(); i != e; ++i) { + for (LoadInst *Load : Loads) { // Check to see if the load is invalidated from the start of the block to // the load itself. - LoadInst *Load = Loads[i]; BasicBlock *BB = Load->getParent(); MemoryLocation Loc = MemoryLocation::get(Load); @@ -604,9 +630,9 @@ bool ArgPromotion::isSafeToPromoteArgument(Argument *Arg, /// 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. -CallGraphNode *ArgPromotion::DoPromotion(Function *F, - SmallPtrSetImpl<Argument*> &ArgsToPromote, - SmallPtrSetImpl<Argument*> &ByValArgsToTransform) { +static CallGraphNode * +DoPromotion(Function *F, SmallPtrSetImpl<Argument *> &ArgsToPromote, + SmallPtrSetImpl<Argument *> &ByValArgsToTransform, CallGraph &CG) { // Start by computing a new prototype for the function, which is the same as // the old function, but has modified arguments. @@ -700,12 +726,11 @@ CallGraphNode *ArgPromotion::DoPromotion(Function *F, } // Add a parameter to the function for each element passed in. - for (ScalarizeTable::iterator SI = ArgIndices.begin(), - E = ArgIndices.end(); SI != E; ++SI) { + for (const auto &ArgIndex : ArgIndices) { // not allowed to dereference ->begin() if size() is 0 Params.push_back(GetElementPtrInst::getIndexedType( cast<PointerType>(I->getType()->getScalarType())->getElementType(), - SI->second)); + ArgIndex.second)); assert(Params.back()); } @@ -745,10 +770,6 @@ CallGraphNode *ArgPromotion::DoPromotion(Function *F, F->getParent()->getFunctionList().insert(F->getIterator(), NF); NF->takeName(F); - // Get the callgraph information that we need to update to reflect our - // changes. - CallGraph &CG = getAnalysis<CallGraphWrapperPass>().getCallGraph(); - // Get a new callgraph node for NF. CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF); @@ -800,27 +821,25 @@ CallGraphNode *ArgPromotion::DoPromotion(Function *F, // Store the Value* version of the indices in here, but declare it now // for reuse. std::vector<Value*> Ops; - for (ScalarizeTable::iterator SI = ArgIndices.begin(), - E = ArgIndices.end(); SI != E; ++SI) { + for (const auto &ArgIndex : ArgIndices) { Value *V = *AI; - LoadInst *OrigLoad = OriginalLoads[std::make_pair(&*I, SI->second)]; - if (!SI->second.empty()) { - Ops.reserve(SI->second.size()); + LoadInst *OrigLoad = + OriginalLoads[std::make_pair(&*I, ArgIndex.second)]; + if (!ArgIndex.second.empty()) { + Ops.reserve(ArgIndex.second.size()); Type *ElTy = V->getType(); - for (IndicesVector::const_iterator II = SI->second.begin(), - IE = SI->second.end(); - II != IE; ++II) { + for (unsigned long II : ArgIndex.second) { // Use i32 to index structs, and i64 for others (pointers/arrays). // This satisfies GEP constraints. Type *IdxTy = (ElTy->isStructTy() ? Type::getInt32Ty(F->getContext()) : Type::getInt64Ty(F->getContext())); - Ops.push_back(ConstantInt::get(IdxTy, *II)); + Ops.push_back(ConstantInt::get(IdxTy, II)); // Keep track of the type we're currently indexing. - ElTy = cast<CompositeType>(ElTy)->getTypeAtIndex(*II); + ElTy = cast<CompositeType>(ElTy)->getTypeAtIndex(II); } // And create a GEP to extract those indices. - V = GetElementPtrInst::Create(SI->first, V, Ops, + V = GetElementPtrInst::Create(ArgIndex.first, V, Ops, V->getName() + ".idx", Call); Ops.clear(); } @@ -852,15 +871,18 @@ CallGraphNode *ArgPromotion::DoPromotion(Function *F, AttributesVec.push_back(AttributeSet::get(Call->getContext(), CallPAL.getFnAttributes())); + SmallVector<OperandBundleDef, 1> OpBundles; + CS.getOperandBundlesAsDefs(OpBundles); + Instruction *New; if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) { New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), - Args, "", Call); + Args, OpBundles, "", Call); cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv()); cast<InvokeInst>(New)->setAttributes(AttributeSet::get(II->getContext(), AttributesVec)); } else { - New = CallInst::Create(NF, Args, "", Call); + New = CallInst::Create(NF, Args, OpBundles, "", Call); cast<CallInst>(New)->setCallingConv(CS.getCallingConv()); cast<CallInst>(New)->setAttributes(AttributeSet::get(New->getContext(), AttributesVec)); |