10b57cec5SDimitry Andric //===- FunctionAttrs.cpp - Pass which marks functions attributes ----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements interprocedural passes which walk the
110b57cec5SDimitry Andric /// call-graph deducing and/or propagating function attributes.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "llvm/Transforms/IPO/FunctionAttrs.h"
16e8d8bef9SDimitry Andric #include "llvm/ADT/ArrayRef.h"
17349cc55cSDimitry Andric #include "llvm/ADT/DenseMap.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SCCIterator.h"
190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SetVector.h"
210b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
22349cc55cSDimitry Andric #include "llvm/ADT/SmallSet.h"
230b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
240b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
250b57cec5SDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
260b57cec5SDimitry Andric #include "llvm/Analysis/BasicAliasAnalysis.h"
27e8d8bef9SDimitry Andric #include "llvm/Analysis/CFG.h"
280b57cec5SDimitry Andric #include "llvm/Analysis/CGSCCPassManager.h"
290b57cec5SDimitry Andric #include "llvm/Analysis/CallGraph.h"
300b57cec5SDimitry Andric #include "llvm/Analysis/CallGraphSCCPass.h"
310b57cec5SDimitry Andric #include "llvm/Analysis/CaptureTracking.h"
320b57cec5SDimitry Andric #include "llvm/Analysis/LazyCallGraph.h"
330b57cec5SDimitry Andric #include "llvm/Analysis/MemoryLocation.h"
340b57cec5SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
350b57cec5SDimitry Andric #include "llvm/IR/Argument.h"
360b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
370b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
380b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
390b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
400b57cec5SDimitry Andric #include "llvm/IR/Function.h"
410b57cec5SDimitry Andric #include "llvm/IR/InstIterator.h"
420b57cec5SDimitry Andric #include "llvm/IR/InstrTypes.h"
430b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
440b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
450b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
460b57cec5SDimitry Andric #include "llvm/IR/Metadata.h"
4781ad6265SDimitry Andric #include "llvm/IR/ModuleSummaryIndex.h"
480b57cec5SDimitry Andric #include "llvm/IR/PassManager.h"
490b57cec5SDimitry Andric #include "llvm/IR/Type.h"
500b57cec5SDimitry Andric #include "llvm/IR/Use.h"
510b57cec5SDimitry Andric #include "llvm/IR/User.h"
520b57cec5SDimitry Andric #include "llvm/IR/Value.h"
530b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
540b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
550b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
560b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
570b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
580b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
590b57cec5SDimitry Andric #include "llvm/Transforms/IPO.h"
60fe6060f1SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
610b57cec5SDimitry Andric #include <cassert>
620b57cec5SDimitry Andric #include <iterator>
630b57cec5SDimitry Andric #include <map>
64bdd1243dSDimitry Andric #include <optional>
650b57cec5SDimitry Andric #include <vector>
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric using namespace llvm;
680b57cec5SDimitry Andric
69e8d8bef9SDimitry Andric #define DEBUG_TYPE "function-attrs"
700b57cec5SDimitry Andric
71bdd1243dSDimitry Andric STATISTIC(NumMemoryAttr, "Number of functions with improved memory attribute");
720b57cec5SDimitry Andric STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
730b57cec5SDimitry Andric STATISTIC(NumReturned, "Number of arguments marked returned");
740b57cec5SDimitry Andric STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
750b57cec5SDimitry Andric STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");
760eae32dcSDimitry Andric STATISTIC(NumWriteOnlyArg, "Number of arguments marked writeonly");
770b57cec5SDimitry Andric STATISTIC(NumNoAlias, "Number of function returns marked noalias");
780b57cec5SDimitry Andric STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull");
79647cbc5dSDimitry Andric STATISTIC(NumNoUndefReturn, "Number of function returns marked noundef");
800b57cec5SDimitry Andric STATISTIC(NumNoRecurse, "Number of functions marked as norecurse");
810b57cec5SDimitry Andric STATISTIC(NumNoUnwind, "Number of functions marked as nounwind");
820b57cec5SDimitry Andric STATISTIC(NumNoFree, "Number of functions marked as nofree");
83e8d8bef9SDimitry Andric STATISTIC(NumWillReturn, "Number of functions marked as willreturn");
84fe6060f1SDimitry Andric STATISTIC(NumNoSync, "Number of functions marked as nosync");
850b57cec5SDimitry Andric
86349cc55cSDimitry Andric STATISTIC(NumThinLinkNoRecurse,
87349cc55cSDimitry Andric "Number of functions marked as norecurse during thinlink");
88349cc55cSDimitry Andric STATISTIC(NumThinLinkNoUnwind,
89349cc55cSDimitry Andric "Number of functions marked as nounwind during thinlink");
90349cc55cSDimitry Andric
910b57cec5SDimitry Andric static cl::opt<bool> EnableNonnullArgPropagation(
928bcb0991SDimitry Andric "enable-nonnull-arg-prop", cl::init(true), cl::Hidden,
930b57cec5SDimitry Andric cl::desc("Try to propagate nonnull argument attributes from callsites to "
940b57cec5SDimitry Andric "caller functions."));
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric static cl::opt<bool> DisableNoUnwindInference(
970b57cec5SDimitry Andric "disable-nounwind-inference", cl::Hidden,
980b57cec5SDimitry Andric cl::desc("Stop inferring nounwind attribute during function-attrs pass"));
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric static cl::opt<bool> DisableNoFreeInference(
1010b57cec5SDimitry Andric "disable-nofree-inference", cl::Hidden,
1020b57cec5SDimitry Andric cl::desc("Stop inferring nofree attribute during function-attrs pass"));
1030b57cec5SDimitry Andric
104349cc55cSDimitry Andric static cl::opt<bool> DisableThinLTOPropagation(
105349cc55cSDimitry Andric "disable-thinlto-funcattrs", cl::init(true), cl::Hidden,
106349cc55cSDimitry Andric cl::desc("Don't propagate function-attrs in thinLTO"));
107349cc55cSDimitry Andric
1080b57cec5SDimitry Andric namespace {
1090b57cec5SDimitry Andric
1100b57cec5SDimitry Andric using SCCNodeSet = SmallSetVector<Function *, 8>;
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric } // end anonymous namespace
1130b57cec5SDimitry Andric
addLocAccess(MemoryEffects & ME,const MemoryLocation & Loc,ModRefInfo MR,AAResults & AAR)1145f757f3fSDimitry Andric static void addLocAccess(MemoryEffects &ME, const MemoryLocation &Loc,
1155f757f3fSDimitry Andric ModRefInfo MR, AAResults &AAR) {
116bdd1243dSDimitry Andric // Ignore accesses to known-invariant or local memory.
117bdd1243dSDimitry Andric MR &= AAR.getModRefInfoMask(Loc, /*IgnoreLocal=*/true);
118bdd1243dSDimitry Andric if (isNoModRef(MR))
119bdd1243dSDimitry Andric return;
120bdd1243dSDimitry Andric
121bdd1243dSDimitry Andric const Value *UO = getUnderlyingObject(Loc.Ptr);
122bdd1243dSDimitry Andric assert(!isa<AllocaInst>(UO) &&
123bdd1243dSDimitry Andric "Should have been handled by getModRefInfoMask()");
124bdd1243dSDimitry Andric if (isa<Argument>(UO)) {
125bdd1243dSDimitry Andric ME |= MemoryEffects::argMemOnly(MR);
126bdd1243dSDimitry Andric return;
127bdd1243dSDimitry Andric }
128bdd1243dSDimitry Andric
129bdd1243dSDimitry Andric // If it's not an identified object, it might be an argument.
130bdd1243dSDimitry Andric if (!isIdentifiedObject(UO))
131bdd1243dSDimitry Andric ME |= MemoryEffects::argMemOnly(MR);
13206c3fb27SDimitry Andric ME |= MemoryEffects(IRMemLocation::Other, MR);
1335f757f3fSDimitry Andric }
1345f757f3fSDimitry Andric
addArgLocs(MemoryEffects & ME,const CallBase * Call,ModRefInfo ArgMR,AAResults & AAR)1355f757f3fSDimitry Andric static void addArgLocs(MemoryEffects &ME, const CallBase *Call,
1365f757f3fSDimitry Andric ModRefInfo ArgMR, AAResults &AAR) {
1375f757f3fSDimitry Andric for (const Value *Arg : Call->args()) {
1385f757f3fSDimitry Andric if (!Arg->getType()->isPtrOrPtrVectorTy())
1395f757f3fSDimitry Andric continue;
1405f757f3fSDimitry Andric
1415f757f3fSDimitry Andric addLocAccess(ME,
1425f757f3fSDimitry Andric MemoryLocation::getBeforeOrAfter(Arg, Call->getAAMetadata()),
1435f757f3fSDimitry Andric ArgMR, AAR);
1445f757f3fSDimitry Andric }
1455f757f3fSDimitry Andric }
1465f757f3fSDimitry Andric
1475f757f3fSDimitry Andric /// Returns the memory access attribute for function F using AAR for AA results,
1485f757f3fSDimitry Andric /// where SCCNodes is the current SCC.
1495f757f3fSDimitry Andric ///
1505f757f3fSDimitry Andric /// If ThisBody is true, this function may examine the function body and will
1515f757f3fSDimitry Andric /// return a result pertaining to this copy of the function. If it is false, the
1525f757f3fSDimitry Andric /// result will be based only on AA results for the function declaration; it
1535f757f3fSDimitry Andric /// will be assumed that some other (perhaps less optimized) version of the
1545f757f3fSDimitry Andric /// function may be selected at link time.
1555f757f3fSDimitry Andric ///
1565f757f3fSDimitry Andric /// The return value is split into two parts: Memory effects that always apply,
1575f757f3fSDimitry Andric /// and additional memory effects that apply if any of the functions in the SCC
1585f757f3fSDimitry Andric /// can access argmem.
1595f757f3fSDimitry Andric static std::pair<MemoryEffects, MemoryEffects>
checkFunctionMemoryAccess(Function & F,bool ThisBody,AAResults & AAR,const SCCNodeSet & SCCNodes)1605f757f3fSDimitry Andric checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR,
1615f757f3fSDimitry Andric const SCCNodeSet &SCCNodes) {
1625f757f3fSDimitry Andric MemoryEffects OrigME = AAR.getMemoryEffects(&F);
1635f757f3fSDimitry Andric if (OrigME.doesNotAccessMemory())
1645f757f3fSDimitry Andric // Already perfect!
1655f757f3fSDimitry Andric return {OrigME, MemoryEffects::none()};
1665f757f3fSDimitry Andric
1675f757f3fSDimitry Andric if (!ThisBody)
1685f757f3fSDimitry Andric return {OrigME, MemoryEffects::none()};
1695f757f3fSDimitry Andric
1705f757f3fSDimitry Andric MemoryEffects ME = MemoryEffects::none();
1715f757f3fSDimitry Andric // Additional locations accessed if the SCC accesses argmem.
1725f757f3fSDimitry Andric MemoryEffects RecursiveArgME = MemoryEffects::none();
1735f757f3fSDimitry Andric
1745f757f3fSDimitry Andric // Inalloca and preallocated arguments are always clobbered by the call.
1755f757f3fSDimitry Andric if (F.getAttributes().hasAttrSomewhere(Attribute::InAlloca) ||
1765f757f3fSDimitry Andric F.getAttributes().hasAttrSomewhere(Attribute::Preallocated))
1775f757f3fSDimitry Andric ME |= MemoryEffects::argMemOnly(ModRefInfo::ModRef);
1785f757f3fSDimitry Andric
179bdd1243dSDimitry Andric // Scan the function body for instructions that may read or write memory.
180349cc55cSDimitry Andric for (Instruction &I : instructions(F)) {
1810b57cec5SDimitry Andric // Some instructions can be ignored even if they read or write memory.
1820b57cec5SDimitry Andric // Detect these now, skipping to the next instruction if one is found.
183349cc55cSDimitry Andric if (auto *Call = dyn_cast<CallBase>(&I)) {
1845f757f3fSDimitry Andric // We can optimistically ignore calls to functions in the same SCC, with
1855f757f3fSDimitry Andric // two caveats:
1865f757f3fSDimitry Andric // * Calls with operand bundles may have additional effects.
1875f757f3fSDimitry Andric // * Argument memory accesses may imply additional effects depending on
1885f757f3fSDimitry Andric // what the argument location is.
1890b57cec5SDimitry Andric if (!Call->hasOperandBundles() && Call->getCalledFunction() &&
1905f757f3fSDimitry Andric SCCNodes.count(Call->getCalledFunction())) {
1915f757f3fSDimitry Andric // Keep track of which additional locations are accessed if the SCC
1925f757f3fSDimitry Andric // turns out to access argmem.
1935f757f3fSDimitry Andric addArgLocs(RecursiveArgME, Call, ModRefInfo::ModRef, AAR);
1940b57cec5SDimitry Andric continue;
1955f757f3fSDimitry Andric }
1965f757f3fSDimitry Andric
197bdd1243dSDimitry Andric MemoryEffects CallME = AAR.getMemoryEffects(Call);
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric // If the call doesn't access memory, we're done.
200bdd1243dSDimitry Andric if (CallME.doesNotAccessMemory())
2010b57cec5SDimitry Andric continue;
2020b57cec5SDimitry Andric
203d409305fSDimitry Andric // A pseudo probe call shouldn't change any function attribute since it
204d409305fSDimitry Andric // doesn't translate to a real instruction. It comes with a memory access
205d409305fSDimitry Andric // tag to prevent itself being removed by optimizations and not block
206d409305fSDimitry Andric // other instructions being optimized.
207d409305fSDimitry Andric if (isa<PseudoProbeInst>(I))
208d409305fSDimitry Andric continue;
209d409305fSDimitry Andric
21006c3fb27SDimitry Andric ME |= CallME.getWithoutLoc(IRMemLocation::ArgMem);
211bdd1243dSDimitry Andric
212bdd1243dSDimitry Andric // If the call accesses captured memory (currently part of "other") and
213bdd1243dSDimitry Andric // an argument is captured (currently not tracked), then it may also
214bdd1243dSDimitry Andric // access argument memory.
21506c3fb27SDimitry Andric ModRefInfo OtherMR = CallME.getModRef(IRMemLocation::Other);
216bdd1243dSDimitry Andric ME |= MemoryEffects::argMemOnly(OtherMR);
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric // Check whether all pointer arguments point to local memory, and
2190b57cec5SDimitry Andric // ignore calls that only access local memory.
22006c3fb27SDimitry Andric ModRefInfo ArgMR = CallME.getModRef(IRMemLocation::ArgMem);
2215f757f3fSDimitry Andric if (ArgMR != ModRefInfo::NoModRef)
2225f757f3fSDimitry Andric addArgLocs(ME, Call, ArgMR, AAR);
2230b57cec5SDimitry Andric continue;
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric
226bdd1243dSDimitry Andric ModRefInfo MR = ModRefInfo::NoModRef;
227bdd1243dSDimitry Andric if (I.mayWriteToMemory())
228bdd1243dSDimitry Andric MR |= ModRefInfo::Mod;
229bdd1243dSDimitry Andric if (I.mayReadFromMemory())
230bdd1243dSDimitry Andric MR |= ModRefInfo::Ref;
231bdd1243dSDimitry Andric if (MR == ModRefInfo::NoModRef)
232bdd1243dSDimitry Andric continue;
2330b57cec5SDimitry Andric
234bdd1243dSDimitry Andric std::optional<MemoryLocation> Loc = MemoryLocation::getOrNone(&I);
235bdd1243dSDimitry Andric if (!Loc) {
236bdd1243dSDimitry Andric // If no location is known, conservatively assume anything can be
237bdd1243dSDimitry Andric // accessed.
238bdd1243dSDimitry Andric ME |= MemoryEffects(MR);
239bdd1243dSDimitry Andric continue;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
242bdd1243dSDimitry Andric // Volatile operations may access inaccessible memory.
243bdd1243dSDimitry Andric if (I.isVolatile())
244bdd1243dSDimitry Andric ME |= MemoryEffects::inaccessibleMemOnly(MR);
24581ad6265SDimitry Andric
2465f757f3fSDimitry Andric addLocAccess(ME, *Loc, MR, AAR);
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric
2495f757f3fSDimitry Andric return {OrigME & ME, RecursiveArgME};
250bdd1243dSDimitry Andric }
251bdd1243dSDimitry Andric
computeFunctionBodyMemoryAccess(Function & F,AAResults & AAR)252bdd1243dSDimitry Andric MemoryEffects llvm::computeFunctionBodyMemoryAccess(Function &F,
2530b57cec5SDimitry Andric AAResults &AAR) {
2545f757f3fSDimitry Andric return checkFunctionMemoryAccess(F, /*ThisBody=*/true, AAR, {}).first;
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric
25781ad6265SDimitry Andric /// Deduce readonly/readnone/writeonly attributes for the SCC.
2580b57cec5SDimitry Andric template <typename AARGetterT>
addMemoryAttrs(const SCCNodeSet & SCCNodes,AARGetterT && AARGetter,SmallSet<Function *,8> & Changed)25981ad6265SDimitry Andric static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
260349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
261bdd1243dSDimitry Andric MemoryEffects ME = MemoryEffects::none();
2625f757f3fSDimitry Andric MemoryEffects RecursiveArgME = MemoryEffects::none();
2630b57cec5SDimitry Andric for (Function *F : SCCNodes) {
2640b57cec5SDimitry Andric // Call the callable parameter to look up AA results for this function.
2650b57cec5SDimitry Andric AAResults &AAR = AARGetter(*F);
2660b57cec5SDimitry Andric // Non-exact function definitions may not be selected at link time, and an
2670b57cec5SDimitry Andric // alternative version that writes to memory may be selected. See the
2680b57cec5SDimitry Andric // comment on GlobalValue::isDefinitionExact for more details.
2695f757f3fSDimitry Andric auto [FnME, FnRecursiveArgME] =
2705f757f3fSDimitry Andric checkFunctionMemoryAccess(*F, F->hasExactDefinition(), AAR, SCCNodes);
2715f757f3fSDimitry Andric ME |= FnME;
2725f757f3fSDimitry Andric RecursiveArgME |= FnRecursiveArgME;
273bdd1243dSDimitry Andric // Reached bottom of the lattice, we will not be able to improve the result.
274bdd1243dSDimitry Andric if (ME == MemoryEffects::unknown())
275349cc55cSDimitry Andric return;
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric
2785f757f3fSDimitry Andric // If the SCC accesses argmem, add recursive accesses resulting from that.
2795f757f3fSDimitry Andric ModRefInfo ArgMR = ME.getModRef(IRMemLocation::ArgMem);
2805f757f3fSDimitry Andric if (ArgMR != ModRefInfo::NoModRef)
2815f757f3fSDimitry Andric ME |= RecursiveArgME & MemoryEffects(ArgMR);
2825f757f3fSDimitry Andric
2830b57cec5SDimitry Andric for (Function *F : SCCNodes) {
284bdd1243dSDimitry Andric MemoryEffects OldME = F->getMemoryEffects();
285bdd1243dSDimitry Andric MemoryEffects NewME = ME & OldME;
286bdd1243dSDimitry Andric if (NewME != OldME) {
287bdd1243dSDimitry Andric ++NumMemoryAttr;
288bdd1243dSDimitry Andric F->setMemoryEffects(NewME);
2895f757f3fSDimitry Andric // Remove conflicting writable attributes.
2905f757f3fSDimitry Andric if (!isModSet(NewME.getModRef(IRMemLocation::ArgMem)))
2915f757f3fSDimitry Andric for (Argument &A : F->args())
2925f757f3fSDimitry Andric A.removeAttr(Attribute::Writable);
29381ad6265SDimitry Andric Changed.insert(F);
29481ad6265SDimitry Andric }
2950b57cec5SDimitry Andric }
296349cc55cSDimitry Andric }
2970b57cec5SDimitry Andric
298349cc55cSDimitry Andric // Compute definitive function attributes for a function taking into account
299349cc55cSDimitry Andric // prevailing definitions and linkage types
calculatePrevailingSummary(ValueInfo VI,DenseMap<ValueInfo,FunctionSummary * > & CachedPrevailingSummary,function_ref<bool (GlobalValue::GUID,const GlobalValueSummary *)> IsPrevailing)300349cc55cSDimitry Andric static FunctionSummary *calculatePrevailingSummary(
301349cc55cSDimitry Andric ValueInfo VI,
302349cc55cSDimitry Andric DenseMap<ValueInfo, FunctionSummary *> &CachedPrevailingSummary,
303349cc55cSDimitry Andric function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
304349cc55cSDimitry Andric IsPrevailing) {
305349cc55cSDimitry Andric
306349cc55cSDimitry Andric if (CachedPrevailingSummary.count(VI))
307349cc55cSDimitry Andric return CachedPrevailingSummary[VI];
308349cc55cSDimitry Andric
309349cc55cSDimitry Andric /// At this point, prevailing symbols have been resolved. The following leads
310349cc55cSDimitry Andric /// to returning a conservative result:
311349cc55cSDimitry Andric /// - Multiple instances with local linkage. Normally local linkage would be
312349cc55cSDimitry Andric /// unique per module
313349cc55cSDimitry Andric /// as the GUID includes the module path. We could have a guid alias if
314349cc55cSDimitry Andric /// there wasn't any distinguishing path when each file was compiled, but
315349cc55cSDimitry Andric /// that should be rare so we'll punt on those.
316349cc55cSDimitry Andric
317349cc55cSDimitry Andric /// These next 2 cases should not happen and will assert:
318349cc55cSDimitry Andric /// - Multiple instances with external linkage. This should be caught in
319349cc55cSDimitry Andric /// symbol resolution
320349cc55cSDimitry Andric /// - Non-existent FunctionSummary for Aliasee. This presents a hole in our
321349cc55cSDimitry Andric /// knowledge meaning we have to go conservative.
322349cc55cSDimitry Andric
323349cc55cSDimitry Andric /// Otherwise, we calculate attributes for a function as:
324349cc55cSDimitry Andric /// 1. If we have a local linkage, take its attributes. If there's somehow
325349cc55cSDimitry Andric /// multiple, bail and go conservative.
326349cc55cSDimitry Andric /// 2. If we have an external/WeakODR/LinkOnceODR linkage check that it is
327349cc55cSDimitry Andric /// prevailing, take its attributes.
328349cc55cSDimitry Andric /// 3. If we have a Weak/LinkOnce linkage the copies can have semantic
329349cc55cSDimitry Andric /// differences. However, if the prevailing copy is known it will be used
330349cc55cSDimitry Andric /// so take its attributes. If the prevailing copy is in a native file
331349cc55cSDimitry Andric /// all IR copies will be dead and propagation will go conservative.
332349cc55cSDimitry Andric /// 4. AvailableExternally summaries without a prevailing copy are known to
333349cc55cSDimitry Andric /// occur in a couple of circumstances:
334349cc55cSDimitry Andric /// a. An internal function gets imported due to its caller getting
335349cc55cSDimitry Andric /// imported, it becomes AvailableExternally but no prevailing
336349cc55cSDimitry Andric /// definition exists. Because it has to get imported along with its
337349cc55cSDimitry Andric /// caller the attributes will be captured by propagating on its
338349cc55cSDimitry Andric /// caller.
339349cc55cSDimitry Andric /// b. C++11 [temp.explicit]p10 can generate AvailableExternally
340349cc55cSDimitry Andric /// definitions of explicitly instanced template declarations
341349cc55cSDimitry Andric /// for inlining which are ultimately dropped from the TU. Since this
342349cc55cSDimitry Andric /// is localized to the TU the attributes will have already made it to
343349cc55cSDimitry Andric /// the callers.
344349cc55cSDimitry Andric /// These are edge cases and already captured by their callers so we
345349cc55cSDimitry Andric /// ignore these for now. If they become relevant to optimize in the
346349cc55cSDimitry Andric /// future this can be revisited.
347349cc55cSDimitry Andric /// 5. Otherwise, go conservative.
348349cc55cSDimitry Andric
349349cc55cSDimitry Andric CachedPrevailingSummary[VI] = nullptr;
350349cc55cSDimitry Andric FunctionSummary *Local = nullptr;
351349cc55cSDimitry Andric FunctionSummary *Prevailing = nullptr;
352349cc55cSDimitry Andric
353349cc55cSDimitry Andric for (const auto &GVS : VI.getSummaryList()) {
354349cc55cSDimitry Andric if (!GVS->isLive())
355349cc55cSDimitry Andric continue;
356349cc55cSDimitry Andric
357349cc55cSDimitry Andric FunctionSummary *FS = dyn_cast<FunctionSummary>(GVS->getBaseObject());
358349cc55cSDimitry Andric // Virtual and Unknown (e.g. indirect) calls require going conservative
359349cc55cSDimitry Andric if (!FS || FS->fflags().HasUnknownCall)
360349cc55cSDimitry Andric return nullptr;
361349cc55cSDimitry Andric
362349cc55cSDimitry Andric const auto &Linkage = GVS->linkage();
363349cc55cSDimitry Andric if (GlobalValue::isLocalLinkage(Linkage)) {
364349cc55cSDimitry Andric if (Local) {
365349cc55cSDimitry Andric LLVM_DEBUG(
366349cc55cSDimitry Andric dbgs()
367349cc55cSDimitry Andric << "ThinLTO FunctionAttrs: Multiple Local Linkage, bailing on "
368349cc55cSDimitry Andric "function "
369349cc55cSDimitry Andric << VI.name() << " from " << FS->modulePath() << ". Previous module "
370349cc55cSDimitry Andric << Local->modulePath() << "\n");
371349cc55cSDimitry Andric return nullptr;
372349cc55cSDimitry Andric }
373349cc55cSDimitry Andric Local = FS;
374349cc55cSDimitry Andric } else if (GlobalValue::isExternalLinkage(Linkage)) {
375349cc55cSDimitry Andric assert(IsPrevailing(VI.getGUID(), GVS.get()));
376349cc55cSDimitry Andric Prevailing = FS;
377349cc55cSDimitry Andric break;
378349cc55cSDimitry Andric } else if (GlobalValue::isWeakODRLinkage(Linkage) ||
379349cc55cSDimitry Andric GlobalValue::isLinkOnceODRLinkage(Linkage) ||
380349cc55cSDimitry Andric GlobalValue::isWeakAnyLinkage(Linkage) ||
381349cc55cSDimitry Andric GlobalValue::isLinkOnceAnyLinkage(Linkage)) {
382349cc55cSDimitry Andric if (IsPrevailing(VI.getGUID(), GVS.get())) {
383349cc55cSDimitry Andric Prevailing = FS;
384349cc55cSDimitry Andric break;
385349cc55cSDimitry Andric }
386349cc55cSDimitry Andric } else if (GlobalValue::isAvailableExternallyLinkage(Linkage)) {
387349cc55cSDimitry Andric // TODO: Handle these cases if they become meaningful
388349cc55cSDimitry Andric continue;
389349cc55cSDimitry Andric }
390349cc55cSDimitry Andric }
391349cc55cSDimitry Andric
392349cc55cSDimitry Andric if (Local) {
393349cc55cSDimitry Andric assert(!Prevailing);
394349cc55cSDimitry Andric CachedPrevailingSummary[VI] = Local;
395349cc55cSDimitry Andric } else if (Prevailing) {
396349cc55cSDimitry Andric assert(!Local);
397349cc55cSDimitry Andric CachedPrevailingSummary[VI] = Prevailing;
398349cc55cSDimitry Andric }
399349cc55cSDimitry Andric
400349cc55cSDimitry Andric return CachedPrevailingSummary[VI];
401349cc55cSDimitry Andric }
402349cc55cSDimitry Andric
thinLTOPropagateFunctionAttrs(ModuleSummaryIndex & Index,function_ref<bool (GlobalValue::GUID,const GlobalValueSummary *)> IsPrevailing)403349cc55cSDimitry Andric bool llvm::thinLTOPropagateFunctionAttrs(
404349cc55cSDimitry Andric ModuleSummaryIndex &Index,
405349cc55cSDimitry Andric function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
406349cc55cSDimitry Andric IsPrevailing) {
407349cc55cSDimitry Andric // TODO: implement addNoAliasAttrs once
408349cc55cSDimitry Andric // there's more information about the return type in the summary
409349cc55cSDimitry Andric if (DisableThinLTOPropagation)
410349cc55cSDimitry Andric return false;
411349cc55cSDimitry Andric
412349cc55cSDimitry Andric DenseMap<ValueInfo, FunctionSummary *> CachedPrevailingSummary;
413349cc55cSDimitry Andric bool Changed = false;
414349cc55cSDimitry Andric
415349cc55cSDimitry Andric auto PropagateAttributes = [&](std::vector<ValueInfo> &SCCNodes) {
416349cc55cSDimitry Andric // Assume we can propagate unless we discover otherwise
417349cc55cSDimitry Andric FunctionSummary::FFlags InferredFlags;
418349cc55cSDimitry Andric InferredFlags.NoRecurse = (SCCNodes.size() == 1);
419349cc55cSDimitry Andric InferredFlags.NoUnwind = true;
420349cc55cSDimitry Andric
421349cc55cSDimitry Andric for (auto &V : SCCNodes) {
422349cc55cSDimitry Andric FunctionSummary *CallerSummary =
423349cc55cSDimitry Andric calculatePrevailingSummary(V, CachedPrevailingSummary, IsPrevailing);
424349cc55cSDimitry Andric
425349cc55cSDimitry Andric // Function summaries can fail to contain information such as declarations
426349cc55cSDimitry Andric if (!CallerSummary)
427349cc55cSDimitry Andric return;
428349cc55cSDimitry Andric
429349cc55cSDimitry Andric if (CallerSummary->fflags().MayThrow)
430349cc55cSDimitry Andric InferredFlags.NoUnwind = false;
431349cc55cSDimitry Andric
432349cc55cSDimitry Andric for (const auto &Callee : CallerSummary->calls()) {
433349cc55cSDimitry Andric FunctionSummary *CalleeSummary = calculatePrevailingSummary(
434349cc55cSDimitry Andric Callee.first, CachedPrevailingSummary, IsPrevailing);
435349cc55cSDimitry Andric
436349cc55cSDimitry Andric if (!CalleeSummary)
437349cc55cSDimitry Andric return;
438349cc55cSDimitry Andric
439349cc55cSDimitry Andric if (!CalleeSummary->fflags().NoRecurse)
440349cc55cSDimitry Andric InferredFlags.NoRecurse = false;
441349cc55cSDimitry Andric
442349cc55cSDimitry Andric if (!CalleeSummary->fflags().NoUnwind)
443349cc55cSDimitry Andric InferredFlags.NoUnwind = false;
444349cc55cSDimitry Andric
445349cc55cSDimitry Andric if (!InferredFlags.NoUnwind && !InferredFlags.NoRecurse)
446349cc55cSDimitry Andric break;
447349cc55cSDimitry Andric }
448349cc55cSDimitry Andric }
449349cc55cSDimitry Andric
450349cc55cSDimitry Andric if (InferredFlags.NoUnwind || InferredFlags.NoRecurse) {
451349cc55cSDimitry Andric Changed = true;
452349cc55cSDimitry Andric for (auto &V : SCCNodes) {
453349cc55cSDimitry Andric if (InferredFlags.NoRecurse) {
454349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "ThinLTO FunctionAttrs: Propagated NoRecurse to "
455349cc55cSDimitry Andric << V.name() << "\n");
456349cc55cSDimitry Andric ++NumThinLinkNoRecurse;
457349cc55cSDimitry Andric }
458349cc55cSDimitry Andric
459349cc55cSDimitry Andric if (InferredFlags.NoUnwind) {
460349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "ThinLTO FunctionAttrs: Propagated NoUnwind to "
461349cc55cSDimitry Andric << V.name() << "\n");
462349cc55cSDimitry Andric ++NumThinLinkNoUnwind;
463349cc55cSDimitry Andric }
464349cc55cSDimitry Andric
465bdd1243dSDimitry Andric for (const auto &S : V.getSummaryList()) {
466349cc55cSDimitry Andric if (auto *FS = dyn_cast<FunctionSummary>(S.get())) {
467349cc55cSDimitry Andric if (InferredFlags.NoRecurse)
468349cc55cSDimitry Andric FS->setNoRecurse();
469349cc55cSDimitry Andric
470349cc55cSDimitry Andric if (InferredFlags.NoUnwind)
471349cc55cSDimitry Andric FS->setNoUnwind();
472349cc55cSDimitry Andric }
473349cc55cSDimitry Andric }
474349cc55cSDimitry Andric }
475349cc55cSDimitry Andric }
476349cc55cSDimitry Andric };
477349cc55cSDimitry Andric
478349cc55cSDimitry Andric // Call propagation functions on each SCC in the Index
479349cc55cSDimitry Andric for (scc_iterator<ModuleSummaryIndex *> I = scc_begin(&Index); !I.isAtEnd();
480349cc55cSDimitry Andric ++I) {
481349cc55cSDimitry Andric std::vector<ValueInfo> Nodes(*I);
482349cc55cSDimitry Andric PropagateAttributes(Nodes);
483349cc55cSDimitry Andric }
484349cc55cSDimitry Andric return Changed;
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric
4870b57cec5SDimitry Andric namespace {
4880b57cec5SDimitry Andric
4890b57cec5SDimitry Andric /// For a given pointer Argument, this retains a list of Arguments of functions
4900b57cec5SDimitry Andric /// in the same SCC that the pointer data flows into. We use this to build an
4910b57cec5SDimitry Andric /// SCC of the arguments.
4920b57cec5SDimitry Andric struct ArgumentGraphNode {
4930b57cec5SDimitry Andric Argument *Definition;
4940b57cec5SDimitry Andric SmallVector<ArgumentGraphNode *, 4> Uses;
4950b57cec5SDimitry Andric };
4960b57cec5SDimitry Andric
4970b57cec5SDimitry Andric class ArgumentGraph {
4980b57cec5SDimitry Andric // We store pointers to ArgumentGraphNode objects, so it's important that
4990b57cec5SDimitry Andric // that they not move around upon insert.
5000b57cec5SDimitry Andric using ArgumentMapTy = std::map<Argument *, ArgumentGraphNode>;
5010b57cec5SDimitry Andric
5020b57cec5SDimitry Andric ArgumentMapTy ArgumentMap;
5030b57cec5SDimitry Andric
5040b57cec5SDimitry Andric // There is no root node for the argument graph, in fact:
5050b57cec5SDimitry Andric // void f(int *x, int *y) { if (...) f(x, y); }
5060b57cec5SDimitry Andric // is an example where the graph is disconnected. The SCCIterator requires a
5070b57cec5SDimitry Andric // single entry point, so we maintain a fake ("synthetic") root node that
5080b57cec5SDimitry Andric // uses every node. Because the graph is directed and nothing points into
5090b57cec5SDimitry Andric // the root, it will not participate in any SCCs (except for its own).
5100b57cec5SDimitry Andric ArgumentGraphNode SyntheticRoot;
5110b57cec5SDimitry Andric
5120b57cec5SDimitry Andric public:
ArgumentGraph()5130b57cec5SDimitry Andric ArgumentGraph() { SyntheticRoot.Definition = nullptr; }
5140b57cec5SDimitry Andric
5150b57cec5SDimitry Andric using iterator = SmallVectorImpl<ArgumentGraphNode *>::iterator;
5160b57cec5SDimitry Andric
begin()5170b57cec5SDimitry Andric iterator begin() { return SyntheticRoot.Uses.begin(); }
end()5180b57cec5SDimitry Andric iterator end() { return SyntheticRoot.Uses.end(); }
getEntryNode()5190b57cec5SDimitry Andric ArgumentGraphNode *getEntryNode() { return &SyntheticRoot; }
5200b57cec5SDimitry Andric
operator [](Argument * A)5210b57cec5SDimitry Andric ArgumentGraphNode *operator[](Argument *A) {
5220b57cec5SDimitry Andric ArgumentGraphNode &Node = ArgumentMap[A];
5230b57cec5SDimitry Andric Node.Definition = A;
5240b57cec5SDimitry Andric SyntheticRoot.Uses.push_back(&Node);
5250b57cec5SDimitry Andric return &Node;
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric };
5280b57cec5SDimitry Andric
5290b57cec5SDimitry Andric /// This tracker checks whether callees are in the SCC, and if so it does not
5300b57cec5SDimitry Andric /// consider that a capture, instead adding it to the "Uses" list and
5310b57cec5SDimitry Andric /// continuing with the analysis.
5320b57cec5SDimitry Andric struct ArgumentUsesTracker : public CaptureTracker {
ArgumentUsesTracker__anon416db8590311::ArgumentUsesTracker5330b57cec5SDimitry Andric ArgumentUsesTracker(const SCCNodeSet &SCCNodes) : SCCNodes(SCCNodes) {}
5340b57cec5SDimitry Andric
tooManyUses__anon416db8590311::ArgumentUsesTracker5350b57cec5SDimitry Andric void tooManyUses() override { Captured = true; }
5360b57cec5SDimitry Andric
captured__anon416db8590311::ArgumentUsesTracker5370b57cec5SDimitry Andric bool captured(const Use *U) override {
5385ffd83dbSDimitry Andric CallBase *CB = dyn_cast<CallBase>(U->getUser());
5395ffd83dbSDimitry Andric if (!CB) {
5400b57cec5SDimitry Andric Captured = true;
5410b57cec5SDimitry Andric return true;
5420b57cec5SDimitry Andric }
5430b57cec5SDimitry Andric
5445ffd83dbSDimitry Andric Function *F = CB->getCalledFunction();
5450b57cec5SDimitry Andric if (!F || !F->hasExactDefinition() || !SCCNodes.count(F)) {
5460b57cec5SDimitry Andric Captured = true;
5470b57cec5SDimitry Andric return true;
5480b57cec5SDimitry Andric }
5490b57cec5SDimitry Andric
5500eae32dcSDimitry Andric assert(!CB->isCallee(U) && "callee operand reported captured?");
5510eae32dcSDimitry Andric const unsigned UseIndex = CB->getDataOperandNo(U);
552349cc55cSDimitry Andric if (UseIndex >= CB->arg_size()) {
5530b57cec5SDimitry Andric // Data operand, but not a argument operand -- must be a bundle operand
5545ffd83dbSDimitry Andric assert(CB->hasOperandBundles() && "Must be!");
5550b57cec5SDimitry Andric
5560b57cec5SDimitry Andric // CaptureTracking told us that we're being captured by an operand bundle
5570b57cec5SDimitry Andric // use. In this case it does not matter if the callee is within our SCC
5580b57cec5SDimitry Andric // or not -- we've been captured in some unknown way, and we have to be
5590b57cec5SDimitry Andric // conservative.
5600b57cec5SDimitry Andric Captured = true;
5610b57cec5SDimitry Andric return true;
5620b57cec5SDimitry Andric }
5630b57cec5SDimitry Andric
5640b57cec5SDimitry Andric if (UseIndex >= F->arg_size()) {
5650b57cec5SDimitry Andric assert(F->isVarArg() && "More params than args in non-varargs call");
5660b57cec5SDimitry Andric Captured = true;
5670b57cec5SDimitry Andric return true;
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric
5700b57cec5SDimitry Andric Uses.push_back(&*std::next(F->arg_begin(), UseIndex));
5710b57cec5SDimitry Andric return false;
5720b57cec5SDimitry Andric }
5730b57cec5SDimitry Andric
5740b57cec5SDimitry Andric // True only if certainly captured (used outside our SCC).
5750b57cec5SDimitry Andric bool Captured = false;
5760b57cec5SDimitry Andric
5770b57cec5SDimitry Andric // Uses within our SCC.
5780b57cec5SDimitry Andric SmallVector<Argument *, 4> Uses;
5790b57cec5SDimitry Andric
5800b57cec5SDimitry Andric const SCCNodeSet &SCCNodes;
5810b57cec5SDimitry Andric };
5820b57cec5SDimitry Andric
5830b57cec5SDimitry Andric } // end anonymous namespace
5840b57cec5SDimitry Andric
5850b57cec5SDimitry Andric namespace llvm {
5860b57cec5SDimitry Andric
5870b57cec5SDimitry Andric template <> struct GraphTraits<ArgumentGraphNode *> {
5880b57cec5SDimitry Andric using NodeRef = ArgumentGraphNode *;
5890b57cec5SDimitry Andric using ChildIteratorType = SmallVectorImpl<ArgumentGraphNode *>::iterator;
5900b57cec5SDimitry Andric
getEntryNodellvm::GraphTraits5910b57cec5SDimitry Andric static NodeRef getEntryNode(NodeRef A) { return A; }
child_beginllvm::GraphTraits5920b57cec5SDimitry Andric static ChildIteratorType child_begin(NodeRef N) { return N->Uses.begin(); }
child_endllvm::GraphTraits5930b57cec5SDimitry Andric static ChildIteratorType child_end(NodeRef N) { return N->Uses.end(); }
5940b57cec5SDimitry Andric };
5950b57cec5SDimitry Andric
5960b57cec5SDimitry Andric template <>
5970b57cec5SDimitry Andric struct GraphTraits<ArgumentGraph *> : public GraphTraits<ArgumentGraphNode *> {
getEntryNodellvm::GraphTraits5980b57cec5SDimitry Andric static NodeRef getEntryNode(ArgumentGraph *AG) { return AG->getEntryNode(); }
5990b57cec5SDimitry Andric
nodes_beginllvm::GraphTraits6000b57cec5SDimitry Andric static ChildIteratorType nodes_begin(ArgumentGraph *AG) {
6010b57cec5SDimitry Andric return AG->begin();
6020b57cec5SDimitry Andric }
6030b57cec5SDimitry Andric
nodes_endllvm::GraphTraits6040b57cec5SDimitry Andric static ChildIteratorType nodes_end(ArgumentGraph *AG) { return AG->end(); }
6050b57cec5SDimitry Andric };
6060b57cec5SDimitry Andric
6070b57cec5SDimitry Andric } // end namespace llvm
6080b57cec5SDimitry Andric
6090b57cec5SDimitry Andric /// Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
6100b57cec5SDimitry Andric static Attribute::AttrKind
determinePointerAccessAttrs(Argument * A,const SmallPtrSet<Argument *,8> & SCCNodes)6110eae32dcSDimitry Andric determinePointerAccessAttrs(Argument *A,
6120b57cec5SDimitry Andric const SmallPtrSet<Argument *, 8> &SCCNodes) {
6130b57cec5SDimitry Andric SmallVector<Use *, 32> Worklist;
6140b57cec5SDimitry Andric SmallPtrSet<Use *, 32> Visited;
6150b57cec5SDimitry Andric
6160b57cec5SDimitry Andric // inalloca arguments are always clobbered by the call.
6175ffd83dbSDimitry Andric if (A->hasInAllocaAttr() || A->hasPreallocatedAttr())
6180b57cec5SDimitry Andric return Attribute::None;
6190b57cec5SDimitry Andric
6200b57cec5SDimitry Andric bool IsRead = false;
6210eae32dcSDimitry Andric bool IsWrite = false;
6220b57cec5SDimitry Andric
6230b57cec5SDimitry Andric for (Use &U : A->uses()) {
6240b57cec5SDimitry Andric Visited.insert(&U);
6250b57cec5SDimitry Andric Worklist.push_back(&U);
6260b57cec5SDimitry Andric }
6270b57cec5SDimitry Andric
6280b57cec5SDimitry Andric while (!Worklist.empty()) {
6290eae32dcSDimitry Andric if (IsWrite && IsRead)
6300eae32dcSDimitry Andric // No point in searching further..
6310eae32dcSDimitry Andric return Attribute::None;
6320eae32dcSDimitry Andric
6330b57cec5SDimitry Andric Use *U = Worklist.pop_back_val();
6340b57cec5SDimitry Andric Instruction *I = cast<Instruction>(U->getUser());
6350b57cec5SDimitry Andric
6360b57cec5SDimitry Andric switch (I->getOpcode()) {
6370b57cec5SDimitry Andric case Instruction::BitCast:
6380b57cec5SDimitry Andric case Instruction::GetElementPtr:
6390b57cec5SDimitry Andric case Instruction::PHI:
6400b57cec5SDimitry Andric case Instruction::Select:
6410b57cec5SDimitry Andric case Instruction::AddrSpaceCast:
6420b57cec5SDimitry Andric // The original value is not read/written via this if the new value isn't.
6430b57cec5SDimitry Andric for (Use &UU : I->uses())
6440b57cec5SDimitry Andric if (Visited.insert(&UU).second)
6450b57cec5SDimitry Andric Worklist.push_back(&UU);
6460b57cec5SDimitry Andric break;
6470b57cec5SDimitry Andric
6480b57cec5SDimitry Andric case Instruction::Call:
6490b57cec5SDimitry Andric case Instruction::Invoke: {
6500eae32dcSDimitry Andric CallBase &CB = cast<CallBase>(*I);
6510eae32dcSDimitry Andric if (CB.isCallee(U)) {
6520eae32dcSDimitry Andric IsRead = true;
6530eae32dcSDimitry Andric // Note that indirect calls do not capture, see comment in
6540eae32dcSDimitry Andric // CaptureTracking for context
6550eae32dcSDimitry Andric continue;
6560eae32dcSDimitry Andric }
6570b57cec5SDimitry Andric
6580eae32dcSDimitry Andric // Given we've explictily handled the callee operand above, what's left
6590eae32dcSDimitry Andric // must be a data operand (e.g. argument or operand bundle)
6600eae32dcSDimitry Andric const unsigned UseIndex = CB.getDataOperandNo(U);
6610b57cec5SDimitry Andric
6625f757f3fSDimitry Andric // Some intrinsics (for instance ptrmask) do not capture their results,
6635f757f3fSDimitry Andric // but return results thas alias their pointer argument, and thus should
6645f757f3fSDimitry Andric // be handled like GEP or addrspacecast above.
6655f757f3fSDimitry Andric if (isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(
6665f757f3fSDimitry Andric &CB, /*MustPreserveNullness=*/false)) {
6675f757f3fSDimitry Andric for (Use &UU : CB.uses())
6685f757f3fSDimitry Andric if (Visited.insert(&UU).second)
6695f757f3fSDimitry Andric Worklist.push_back(&UU);
6705f757f3fSDimitry Andric } else if (!CB.doesNotCapture(UseIndex)) {
6710eae32dcSDimitry Andric if (!CB.onlyReadsMemory())
6720eae32dcSDimitry Andric // If the callee can save a copy into other memory, then simply
6730eae32dcSDimitry Andric // scanning uses of the call is insufficient. We have no way
6740eae32dcSDimitry Andric // of tracking copies of the pointer through memory to see
6750eae32dcSDimitry Andric // if a reloaded copy is written to, thus we must give up.
6760eae32dcSDimitry Andric return Attribute::None;
6770eae32dcSDimitry Andric // Push users for processing once we finish this one
6780eae32dcSDimitry Andric if (!I->getType()->isVoidTy())
6790b57cec5SDimitry Andric for (Use &UU : I->uses())
6800b57cec5SDimitry Andric if (Visited.insert(&UU).second)
6810b57cec5SDimitry Andric Worklist.push_back(&UU);
6820eae32dcSDimitry Andric }
6830b57cec5SDimitry Andric
6845f757f3fSDimitry Andric ModRefInfo ArgMR = CB.getMemoryEffects().getModRef(IRMemLocation::ArgMem);
6855f757f3fSDimitry Andric if (isNoModRef(ArgMR))
6860b57cec5SDimitry Andric continue;
6870b57cec5SDimitry Andric
6880eae32dcSDimitry Andric if (Function *F = CB.getCalledFunction())
6890eae32dcSDimitry Andric if (CB.isArgOperand(U) && UseIndex < F->arg_size() &&
6900eae32dcSDimitry Andric SCCNodes.count(F->getArg(UseIndex)))
6910eae32dcSDimitry Andric // This is an argument which is part of the speculative SCC. Note
6920eae32dcSDimitry Andric // that only operands corresponding to formal arguments of the callee
6930eae32dcSDimitry Andric // can participate in the speculation.
6940eae32dcSDimitry Andric break;
6950b57cec5SDimitry Andric
6965ffd83dbSDimitry Andric // The accessors used on call site here do the right thing for calls and
6970b57cec5SDimitry Andric // invokes with operand bundles.
69804eeddc0SDimitry Andric if (CB.doesNotAccessMemory(UseIndex)) {
69904eeddc0SDimitry Andric /* nop */
7005f757f3fSDimitry Andric } else if (!isModSet(ArgMR) || CB.onlyReadsMemory(UseIndex)) {
7010b57cec5SDimitry Andric IsRead = true;
7025f757f3fSDimitry Andric } else if (!isRefSet(ArgMR) ||
70304eeddc0SDimitry Andric CB.dataOperandHasImpliedAttr(UseIndex, Attribute::WriteOnly)) {
70404eeddc0SDimitry Andric IsWrite = true;
70504eeddc0SDimitry Andric } else {
70604eeddc0SDimitry Andric return Attribute::None;
70704eeddc0SDimitry Andric }
7080b57cec5SDimitry Andric break;
7090b57cec5SDimitry Andric }
7100b57cec5SDimitry Andric
7110b57cec5SDimitry Andric case Instruction::Load:
7120b57cec5SDimitry Andric // A volatile load has side effects beyond what readonly can be relied
7130b57cec5SDimitry Andric // upon.
7140b57cec5SDimitry Andric if (cast<LoadInst>(I)->isVolatile())
7150b57cec5SDimitry Andric return Attribute::None;
7160b57cec5SDimitry Andric
7170b57cec5SDimitry Andric IsRead = true;
7180b57cec5SDimitry Andric break;
7190b57cec5SDimitry Andric
7200eae32dcSDimitry Andric case Instruction::Store:
7210eae32dcSDimitry Andric if (cast<StoreInst>(I)->getValueOperand() == *U)
7220eae32dcSDimitry Andric // untrackable capture
7230eae32dcSDimitry Andric return Attribute::None;
7240eae32dcSDimitry Andric
7250eae32dcSDimitry Andric // A volatile store has side effects beyond what writeonly can be relied
7260eae32dcSDimitry Andric // upon.
7270eae32dcSDimitry Andric if (cast<StoreInst>(I)->isVolatile())
7280eae32dcSDimitry Andric return Attribute::None;
7290eae32dcSDimitry Andric
7300eae32dcSDimitry Andric IsWrite = true;
7310eae32dcSDimitry Andric break;
7320eae32dcSDimitry Andric
7330b57cec5SDimitry Andric case Instruction::ICmp:
7340b57cec5SDimitry Andric case Instruction::Ret:
7350b57cec5SDimitry Andric break;
7360b57cec5SDimitry Andric
7370b57cec5SDimitry Andric default:
7380b57cec5SDimitry Andric return Attribute::None;
7390b57cec5SDimitry Andric }
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric
7420eae32dcSDimitry Andric if (IsWrite && IsRead)
7430eae32dcSDimitry Andric return Attribute::None;
7440eae32dcSDimitry Andric else if (IsRead)
7450eae32dcSDimitry Andric return Attribute::ReadOnly;
7460eae32dcSDimitry Andric else if (IsWrite)
7470eae32dcSDimitry Andric return Attribute::WriteOnly;
7480eae32dcSDimitry Andric else
7490eae32dcSDimitry Andric return Attribute::ReadNone;
7500b57cec5SDimitry Andric }
7510b57cec5SDimitry Andric
7520b57cec5SDimitry Andric /// Deduce returned attributes for the SCC.
addArgumentReturnedAttrs(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)753349cc55cSDimitry Andric static void addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes,
754349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
7550b57cec5SDimitry Andric // Check each function in turn, determining if an argument is always returned.
7560b57cec5SDimitry Andric for (Function *F : SCCNodes) {
7570b57cec5SDimitry Andric // We can infer and propagate function attributes only when we know that the
7580b57cec5SDimitry Andric // definition we'll get at link time is *exactly* the definition we see now.
7590b57cec5SDimitry Andric // For more details, see GlobalValue::mayBeDerefined.
7600b57cec5SDimitry Andric if (!F->hasExactDefinition())
7610b57cec5SDimitry Andric continue;
7620b57cec5SDimitry Andric
7630b57cec5SDimitry Andric if (F->getReturnType()->isVoidTy())
7640b57cec5SDimitry Andric continue;
7650b57cec5SDimitry Andric
7660b57cec5SDimitry Andric // There is nothing to do if an argument is already marked as 'returned'.
76706c3fb27SDimitry Andric if (F->getAttributes().hasAttrSomewhere(Attribute::Returned))
7680b57cec5SDimitry Andric continue;
7690b57cec5SDimitry Andric
77006c3fb27SDimitry Andric auto FindRetArg = [&]() -> Argument * {
77106c3fb27SDimitry Andric Argument *RetArg = nullptr;
7720b57cec5SDimitry Andric for (BasicBlock &BB : *F)
7730b57cec5SDimitry Andric if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) {
7740b57cec5SDimitry Andric // Note that stripPointerCasts should look through functions with
7750b57cec5SDimitry Andric // returned arguments.
77606c3fb27SDimitry Andric auto *RetVal =
77706c3fb27SDimitry Andric dyn_cast<Argument>(Ret->getReturnValue()->stripPointerCasts());
77806c3fb27SDimitry Andric if (!RetVal || RetVal->getType() != F->getReturnType())
7790b57cec5SDimitry Andric return nullptr;
7800b57cec5SDimitry Andric
7810b57cec5SDimitry Andric if (!RetArg)
7820b57cec5SDimitry Andric RetArg = RetVal;
7830b57cec5SDimitry Andric else if (RetArg != RetVal)
7840b57cec5SDimitry Andric return nullptr;
7850b57cec5SDimitry Andric }
7860b57cec5SDimitry Andric
7870b57cec5SDimitry Andric return RetArg;
7880b57cec5SDimitry Andric };
7890b57cec5SDimitry Andric
79006c3fb27SDimitry Andric if (Argument *RetArg = FindRetArg()) {
79106c3fb27SDimitry Andric RetArg->addAttr(Attribute::Returned);
7920b57cec5SDimitry Andric ++NumReturned;
793349cc55cSDimitry Andric Changed.insert(F);
7940b57cec5SDimitry Andric }
7950b57cec5SDimitry Andric }
7960b57cec5SDimitry Andric }
7970b57cec5SDimitry Andric
7980b57cec5SDimitry Andric /// If a callsite has arguments that are also arguments to the parent function,
7990b57cec5SDimitry Andric /// try to propagate attributes from the callsite's arguments to the parent's
8000b57cec5SDimitry Andric /// arguments. This may be important because inlining can cause information loss
8010b57cec5SDimitry Andric /// when attribute knowledge disappears with the inlined call.
addArgumentAttrsFromCallsites(Function & F)8020b57cec5SDimitry Andric static bool addArgumentAttrsFromCallsites(Function &F) {
8030b57cec5SDimitry Andric if (!EnableNonnullArgPropagation)
8040b57cec5SDimitry Andric return false;
8050b57cec5SDimitry Andric
8060b57cec5SDimitry Andric bool Changed = false;
8070b57cec5SDimitry Andric
8080b57cec5SDimitry Andric // For an argument attribute to transfer from a callsite to the parent, the
8090b57cec5SDimitry Andric // call must be guaranteed to execute every time the parent is called.
8100b57cec5SDimitry Andric // Conservatively, just check for calls in the entry block that are guaranteed
8110b57cec5SDimitry Andric // to execute.
8120b57cec5SDimitry Andric // TODO: This could be enhanced by testing if the callsite post-dominates the
8130b57cec5SDimitry Andric // entry block or by doing simple forward walks or backward walks to the
8140b57cec5SDimitry Andric // callsite.
8150b57cec5SDimitry Andric BasicBlock &Entry = F.getEntryBlock();
8160b57cec5SDimitry Andric for (Instruction &I : Entry) {
8175ffd83dbSDimitry Andric if (auto *CB = dyn_cast<CallBase>(&I)) {
8185ffd83dbSDimitry Andric if (auto *CalledFunc = CB->getCalledFunction()) {
8190b57cec5SDimitry Andric for (auto &CSArg : CalledFunc->args()) {
820e8d8bef9SDimitry Andric if (!CSArg.hasNonNullAttr(/* AllowUndefOrPoison */ false))
8210b57cec5SDimitry Andric continue;
8220b57cec5SDimitry Andric
8230b57cec5SDimitry Andric // If the non-null callsite argument operand is an argument to 'F'
8240b57cec5SDimitry Andric // (the caller) and the call is guaranteed to execute, then the value
8250b57cec5SDimitry Andric // must be non-null throughout 'F'.
8265ffd83dbSDimitry Andric auto *FArg = dyn_cast<Argument>(CB->getArgOperand(CSArg.getArgNo()));
8270b57cec5SDimitry Andric if (FArg && !FArg->hasNonNullAttr()) {
8280b57cec5SDimitry Andric FArg->addAttr(Attribute::NonNull);
8290b57cec5SDimitry Andric Changed = true;
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric }
8320b57cec5SDimitry Andric }
8330b57cec5SDimitry Andric }
8340b57cec5SDimitry Andric if (!isGuaranteedToTransferExecutionToSuccessor(&I))
8350b57cec5SDimitry Andric break;
8360b57cec5SDimitry Andric }
8370b57cec5SDimitry Andric
8380b57cec5SDimitry Andric return Changed;
8390b57cec5SDimitry Andric }
8400b57cec5SDimitry Andric
addAccessAttr(Argument * A,Attribute::AttrKind R)8410eae32dcSDimitry Andric static bool addAccessAttr(Argument *A, Attribute::AttrKind R) {
8420eae32dcSDimitry Andric assert((R == Attribute::ReadOnly || R == Attribute::ReadNone ||
8430eae32dcSDimitry Andric R == Attribute::WriteOnly)
8440eae32dcSDimitry Andric && "Must be an access attribute.");
8458bcb0991SDimitry Andric assert(A && "Argument must not be null.");
8468bcb0991SDimitry Andric
8478bcb0991SDimitry Andric // If the argument already has the attribute, nothing needs to be done.
8488bcb0991SDimitry Andric if (A->hasAttribute(R))
8498bcb0991SDimitry Andric return false;
8508bcb0991SDimitry Andric
8518bcb0991SDimitry Andric // Otherwise, remove potentially conflicting attribute, add the new one,
8528bcb0991SDimitry Andric // and update statistics.
8538bcb0991SDimitry Andric A->removeAttr(Attribute::WriteOnly);
8548bcb0991SDimitry Andric A->removeAttr(Attribute::ReadOnly);
8558bcb0991SDimitry Andric A->removeAttr(Attribute::ReadNone);
8565f757f3fSDimitry Andric // Remove conflicting writable attribute.
8575f757f3fSDimitry Andric if (R == Attribute::ReadNone || R == Attribute::ReadOnly)
8585f757f3fSDimitry Andric A->removeAttr(Attribute::Writable);
8598bcb0991SDimitry Andric A->addAttr(R);
8600eae32dcSDimitry Andric if (R == Attribute::ReadOnly)
8610eae32dcSDimitry Andric ++NumReadOnlyArg;
8620eae32dcSDimitry Andric else if (R == Attribute::WriteOnly)
8630eae32dcSDimitry Andric ++NumWriteOnlyArg;
8640eae32dcSDimitry Andric else
8650eae32dcSDimitry Andric ++NumReadNoneArg;
8668bcb0991SDimitry Andric return true;
8678bcb0991SDimitry Andric }
8688bcb0991SDimitry Andric
8690b57cec5SDimitry Andric /// Deduce nocapture attributes for the SCC.
addArgumentAttrs(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)870349cc55cSDimitry Andric static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
871349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
8720b57cec5SDimitry Andric ArgumentGraph AG;
8730b57cec5SDimitry Andric
8740b57cec5SDimitry Andric // Check each function in turn, determining which pointer arguments are not
8750b57cec5SDimitry Andric // captured.
8760b57cec5SDimitry Andric for (Function *F : SCCNodes) {
8770b57cec5SDimitry Andric // We can infer and propagate function attributes only when we know that the
8780b57cec5SDimitry Andric // definition we'll get at link time is *exactly* the definition we see now.
8790b57cec5SDimitry Andric // For more details, see GlobalValue::mayBeDerefined.
8800b57cec5SDimitry Andric if (!F->hasExactDefinition())
8810b57cec5SDimitry Andric continue;
8820b57cec5SDimitry Andric
883349cc55cSDimitry Andric if (addArgumentAttrsFromCallsites(*F))
884349cc55cSDimitry Andric Changed.insert(F);
8850b57cec5SDimitry Andric
8860b57cec5SDimitry Andric // Functions that are readonly (or readnone) and nounwind and don't return
8870b57cec5SDimitry Andric // a value can't capture arguments. Don't analyze them.
8880b57cec5SDimitry Andric if (F->onlyReadsMemory() && F->doesNotThrow() &&
8890b57cec5SDimitry Andric F->getReturnType()->isVoidTy()) {
890972a253aSDimitry Andric for (Argument &A : F->args()) {
891972a253aSDimitry Andric if (A.getType()->isPointerTy() && !A.hasNoCaptureAttr()) {
892972a253aSDimitry Andric A.addAttr(Attribute::NoCapture);
8930b57cec5SDimitry Andric ++NumNoCapture;
894349cc55cSDimitry Andric Changed.insert(F);
8950b57cec5SDimitry Andric }
8960b57cec5SDimitry Andric }
8970b57cec5SDimitry Andric continue;
8980b57cec5SDimitry Andric }
8990b57cec5SDimitry Andric
900972a253aSDimitry Andric for (Argument &A : F->args()) {
901972a253aSDimitry Andric if (!A.getType()->isPointerTy())
9020b57cec5SDimitry Andric continue;
9030b57cec5SDimitry Andric bool HasNonLocalUses = false;
904972a253aSDimitry Andric if (!A.hasNoCaptureAttr()) {
9050b57cec5SDimitry Andric ArgumentUsesTracker Tracker(SCCNodes);
906972a253aSDimitry Andric PointerMayBeCaptured(&A, &Tracker);
9070b57cec5SDimitry Andric if (!Tracker.Captured) {
9080b57cec5SDimitry Andric if (Tracker.Uses.empty()) {
9090b57cec5SDimitry Andric // If it's trivially not captured, mark it nocapture now.
910972a253aSDimitry Andric A.addAttr(Attribute::NoCapture);
9110b57cec5SDimitry Andric ++NumNoCapture;
912349cc55cSDimitry Andric Changed.insert(F);
9130b57cec5SDimitry Andric } else {
9140b57cec5SDimitry Andric // If it's not trivially captured and not trivially not captured,
9150b57cec5SDimitry Andric // then it must be calling into another function in our SCC. Save
9160b57cec5SDimitry Andric // its particulars for Argument-SCC analysis later.
917972a253aSDimitry Andric ArgumentGraphNode *Node = AG[&A];
9180b57cec5SDimitry Andric for (Argument *Use : Tracker.Uses) {
9190b57cec5SDimitry Andric Node->Uses.push_back(AG[Use]);
920972a253aSDimitry Andric if (Use != &A)
9210b57cec5SDimitry Andric HasNonLocalUses = true;
9220b57cec5SDimitry Andric }
9230b57cec5SDimitry Andric }
9240b57cec5SDimitry Andric }
9250b57cec5SDimitry Andric // Otherwise, it's captured. Don't bother doing SCC analysis on it.
9260b57cec5SDimitry Andric }
927972a253aSDimitry Andric if (!HasNonLocalUses && !A.onlyReadsMemory()) {
9280eae32dcSDimitry Andric // Can we determine that it's readonly/readnone/writeonly without doing
9290eae32dcSDimitry Andric // an SCC? Note that we don't allow any calls at all here, or else our
9300eae32dcSDimitry Andric // result will be dependent on the iteration order through the
9310eae32dcSDimitry Andric // functions in the SCC.
9320b57cec5SDimitry Andric SmallPtrSet<Argument *, 8> Self;
933972a253aSDimitry Andric Self.insert(&A);
934972a253aSDimitry Andric Attribute::AttrKind R = determinePointerAccessAttrs(&A, Self);
9358bcb0991SDimitry Andric if (R != Attribute::None)
936972a253aSDimitry Andric if (addAccessAttr(&A, R))
937349cc55cSDimitry Andric Changed.insert(F);
9380b57cec5SDimitry Andric }
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric }
9410b57cec5SDimitry Andric
9420b57cec5SDimitry Andric // The graph we've collected is partial because we stopped scanning for
9430b57cec5SDimitry Andric // argument uses once we solved the argument trivially. These partial nodes
9440b57cec5SDimitry Andric // show up as ArgumentGraphNode objects with an empty Uses list, and for
9450b57cec5SDimitry Andric // these nodes the final decision about whether they capture has already been
9460b57cec5SDimitry Andric // made. If the definition doesn't have a 'nocapture' attribute by now, it
9470b57cec5SDimitry Andric // captures.
9480b57cec5SDimitry Andric
9490b57cec5SDimitry Andric for (scc_iterator<ArgumentGraph *> I = scc_begin(&AG); !I.isAtEnd(); ++I) {
9500b57cec5SDimitry Andric const std::vector<ArgumentGraphNode *> &ArgumentSCC = *I;
9510b57cec5SDimitry Andric if (ArgumentSCC.size() == 1) {
9520b57cec5SDimitry Andric if (!ArgumentSCC[0]->Definition)
9530b57cec5SDimitry Andric continue; // synthetic root node
9540b57cec5SDimitry Andric
9550b57cec5SDimitry Andric // eg. "void f(int* x) { if (...) f(x); }"
9560b57cec5SDimitry Andric if (ArgumentSCC[0]->Uses.size() == 1 &&
9570b57cec5SDimitry Andric ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
9580b57cec5SDimitry Andric Argument *A = ArgumentSCC[0]->Definition;
9590b57cec5SDimitry Andric A->addAttr(Attribute::NoCapture);
9600b57cec5SDimitry Andric ++NumNoCapture;
961349cc55cSDimitry Andric Changed.insert(A->getParent());
9620eae32dcSDimitry Andric
9630eae32dcSDimitry Andric // Infer the access attributes given the new nocapture one
9640eae32dcSDimitry Andric SmallPtrSet<Argument *, 8> Self;
9650eae32dcSDimitry Andric Self.insert(&*A);
9660eae32dcSDimitry Andric Attribute::AttrKind R = determinePointerAccessAttrs(&*A, Self);
9670eae32dcSDimitry Andric if (R != Attribute::None)
9680eae32dcSDimitry Andric addAccessAttr(A, R);
9690b57cec5SDimitry Andric }
9700b57cec5SDimitry Andric continue;
9710b57cec5SDimitry Andric }
9720b57cec5SDimitry Andric
9730b57cec5SDimitry Andric bool SCCCaptured = false;
974972a253aSDimitry Andric for (ArgumentGraphNode *Node : ArgumentSCC) {
975972a253aSDimitry Andric if (Node->Uses.empty() && !Node->Definition->hasNoCaptureAttr()) {
9760b57cec5SDimitry Andric SCCCaptured = true;
977972a253aSDimitry Andric break;
9780b57cec5SDimitry Andric }
9790b57cec5SDimitry Andric }
9800b57cec5SDimitry Andric if (SCCCaptured)
9810b57cec5SDimitry Andric continue;
9820b57cec5SDimitry Andric
9830b57cec5SDimitry Andric SmallPtrSet<Argument *, 8> ArgumentSCCNodes;
9840b57cec5SDimitry Andric // Fill ArgumentSCCNodes with the elements of the ArgumentSCC. Used for
9850b57cec5SDimitry Andric // quickly looking up whether a given Argument is in this ArgumentSCC.
9860b57cec5SDimitry Andric for (ArgumentGraphNode *I : ArgumentSCC) {
9870b57cec5SDimitry Andric ArgumentSCCNodes.insert(I->Definition);
9880b57cec5SDimitry Andric }
9890b57cec5SDimitry Andric
990972a253aSDimitry Andric for (ArgumentGraphNode *N : ArgumentSCC) {
9910b57cec5SDimitry Andric for (ArgumentGraphNode *Use : N->Uses) {
9920b57cec5SDimitry Andric Argument *A = Use->Definition;
9930b57cec5SDimitry Andric if (A->hasNoCaptureAttr() || ArgumentSCCNodes.count(A))
9940b57cec5SDimitry Andric continue;
9950b57cec5SDimitry Andric SCCCaptured = true;
9960b57cec5SDimitry Andric break;
9970b57cec5SDimitry Andric }
998972a253aSDimitry Andric if (SCCCaptured)
999972a253aSDimitry Andric break;
10000b57cec5SDimitry Andric }
10010b57cec5SDimitry Andric if (SCCCaptured)
10020b57cec5SDimitry Andric continue;
10030b57cec5SDimitry Andric
1004972a253aSDimitry Andric for (ArgumentGraphNode *N : ArgumentSCC) {
1005972a253aSDimitry Andric Argument *A = N->Definition;
10060b57cec5SDimitry Andric A->addAttr(Attribute::NoCapture);
10070b57cec5SDimitry Andric ++NumNoCapture;
1008349cc55cSDimitry Andric Changed.insert(A->getParent());
10090b57cec5SDimitry Andric }
10100b57cec5SDimitry Andric
10110eae32dcSDimitry Andric // We also want to compute readonly/readnone/writeonly. With a small number
10120eae32dcSDimitry Andric // of false negatives, we can assume that any pointer which is captured
10130eae32dcSDimitry Andric // isn't going to be provably readonly or readnone, since by definition
10140eae32dcSDimitry Andric // we can't analyze all uses of a captured pointer.
10150b57cec5SDimitry Andric //
10160b57cec5SDimitry Andric // The false negatives happen when the pointer is captured by a function
10170b57cec5SDimitry Andric // that promises readonly/readnone behaviour on the pointer, then the
10180b57cec5SDimitry Andric // pointer's lifetime ends before anything that writes to arbitrary memory.
10190b57cec5SDimitry Andric // Also, a readonly/readnone pointer may be returned, but returning a
10200b57cec5SDimitry Andric // pointer is capturing it.
10210b57cec5SDimitry Andric
10220eae32dcSDimitry Andric auto meetAccessAttr = [](Attribute::AttrKind A, Attribute::AttrKind B) {
10230eae32dcSDimitry Andric if (A == B)
10240eae32dcSDimitry Andric return A;
10250eae32dcSDimitry Andric if (A == Attribute::ReadNone)
10260eae32dcSDimitry Andric return B;
10270eae32dcSDimitry Andric if (B == Attribute::ReadNone)
10280eae32dcSDimitry Andric return A;
10290eae32dcSDimitry Andric return Attribute::None;
10300eae32dcSDimitry Andric };
10310eae32dcSDimitry Andric
10320eae32dcSDimitry Andric Attribute::AttrKind AccessAttr = Attribute::ReadNone;
1033972a253aSDimitry Andric for (ArgumentGraphNode *N : ArgumentSCC) {
1034972a253aSDimitry Andric Argument *A = N->Definition;
10350eae32dcSDimitry Andric Attribute::AttrKind K = determinePointerAccessAttrs(A, ArgumentSCCNodes);
10360eae32dcSDimitry Andric AccessAttr = meetAccessAttr(AccessAttr, K);
1037972a253aSDimitry Andric if (AccessAttr == Attribute::None)
1038972a253aSDimitry Andric break;
10390b57cec5SDimitry Andric }
10400b57cec5SDimitry Andric
10410eae32dcSDimitry Andric if (AccessAttr != Attribute::None) {
1042972a253aSDimitry Andric for (ArgumentGraphNode *N : ArgumentSCC) {
1043972a253aSDimitry Andric Argument *A = N->Definition;
10440eae32dcSDimitry Andric if (addAccessAttr(A, AccessAttr))
1045349cc55cSDimitry Andric Changed.insert(A->getParent());
10460b57cec5SDimitry Andric }
10470b57cec5SDimitry Andric }
10480b57cec5SDimitry Andric }
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric
10510b57cec5SDimitry Andric /// Tests whether a function is "malloc-like".
10520b57cec5SDimitry Andric ///
10530b57cec5SDimitry Andric /// A function is "malloc-like" if it returns either null or a pointer that
10540b57cec5SDimitry Andric /// doesn't alias any other pointer visible to the caller.
isFunctionMallocLike(Function * F,const SCCNodeSet & SCCNodes)10550b57cec5SDimitry Andric static bool isFunctionMallocLike(Function *F, const SCCNodeSet &SCCNodes) {
10560b57cec5SDimitry Andric SmallSetVector<Value *, 8> FlowsToReturn;
10570b57cec5SDimitry Andric for (BasicBlock &BB : *F)
10580b57cec5SDimitry Andric if (ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
10590b57cec5SDimitry Andric FlowsToReturn.insert(Ret->getReturnValue());
10600b57cec5SDimitry Andric
10610b57cec5SDimitry Andric for (unsigned i = 0; i != FlowsToReturn.size(); ++i) {
10620b57cec5SDimitry Andric Value *RetVal = FlowsToReturn[i];
10630b57cec5SDimitry Andric
10640b57cec5SDimitry Andric if (Constant *C = dyn_cast<Constant>(RetVal)) {
10650b57cec5SDimitry Andric if (!C->isNullValue() && !isa<UndefValue>(C))
10660b57cec5SDimitry Andric return false;
10670b57cec5SDimitry Andric
10680b57cec5SDimitry Andric continue;
10690b57cec5SDimitry Andric }
10700b57cec5SDimitry Andric
10710b57cec5SDimitry Andric if (isa<Argument>(RetVal))
10720b57cec5SDimitry Andric return false;
10730b57cec5SDimitry Andric
10740b57cec5SDimitry Andric if (Instruction *RVI = dyn_cast<Instruction>(RetVal))
10750b57cec5SDimitry Andric switch (RVI->getOpcode()) {
10760b57cec5SDimitry Andric // Extend the analysis by looking upwards.
10770b57cec5SDimitry Andric case Instruction::BitCast:
10780b57cec5SDimitry Andric case Instruction::GetElementPtr:
10790b57cec5SDimitry Andric case Instruction::AddrSpaceCast:
10800b57cec5SDimitry Andric FlowsToReturn.insert(RVI->getOperand(0));
10810b57cec5SDimitry Andric continue;
10820b57cec5SDimitry Andric case Instruction::Select: {
10830b57cec5SDimitry Andric SelectInst *SI = cast<SelectInst>(RVI);
10840b57cec5SDimitry Andric FlowsToReturn.insert(SI->getTrueValue());
10850b57cec5SDimitry Andric FlowsToReturn.insert(SI->getFalseValue());
10860b57cec5SDimitry Andric continue;
10870b57cec5SDimitry Andric }
10880b57cec5SDimitry Andric case Instruction::PHI: {
10890b57cec5SDimitry Andric PHINode *PN = cast<PHINode>(RVI);
10900b57cec5SDimitry Andric for (Value *IncValue : PN->incoming_values())
10910b57cec5SDimitry Andric FlowsToReturn.insert(IncValue);
10920b57cec5SDimitry Andric continue;
10930b57cec5SDimitry Andric }
10940b57cec5SDimitry Andric
10950b57cec5SDimitry Andric // Check whether the pointer came from an allocation.
10960b57cec5SDimitry Andric case Instruction::Alloca:
10970b57cec5SDimitry Andric break;
10980b57cec5SDimitry Andric case Instruction::Call:
10990b57cec5SDimitry Andric case Instruction::Invoke: {
11005ffd83dbSDimitry Andric CallBase &CB = cast<CallBase>(*RVI);
11015ffd83dbSDimitry Andric if (CB.hasRetAttr(Attribute::NoAlias))
11020b57cec5SDimitry Andric break;
11035ffd83dbSDimitry Andric if (CB.getCalledFunction() && SCCNodes.count(CB.getCalledFunction()))
11040b57cec5SDimitry Andric break;
1105bdd1243dSDimitry Andric [[fallthrough]];
11060b57cec5SDimitry Andric }
11070b57cec5SDimitry Andric default:
11080b57cec5SDimitry Andric return false; // Did not come from an allocation.
11090b57cec5SDimitry Andric }
11100b57cec5SDimitry Andric
11110b57cec5SDimitry Andric if (PointerMayBeCaptured(RetVal, false, /*StoreCaptures=*/false))
11120b57cec5SDimitry Andric return false;
11130b57cec5SDimitry Andric }
11140b57cec5SDimitry Andric
11150b57cec5SDimitry Andric return true;
11160b57cec5SDimitry Andric }
11170b57cec5SDimitry Andric
11180b57cec5SDimitry Andric /// Deduce noalias attributes for the SCC.
addNoAliasAttrs(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1119349cc55cSDimitry Andric static void addNoAliasAttrs(const SCCNodeSet &SCCNodes,
1120349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
11210b57cec5SDimitry Andric // Check each function in turn, determining which functions return noalias
11220b57cec5SDimitry Andric // pointers.
11230b57cec5SDimitry Andric for (Function *F : SCCNodes) {
11240b57cec5SDimitry Andric // Already noalias.
11250b57cec5SDimitry Andric if (F->returnDoesNotAlias())
11260b57cec5SDimitry Andric continue;
11270b57cec5SDimitry Andric
11280b57cec5SDimitry Andric // We can infer and propagate function attributes only when we know that the
11290b57cec5SDimitry Andric // definition we'll get at link time is *exactly* the definition we see now.
11300b57cec5SDimitry Andric // For more details, see GlobalValue::mayBeDerefined.
11310b57cec5SDimitry Andric if (!F->hasExactDefinition())
1132349cc55cSDimitry Andric return;
11330b57cec5SDimitry Andric
11340b57cec5SDimitry Andric // We annotate noalias return values, which are only applicable to
11350b57cec5SDimitry Andric // pointer types.
11360b57cec5SDimitry Andric if (!F->getReturnType()->isPointerTy())
11370b57cec5SDimitry Andric continue;
11380b57cec5SDimitry Andric
11390b57cec5SDimitry Andric if (!isFunctionMallocLike(F, SCCNodes))
1140349cc55cSDimitry Andric return;
11410b57cec5SDimitry Andric }
11420b57cec5SDimitry Andric
11430b57cec5SDimitry Andric for (Function *F : SCCNodes) {
11440b57cec5SDimitry Andric if (F->returnDoesNotAlias() ||
11450b57cec5SDimitry Andric !F->getReturnType()->isPointerTy())
11460b57cec5SDimitry Andric continue;
11470b57cec5SDimitry Andric
11480b57cec5SDimitry Andric F->setReturnDoesNotAlias();
11490b57cec5SDimitry Andric ++NumNoAlias;
1150349cc55cSDimitry Andric Changed.insert(F);
11510b57cec5SDimitry Andric }
11520b57cec5SDimitry Andric }
11530b57cec5SDimitry Andric
11540b57cec5SDimitry Andric /// Tests whether this function is known to not return null.
11550b57cec5SDimitry Andric ///
11560b57cec5SDimitry Andric /// Requires that the function returns a pointer.
11570b57cec5SDimitry Andric ///
11580b57cec5SDimitry Andric /// Returns true if it believes the function will not return a null, and sets
11590b57cec5SDimitry Andric /// \p Speculative based on whether the returned conclusion is a speculative
11600b57cec5SDimitry Andric /// conclusion due to SCC calls.
isReturnNonNull(Function * F,const SCCNodeSet & SCCNodes,bool & Speculative)11610b57cec5SDimitry Andric static bool isReturnNonNull(Function *F, const SCCNodeSet &SCCNodes,
11620b57cec5SDimitry Andric bool &Speculative) {
11630b57cec5SDimitry Andric assert(F->getReturnType()->isPointerTy() &&
11640b57cec5SDimitry Andric "nonnull only meaningful on pointer types");
11650b57cec5SDimitry Andric Speculative = false;
11660b57cec5SDimitry Andric
11670b57cec5SDimitry Andric SmallSetVector<Value *, 8> FlowsToReturn;
11680b57cec5SDimitry Andric for (BasicBlock &BB : *F)
11690b57cec5SDimitry Andric if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
11700b57cec5SDimitry Andric FlowsToReturn.insert(Ret->getReturnValue());
11710b57cec5SDimitry Andric
1172*0fca6ea1SDimitry Andric auto &DL = F->getDataLayout();
11730b57cec5SDimitry Andric
11740b57cec5SDimitry Andric for (unsigned i = 0; i != FlowsToReturn.size(); ++i) {
11750b57cec5SDimitry Andric Value *RetVal = FlowsToReturn[i];
11760b57cec5SDimitry Andric
11770b57cec5SDimitry Andric // If this value is locally known to be non-null, we're good
11780b57cec5SDimitry Andric if (isKnownNonZero(RetVal, DL))
11790b57cec5SDimitry Andric continue;
11800b57cec5SDimitry Andric
11810b57cec5SDimitry Andric // Otherwise, we need to look upwards since we can't make any local
11820b57cec5SDimitry Andric // conclusions.
11830b57cec5SDimitry Andric Instruction *RVI = dyn_cast<Instruction>(RetVal);
11840b57cec5SDimitry Andric if (!RVI)
11850b57cec5SDimitry Andric return false;
11860b57cec5SDimitry Andric switch (RVI->getOpcode()) {
11870b57cec5SDimitry Andric // Extend the analysis by looking upwards.
11880b57cec5SDimitry Andric case Instruction::BitCast:
11890b57cec5SDimitry Andric case Instruction::AddrSpaceCast:
11900b57cec5SDimitry Andric FlowsToReturn.insert(RVI->getOperand(0));
11910b57cec5SDimitry Andric continue;
11923a079333SDimitry Andric case Instruction::GetElementPtr:
11933a079333SDimitry Andric if (cast<GEPOperator>(RVI)->isInBounds()) {
11943a079333SDimitry Andric FlowsToReturn.insert(RVI->getOperand(0));
11953a079333SDimitry Andric continue;
11963a079333SDimitry Andric }
11973a079333SDimitry Andric return false;
11980b57cec5SDimitry Andric case Instruction::Select: {
11990b57cec5SDimitry Andric SelectInst *SI = cast<SelectInst>(RVI);
12000b57cec5SDimitry Andric FlowsToReturn.insert(SI->getTrueValue());
12010b57cec5SDimitry Andric FlowsToReturn.insert(SI->getFalseValue());
12020b57cec5SDimitry Andric continue;
12030b57cec5SDimitry Andric }
12040b57cec5SDimitry Andric case Instruction::PHI: {
12050b57cec5SDimitry Andric PHINode *PN = cast<PHINode>(RVI);
12060b57cec5SDimitry Andric for (int i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
12070b57cec5SDimitry Andric FlowsToReturn.insert(PN->getIncomingValue(i));
12080b57cec5SDimitry Andric continue;
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric case Instruction::Call:
12110b57cec5SDimitry Andric case Instruction::Invoke: {
12125ffd83dbSDimitry Andric CallBase &CB = cast<CallBase>(*RVI);
12135ffd83dbSDimitry Andric Function *Callee = CB.getCalledFunction();
12140b57cec5SDimitry Andric // A call to a node within the SCC is assumed to return null until
12150b57cec5SDimitry Andric // proven otherwise
12160b57cec5SDimitry Andric if (Callee && SCCNodes.count(Callee)) {
12170b57cec5SDimitry Andric Speculative = true;
12180b57cec5SDimitry Andric continue;
12190b57cec5SDimitry Andric }
12200b57cec5SDimitry Andric return false;
12210b57cec5SDimitry Andric }
12220b57cec5SDimitry Andric default:
12230b57cec5SDimitry Andric return false; // Unknown source, may be null
12240b57cec5SDimitry Andric };
12250b57cec5SDimitry Andric llvm_unreachable("should have either continued or returned");
12260b57cec5SDimitry Andric }
12270b57cec5SDimitry Andric
12280b57cec5SDimitry Andric return true;
12290b57cec5SDimitry Andric }
12300b57cec5SDimitry Andric
12310b57cec5SDimitry Andric /// Deduce nonnull attributes for the SCC.
addNonNullAttrs(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1232349cc55cSDimitry Andric static void addNonNullAttrs(const SCCNodeSet &SCCNodes,
1233349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
12340b57cec5SDimitry Andric // Speculative that all functions in the SCC return only nonnull
12350b57cec5SDimitry Andric // pointers. We may refute this as we analyze functions.
12360b57cec5SDimitry Andric bool SCCReturnsNonNull = true;
12370b57cec5SDimitry Andric
12380b57cec5SDimitry Andric // Check each function in turn, determining which functions return nonnull
12390b57cec5SDimitry Andric // pointers.
12400b57cec5SDimitry Andric for (Function *F : SCCNodes) {
12410b57cec5SDimitry Andric // Already nonnull.
1242349cc55cSDimitry Andric if (F->getAttributes().hasRetAttr(Attribute::NonNull))
12430b57cec5SDimitry Andric continue;
12440b57cec5SDimitry Andric
12450b57cec5SDimitry Andric // We can infer and propagate function attributes only when we know that the
12460b57cec5SDimitry Andric // definition we'll get at link time is *exactly* the definition we see now.
12470b57cec5SDimitry Andric // For more details, see GlobalValue::mayBeDerefined.
12480b57cec5SDimitry Andric if (!F->hasExactDefinition())
1249349cc55cSDimitry Andric return;
12500b57cec5SDimitry Andric
12510b57cec5SDimitry Andric // We annotate nonnull return values, which are only applicable to
12520b57cec5SDimitry Andric // pointer types.
12530b57cec5SDimitry Andric if (!F->getReturnType()->isPointerTy())
12540b57cec5SDimitry Andric continue;
12550b57cec5SDimitry Andric
12560b57cec5SDimitry Andric bool Speculative = false;
12570b57cec5SDimitry Andric if (isReturnNonNull(F, SCCNodes, Speculative)) {
12580b57cec5SDimitry Andric if (!Speculative) {
12590b57cec5SDimitry Andric // Mark the function eagerly since we may discover a function
12600b57cec5SDimitry Andric // which prevents us from speculating about the entire SCC
12610b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Eagerly marking " << F->getName()
12620b57cec5SDimitry Andric << " as nonnull\n");
1263349cc55cSDimitry Andric F->addRetAttr(Attribute::NonNull);
12640b57cec5SDimitry Andric ++NumNonNullReturn;
1265349cc55cSDimitry Andric Changed.insert(F);
12660b57cec5SDimitry Andric }
12670b57cec5SDimitry Andric continue;
12680b57cec5SDimitry Andric }
12690b57cec5SDimitry Andric // At least one function returns something which could be null, can't
12700b57cec5SDimitry Andric // speculate any more.
12710b57cec5SDimitry Andric SCCReturnsNonNull = false;
12720b57cec5SDimitry Andric }
12730b57cec5SDimitry Andric
12740b57cec5SDimitry Andric if (SCCReturnsNonNull) {
12750b57cec5SDimitry Andric for (Function *F : SCCNodes) {
1276349cc55cSDimitry Andric if (F->getAttributes().hasRetAttr(Attribute::NonNull) ||
12770b57cec5SDimitry Andric !F->getReturnType()->isPointerTy())
12780b57cec5SDimitry Andric continue;
12790b57cec5SDimitry Andric
12800b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "SCC marking " << F->getName() << " as nonnull\n");
1281349cc55cSDimitry Andric F->addRetAttr(Attribute::NonNull);
12820b57cec5SDimitry Andric ++NumNonNullReturn;
1283349cc55cSDimitry Andric Changed.insert(F);
12840b57cec5SDimitry Andric }
12850b57cec5SDimitry Andric }
12860b57cec5SDimitry Andric }
12870b57cec5SDimitry Andric
1288647cbc5dSDimitry Andric /// Deduce noundef attributes for the SCC.
addNoUndefAttrs(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1289647cbc5dSDimitry Andric static void addNoUndefAttrs(const SCCNodeSet &SCCNodes,
1290647cbc5dSDimitry Andric SmallSet<Function *, 8> &Changed) {
1291647cbc5dSDimitry Andric // Check each function in turn, determining which functions return noundef
1292647cbc5dSDimitry Andric // values.
1293647cbc5dSDimitry Andric for (Function *F : SCCNodes) {
1294647cbc5dSDimitry Andric // Already noundef.
1295*0fca6ea1SDimitry Andric AttributeList Attrs = F->getAttributes();
1296*0fca6ea1SDimitry Andric if (Attrs.hasRetAttr(Attribute::NoUndef))
1297647cbc5dSDimitry Andric continue;
1298647cbc5dSDimitry Andric
1299647cbc5dSDimitry Andric // We can infer and propagate function attributes only when we know that the
1300647cbc5dSDimitry Andric // definition we'll get at link time is *exactly* the definition we see now.
1301647cbc5dSDimitry Andric // For more details, see GlobalValue::mayBeDerefined.
1302647cbc5dSDimitry Andric if (!F->hasExactDefinition())
1303647cbc5dSDimitry Andric return;
1304647cbc5dSDimitry Andric
1305647cbc5dSDimitry Andric // MemorySanitizer assumes that the definition and declaration of a
1306647cbc5dSDimitry Andric // function will be consistent. A function with sanitize_memory attribute
1307647cbc5dSDimitry Andric // should be skipped from inference.
1308647cbc5dSDimitry Andric if (F->hasFnAttribute(Attribute::SanitizeMemory))
1309647cbc5dSDimitry Andric continue;
1310647cbc5dSDimitry Andric
1311647cbc5dSDimitry Andric if (F->getReturnType()->isVoidTy())
1312647cbc5dSDimitry Andric continue;
1313647cbc5dSDimitry Andric
1314*0fca6ea1SDimitry Andric const DataLayout &DL = F->getDataLayout();
1315*0fca6ea1SDimitry Andric if (all_of(*F, [&](BasicBlock &BB) {
1316647cbc5dSDimitry Andric if (auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) {
1317647cbc5dSDimitry Andric // TODO: perform context-sensitive analysis?
1318*0fca6ea1SDimitry Andric Value *RetVal = Ret->getReturnValue();
1319*0fca6ea1SDimitry Andric if (!isGuaranteedNotToBeUndefOrPoison(RetVal))
1320*0fca6ea1SDimitry Andric return false;
1321*0fca6ea1SDimitry Andric
1322*0fca6ea1SDimitry Andric // We know the original return value is not poison now, but it
1323*0fca6ea1SDimitry Andric // could still be converted to poison by another return attribute.
1324*0fca6ea1SDimitry Andric // Try to explicitly re-prove the relevant attributes.
1325*0fca6ea1SDimitry Andric if (Attrs.hasRetAttr(Attribute::NonNull) &&
1326*0fca6ea1SDimitry Andric !isKnownNonZero(RetVal, DL))
1327*0fca6ea1SDimitry Andric return false;
1328*0fca6ea1SDimitry Andric
1329*0fca6ea1SDimitry Andric if (MaybeAlign Align = Attrs.getRetAlignment())
1330*0fca6ea1SDimitry Andric if (RetVal->getPointerAlignment(DL) < *Align)
1331*0fca6ea1SDimitry Andric return false;
1332*0fca6ea1SDimitry Andric
1333*0fca6ea1SDimitry Andric Attribute Attr = Attrs.getRetAttr(Attribute::Range);
1334*0fca6ea1SDimitry Andric if (Attr.isValid() &&
1335*0fca6ea1SDimitry Andric !Attr.getRange().contains(
1336*0fca6ea1SDimitry Andric computeConstantRange(RetVal, /*ForSigned=*/false)))
1337*0fca6ea1SDimitry Andric return false;
1338647cbc5dSDimitry Andric }
1339647cbc5dSDimitry Andric return true;
1340647cbc5dSDimitry Andric })) {
1341647cbc5dSDimitry Andric F->addRetAttr(Attribute::NoUndef);
1342647cbc5dSDimitry Andric ++NumNoUndefReturn;
1343647cbc5dSDimitry Andric Changed.insert(F);
1344647cbc5dSDimitry Andric }
1345647cbc5dSDimitry Andric }
1346647cbc5dSDimitry Andric }
1347647cbc5dSDimitry Andric
13480b57cec5SDimitry Andric namespace {
13490b57cec5SDimitry Andric
13500b57cec5SDimitry Andric /// Collects a set of attribute inference requests and performs them all in one
13510b57cec5SDimitry Andric /// go on a single SCC Node. Inference involves scanning function bodies
13520b57cec5SDimitry Andric /// looking for instructions that violate attribute assumptions.
13530b57cec5SDimitry Andric /// As soon as all the bodies are fine we are free to set the attribute.
13540b57cec5SDimitry Andric /// Customization of inference for individual attributes is performed by
13550b57cec5SDimitry Andric /// providing a handful of predicates for each attribute.
13560b57cec5SDimitry Andric class AttributeInferer {
13570b57cec5SDimitry Andric public:
13580b57cec5SDimitry Andric /// Describes a request for inference of a single attribute.
13590b57cec5SDimitry Andric struct InferenceDescriptor {
13600b57cec5SDimitry Andric
13610b57cec5SDimitry Andric /// Returns true if this function does not have to be handled.
13620b57cec5SDimitry Andric /// General intent for this predicate is to provide an optimization
13630b57cec5SDimitry Andric /// for functions that do not need this attribute inference at all
13640b57cec5SDimitry Andric /// (say, for functions that already have the attribute).
13650b57cec5SDimitry Andric std::function<bool(const Function &)> SkipFunction;
13660b57cec5SDimitry Andric
13670b57cec5SDimitry Andric /// Returns true if this instruction violates attribute assumptions.
13680b57cec5SDimitry Andric std::function<bool(Instruction &)> InstrBreaksAttribute;
13690b57cec5SDimitry Andric
13700b57cec5SDimitry Andric /// Sets the inferred attribute for this function.
13710b57cec5SDimitry Andric std::function<void(Function &)> SetAttribute;
13720b57cec5SDimitry Andric
13730b57cec5SDimitry Andric /// Attribute we derive.
13740b57cec5SDimitry Andric Attribute::AttrKind AKind;
13750b57cec5SDimitry Andric
13760b57cec5SDimitry Andric /// If true, only "exact" definitions can be used to infer this attribute.
13770b57cec5SDimitry Andric /// See GlobalValue::isDefinitionExact.
13780b57cec5SDimitry Andric bool RequiresExactDefinition;
13790b57cec5SDimitry Andric
InferenceDescriptor__anon416db8590711::AttributeInferer::InferenceDescriptor13800b57cec5SDimitry Andric InferenceDescriptor(Attribute::AttrKind AK,
13810b57cec5SDimitry Andric std::function<bool(const Function &)> SkipFunc,
13820b57cec5SDimitry Andric std::function<bool(Instruction &)> InstrScan,
13830b57cec5SDimitry Andric std::function<void(Function &)> SetAttr,
13840b57cec5SDimitry Andric bool ReqExactDef)
13850b57cec5SDimitry Andric : SkipFunction(SkipFunc), InstrBreaksAttribute(InstrScan),
13860b57cec5SDimitry Andric SetAttribute(SetAttr), AKind(AK),
13870b57cec5SDimitry Andric RequiresExactDefinition(ReqExactDef) {}
13880b57cec5SDimitry Andric };
13890b57cec5SDimitry Andric
13900b57cec5SDimitry Andric private:
13910b57cec5SDimitry Andric SmallVector<InferenceDescriptor, 4> InferenceDescriptors;
13920b57cec5SDimitry Andric
13930b57cec5SDimitry Andric public:
registerAttrInference(InferenceDescriptor AttrInference)13940b57cec5SDimitry Andric void registerAttrInference(InferenceDescriptor AttrInference) {
13950b57cec5SDimitry Andric InferenceDescriptors.push_back(AttrInference);
13960b57cec5SDimitry Andric }
13970b57cec5SDimitry Andric
1398349cc55cSDimitry Andric void run(const SCCNodeSet &SCCNodes, SmallSet<Function *, 8> &Changed);
13990b57cec5SDimitry Andric };
14000b57cec5SDimitry Andric
14010b57cec5SDimitry Andric /// Perform all the requested attribute inference actions according to the
14020b57cec5SDimitry Andric /// attribute predicates stored before.
run(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1403349cc55cSDimitry Andric void AttributeInferer::run(const SCCNodeSet &SCCNodes,
1404349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
14050b57cec5SDimitry Andric SmallVector<InferenceDescriptor, 4> InferInSCC = InferenceDescriptors;
14060b57cec5SDimitry Andric // Go through all the functions in SCC and check corresponding attribute
14070b57cec5SDimitry Andric // assumptions for each of them. Attributes that are invalid for this SCC
14080b57cec5SDimitry Andric // will be removed from InferInSCC.
14090b57cec5SDimitry Andric for (Function *F : SCCNodes) {
14100b57cec5SDimitry Andric
14110b57cec5SDimitry Andric // No attributes whose assumptions are still valid - done.
14120b57cec5SDimitry Andric if (InferInSCC.empty())
1413349cc55cSDimitry Andric return;
14140b57cec5SDimitry Andric
14150b57cec5SDimitry Andric // Check if our attributes ever need scanning/can be scanned.
14160b57cec5SDimitry Andric llvm::erase_if(InferInSCC, [F](const InferenceDescriptor &ID) {
14170b57cec5SDimitry Andric if (ID.SkipFunction(*F))
14180b57cec5SDimitry Andric return false;
14190b57cec5SDimitry Andric
14200b57cec5SDimitry Andric // Remove from further inference (invalidate) when visiting a function
14210b57cec5SDimitry Andric // that has no instructions to scan/has an unsuitable definition.
14220b57cec5SDimitry Andric return F->isDeclaration() ||
14230b57cec5SDimitry Andric (ID.RequiresExactDefinition && !F->hasExactDefinition());
14240b57cec5SDimitry Andric });
14250b57cec5SDimitry Andric
14260b57cec5SDimitry Andric // For each attribute still in InferInSCC that doesn't explicitly skip F,
14270b57cec5SDimitry Andric // set up the F instructions scan to verify assumptions of the attribute.
14280b57cec5SDimitry Andric SmallVector<InferenceDescriptor, 4> InferInThisFunc;
14290b57cec5SDimitry Andric llvm::copy_if(
14300b57cec5SDimitry Andric InferInSCC, std::back_inserter(InferInThisFunc),
14310b57cec5SDimitry Andric [F](const InferenceDescriptor &ID) { return !ID.SkipFunction(*F); });
14320b57cec5SDimitry Andric
14330b57cec5SDimitry Andric if (InferInThisFunc.empty())
14340b57cec5SDimitry Andric continue;
14350b57cec5SDimitry Andric
14360b57cec5SDimitry Andric // Start instruction scan.
14370b57cec5SDimitry Andric for (Instruction &I : instructions(*F)) {
14380b57cec5SDimitry Andric llvm::erase_if(InferInThisFunc, [&](const InferenceDescriptor &ID) {
14390b57cec5SDimitry Andric if (!ID.InstrBreaksAttribute(I))
14400b57cec5SDimitry Andric return false;
14410b57cec5SDimitry Andric // Remove attribute from further inference on any other functions
14420b57cec5SDimitry Andric // because attribute assumptions have just been violated.
14430b57cec5SDimitry Andric llvm::erase_if(InferInSCC, [&ID](const InferenceDescriptor &D) {
14440b57cec5SDimitry Andric return D.AKind == ID.AKind;
14450b57cec5SDimitry Andric });
14460b57cec5SDimitry Andric // Remove attribute from the rest of current instruction scan.
14470b57cec5SDimitry Andric return true;
14480b57cec5SDimitry Andric });
14490b57cec5SDimitry Andric
14500b57cec5SDimitry Andric if (InferInThisFunc.empty())
14510b57cec5SDimitry Andric break;
14520b57cec5SDimitry Andric }
14530b57cec5SDimitry Andric }
14540b57cec5SDimitry Andric
14550b57cec5SDimitry Andric if (InferInSCC.empty())
1456349cc55cSDimitry Andric return;
14570b57cec5SDimitry Andric
14580b57cec5SDimitry Andric for (Function *F : SCCNodes)
14590b57cec5SDimitry Andric // At this point InferInSCC contains only functions that were either:
14600b57cec5SDimitry Andric // - explicitly skipped from scan/inference, or
14610b57cec5SDimitry Andric // - verified to have no instructions that break attribute assumptions.
14620b57cec5SDimitry Andric // Hence we just go and force the attribute for all non-skipped functions.
14630b57cec5SDimitry Andric for (auto &ID : InferInSCC) {
14640b57cec5SDimitry Andric if (ID.SkipFunction(*F))
14650b57cec5SDimitry Andric continue;
1466349cc55cSDimitry Andric Changed.insert(F);
14670b57cec5SDimitry Andric ID.SetAttribute(*F);
14680b57cec5SDimitry Andric }
14690b57cec5SDimitry Andric }
14700b57cec5SDimitry Andric
1471e8d8bef9SDimitry Andric struct SCCNodesResult {
1472e8d8bef9SDimitry Andric SCCNodeSet SCCNodes;
1473e8d8bef9SDimitry Andric bool HasUnknownCall;
1474e8d8bef9SDimitry Andric };
1475e8d8bef9SDimitry Andric
14760b57cec5SDimitry Andric } // end anonymous namespace
14770b57cec5SDimitry Andric
14780b57cec5SDimitry Andric /// Helper for non-Convergent inference predicate InstrBreaksAttribute.
InstrBreaksNonConvergent(Instruction & I,const SCCNodeSet & SCCNodes)14790b57cec5SDimitry Andric static bool InstrBreaksNonConvergent(Instruction &I,
14800b57cec5SDimitry Andric const SCCNodeSet &SCCNodes) {
14815ffd83dbSDimitry Andric const CallBase *CB = dyn_cast<CallBase>(&I);
14820b57cec5SDimitry Andric // Breaks non-convergent assumption if CS is a convergent call to a function
14830b57cec5SDimitry Andric // not in the SCC.
14845ffd83dbSDimitry Andric return CB && CB->isConvergent() &&
1485349cc55cSDimitry Andric !SCCNodes.contains(CB->getCalledFunction());
14860b57cec5SDimitry Andric }
14870b57cec5SDimitry Andric
14880b57cec5SDimitry Andric /// Helper for NoUnwind inference predicate InstrBreaksAttribute.
InstrBreaksNonThrowing(Instruction & I,const SCCNodeSet & SCCNodes)14890b57cec5SDimitry Andric static bool InstrBreaksNonThrowing(Instruction &I, const SCCNodeSet &SCCNodes) {
149006c3fb27SDimitry Andric if (!I.mayThrow(/* IncludePhaseOneUnwind */ true))
14910b57cec5SDimitry Andric return false;
14920b57cec5SDimitry Andric if (const auto *CI = dyn_cast<CallInst>(&I)) {
14930b57cec5SDimitry Andric if (Function *Callee = CI->getCalledFunction()) {
14940b57cec5SDimitry Andric // I is a may-throw call to a function inside our SCC. This doesn't
14950b57cec5SDimitry Andric // invalidate our current working assumption that the SCC is no-throw; we
14960b57cec5SDimitry Andric // just have to scan that other function.
1497e8d8bef9SDimitry Andric if (SCCNodes.contains(Callee))
14980b57cec5SDimitry Andric return false;
14990b57cec5SDimitry Andric }
15000b57cec5SDimitry Andric }
15010b57cec5SDimitry Andric return true;
15020b57cec5SDimitry Andric }
15030b57cec5SDimitry Andric
15040b57cec5SDimitry Andric /// Helper for NoFree inference predicate InstrBreaksAttribute.
InstrBreaksNoFree(Instruction & I,const SCCNodeSet & SCCNodes)15050b57cec5SDimitry Andric static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) {
15065ffd83dbSDimitry Andric CallBase *CB = dyn_cast<CallBase>(&I);
15075ffd83dbSDimitry Andric if (!CB)
15080b57cec5SDimitry Andric return false;
15090b57cec5SDimitry Andric
1510fe6060f1SDimitry Andric if (CB->hasFnAttr(Attribute::NoFree))
15110b57cec5SDimitry Andric return false;
15120b57cec5SDimitry Andric
1513fe6060f1SDimitry Andric // Speculatively assume in SCC.
1514fe6060f1SDimitry Andric if (Function *Callee = CB->getCalledFunction())
1515e8d8bef9SDimitry Andric if (SCCNodes.contains(Callee))
15160b57cec5SDimitry Andric return false;
15170b57cec5SDimitry Andric
15180b57cec5SDimitry Andric return true;
15190b57cec5SDimitry Andric }
15200b57cec5SDimitry Andric
152106c3fb27SDimitry Andric // Return true if this is an atomic which has an ordering stronger than
152206c3fb27SDimitry Andric // unordered. Note that this is different than the predicate we use in
152306c3fb27SDimitry Andric // Attributor. Here we chose to be conservative and consider monotonic
152406c3fb27SDimitry Andric // operations potentially synchronizing. We generally don't do much with
152506c3fb27SDimitry Andric // monotonic operations, so this is simply risk reduction.
isOrderedAtomic(Instruction * I)152606c3fb27SDimitry Andric static bool isOrderedAtomic(Instruction *I) {
152706c3fb27SDimitry Andric if (!I->isAtomic())
152806c3fb27SDimitry Andric return false;
152906c3fb27SDimitry Andric
153006c3fb27SDimitry Andric if (auto *FI = dyn_cast<FenceInst>(I))
153106c3fb27SDimitry Andric // All legal orderings for fence are stronger than monotonic.
153206c3fb27SDimitry Andric return FI->getSyncScopeID() != SyncScope::SingleThread;
153306c3fb27SDimitry Andric else if (isa<AtomicCmpXchgInst>(I) || isa<AtomicRMWInst>(I))
153406c3fb27SDimitry Andric return true;
153506c3fb27SDimitry Andric else if (auto *SI = dyn_cast<StoreInst>(I))
153606c3fb27SDimitry Andric return !SI->isUnordered();
153706c3fb27SDimitry Andric else if (auto *LI = dyn_cast<LoadInst>(I))
153806c3fb27SDimitry Andric return !LI->isUnordered();
153906c3fb27SDimitry Andric else {
154006c3fb27SDimitry Andric llvm_unreachable("unknown atomic instruction?");
154106c3fb27SDimitry Andric }
154206c3fb27SDimitry Andric }
154306c3fb27SDimitry Andric
InstrBreaksNoSync(Instruction & I,const SCCNodeSet & SCCNodes)154406c3fb27SDimitry Andric static bool InstrBreaksNoSync(Instruction &I, const SCCNodeSet &SCCNodes) {
154506c3fb27SDimitry Andric // Volatile may synchronize
154606c3fb27SDimitry Andric if (I.isVolatile())
154706c3fb27SDimitry Andric return true;
154806c3fb27SDimitry Andric
154906c3fb27SDimitry Andric // An ordered atomic may synchronize. (See comment about on monotonic.)
155006c3fb27SDimitry Andric if (isOrderedAtomic(&I))
155106c3fb27SDimitry Andric return true;
155206c3fb27SDimitry Andric
155306c3fb27SDimitry Andric auto *CB = dyn_cast<CallBase>(&I);
155406c3fb27SDimitry Andric if (!CB)
155506c3fb27SDimitry Andric // Non call site cases covered by the two checks above
155606c3fb27SDimitry Andric return false;
155706c3fb27SDimitry Andric
155806c3fb27SDimitry Andric if (CB->hasFnAttr(Attribute::NoSync))
155906c3fb27SDimitry Andric return false;
156006c3fb27SDimitry Andric
156106c3fb27SDimitry Andric // Non volatile memset/memcpy/memmoves are nosync
156206c3fb27SDimitry Andric // NOTE: Only intrinsics with volatile flags should be handled here. All
156306c3fb27SDimitry Andric // others should be marked in Intrinsics.td.
156406c3fb27SDimitry Andric if (auto *MI = dyn_cast<MemIntrinsic>(&I))
156506c3fb27SDimitry Andric if (!MI->isVolatile())
156606c3fb27SDimitry Andric return false;
156706c3fb27SDimitry Andric
156806c3fb27SDimitry Andric // Speculatively assume in SCC.
156906c3fb27SDimitry Andric if (Function *Callee = CB->getCalledFunction())
157006c3fb27SDimitry Andric if (SCCNodes.contains(Callee))
157106c3fb27SDimitry Andric return false;
157206c3fb27SDimitry Andric
157306c3fb27SDimitry Andric return true;
157406c3fb27SDimitry Andric }
157506c3fb27SDimitry Andric
1576e8d8bef9SDimitry Andric /// Attempt to remove convergent function attribute when possible.
15770b57cec5SDimitry Andric ///
15780b57cec5SDimitry Andric /// Returns true if any changes to function attributes were made.
inferConvergent(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1579349cc55cSDimitry Andric static void inferConvergent(const SCCNodeSet &SCCNodes,
1580349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
15810b57cec5SDimitry Andric AttributeInferer AI;
15820b57cec5SDimitry Andric
15830b57cec5SDimitry Andric // Request to remove the convergent attribute from all functions in the SCC
15840b57cec5SDimitry Andric // if every callsite within the SCC is not convergent (except for calls
15850b57cec5SDimitry Andric // to functions within the SCC).
15860b57cec5SDimitry Andric // Note: Removal of the attr from the callsites will happen in
15870b57cec5SDimitry Andric // InstCombineCalls separately.
15880b57cec5SDimitry Andric AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
15890b57cec5SDimitry Andric Attribute::Convergent,
15900b57cec5SDimitry Andric // Skip non-convergent functions.
15910b57cec5SDimitry Andric [](const Function &F) { return !F.isConvergent(); },
15920b57cec5SDimitry Andric // Instructions that break non-convergent assumption.
15930b57cec5SDimitry Andric [SCCNodes](Instruction &I) {
15940b57cec5SDimitry Andric return InstrBreaksNonConvergent(I, SCCNodes);
15950b57cec5SDimitry Andric },
15960b57cec5SDimitry Andric [](Function &F) {
15970b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Removing convergent attr from fn " << F.getName()
15980b57cec5SDimitry Andric << "\n");
15990b57cec5SDimitry Andric F.setNotConvergent();
16000b57cec5SDimitry Andric },
16010b57cec5SDimitry Andric /* RequiresExactDefinition= */ false});
1602e8d8bef9SDimitry Andric // Perform all the requested attribute inference actions.
1603349cc55cSDimitry Andric AI.run(SCCNodes, Changed);
1604e8d8bef9SDimitry Andric }
1605e8d8bef9SDimitry Andric
1606e8d8bef9SDimitry Andric /// Infer attributes from all functions in the SCC by scanning every
160706c3fb27SDimitry Andric /// instruction for compliance to the attribute assumptions.
1608e8d8bef9SDimitry Andric ///
1609e8d8bef9SDimitry Andric /// Returns true if any changes to function attributes were made.
inferAttrsFromFunctionBodies(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1610349cc55cSDimitry Andric static void inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes,
1611349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
1612e8d8bef9SDimitry Andric AttributeInferer AI;
16130b57cec5SDimitry Andric
16140b57cec5SDimitry Andric if (!DisableNoUnwindInference)
16150b57cec5SDimitry Andric // Request to infer nounwind attribute for all the functions in the SCC if
16160b57cec5SDimitry Andric // every callsite within the SCC is not throwing (except for calls to
16170b57cec5SDimitry Andric // functions within the SCC). Note that nounwind attribute suffers from
16180b57cec5SDimitry Andric // derefinement - results may change depending on how functions are
16190b57cec5SDimitry Andric // optimized. Thus it can be inferred only from exact definitions.
16200b57cec5SDimitry Andric AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
16210b57cec5SDimitry Andric Attribute::NoUnwind,
16220b57cec5SDimitry Andric // Skip non-throwing functions.
16230b57cec5SDimitry Andric [](const Function &F) { return F.doesNotThrow(); },
16240b57cec5SDimitry Andric // Instructions that break non-throwing assumption.
16255ffd83dbSDimitry Andric [&SCCNodes](Instruction &I) {
16260b57cec5SDimitry Andric return InstrBreaksNonThrowing(I, SCCNodes);
16270b57cec5SDimitry Andric },
16280b57cec5SDimitry Andric [](Function &F) {
16290b57cec5SDimitry Andric LLVM_DEBUG(dbgs()
16300b57cec5SDimitry Andric << "Adding nounwind attr to fn " << F.getName() << "\n");
16310b57cec5SDimitry Andric F.setDoesNotThrow();
16320b57cec5SDimitry Andric ++NumNoUnwind;
16330b57cec5SDimitry Andric },
16340b57cec5SDimitry Andric /* RequiresExactDefinition= */ true});
16350b57cec5SDimitry Andric
16360b57cec5SDimitry Andric if (!DisableNoFreeInference)
16370b57cec5SDimitry Andric // Request to infer nofree attribute for all the functions in the SCC if
16380b57cec5SDimitry Andric // every callsite within the SCC does not directly or indirectly free
16390b57cec5SDimitry Andric // memory (except for calls to functions within the SCC). Note that nofree
16400b57cec5SDimitry Andric // attribute suffers from derefinement - results may change depending on
16410b57cec5SDimitry Andric // how functions are optimized. Thus it can be inferred only from exact
16420b57cec5SDimitry Andric // definitions.
16430b57cec5SDimitry Andric AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
16440b57cec5SDimitry Andric Attribute::NoFree,
16450b57cec5SDimitry Andric // Skip functions known not to free memory.
16460b57cec5SDimitry Andric [](const Function &F) { return F.doesNotFreeMemory(); },
16470b57cec5SDimitry Andric // Instructions that break non-deallocating assumption.
16485ffd83dbSDimitry Andric [&SCCNodes](Instruction &I) {
16490b57cec5SDimitry Andric return InstrBreaksNoFree(I, SCCNodes);
16500b57cec5SDimitry Andric },
16510b57cec5SDimitry Andric [](Function &F) {
16520b57cec5SDimitry Andric LLVM_DEBUG(dbgs()
16530b57cec5SDimitry Andric << "Adding nofree attr to fn " << F.getName() << "\n");
16540b57cec5SDimitry Andric F.setDoesNotFreeMemory();
16550b57cec5SDimitry Andric ++NumNoFree;
16560b57cec5SDimitry Andric },
16570b57cec5SDimitry Andric /* RequiresExactDefinition= */ true});
16580b57cec5SDimitry Andric
165906c3fb27SDimitry Andric AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
166006c3fb27SDimitry Andric Attribute::NoSync,
166106c3fb27SDimitry Andric // Skip already marked functions.
166206c3fb27SDimitry Andric [](const Function &F) { return F.hasNoSync(); },
166306c3fb27SDimitry Andric // Instructions that break nosync assumption.
166406c3fb27SDimitry Andric [&SCCNodes](Instruction &I) {
166506c3fb27SDimitry Andric return InstrBreaksNoSync(I, SCCNodes);
166606c3fb27SDimitry Andric },
166706c3fb27SDimitry Andric [](Function &F) {
166806c3fb27SDimitry Andric LLVM_DEBUG(dbgs()
166906c3fb27SDimitry Andric << "Adding nosync attr to fn " << F.getName() << "\n");
167006c3fb27SDimitry Andric F.setNoSync();
167106c3fb27SDimitry Andric ++NumNoSync;
167206c3fb27SDimitry Andric },
167306c3fb27SDimitry Andric /* RequiresExactDefinition= */ true});
167406c3fb27SDimitry Andric
16750b57cec5SDimitry Andric // Perform all the requested attribute inference actions.
1676349cc55cSDimitry Andric AI.run(SCCNodes, Changed);
16770b57cec5SDimitry Andric }
16780b57cec5SDimitry Andric
addNoRecurseAttrs(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1679349cc55cSDimitry Andric static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
1680349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
16810b57cec5SDimitry Andric // Try and identify functions that do not recurse.
16820b57cec5SDimitry Andric
16830b57cec5SDimitry Andric // If the SCC contains multiple nodes we know for sure there is recursion.
16840b57cec5SDimitry Andric if (SCCNodes.size() != 1)
1685349cc55cSDimitry Andric return;
16860b57cec5SDimitry Andric
16870b57cec5SDimitry Andric Function *F = *SCCNodes.begin();
16880b57cec5SDimitry Andric if (!F || !F->hasExactDefinition() || F->doesNotRecurse())
1689349cc55cSDimitry Andric return;
16900b57cec5SDimitry Andric
16910b57cec5SDimitry Andric // If all of the calls in F are identifiable and are to norecurse functions, F
16920b57cec5SDimitry Andric // is norecurse. This check also detects self-recursion as F is not currently
16930b57cec5SDimitry Andric // marked norecurse, so any called from F to F will not be marked norecurse.
16940b57cec5SDimitry Andric for (auto &BB : *F)
16950b57cec5SDimitry Andric for (auto &I : BB.instructionsWithoutDebug())
16965ffd83dbSDimitry Andric if (auto *CB = dyn_cast<CallBase>(&I)) {
16975ffd83dbSDimitry Andric Function *Callee = CB->getCalledFunction();
1698647cbc5dSDimitry Andric if (!Callee || Callee == F ||
1699647cbc5dSDimitry Andric (!Callee->doesNotRecurse() &&
1700647cbc5dSDimitry Andric !(Callee->isDeclaration() &&
1701647cbc5dSDimitry Andric Callee->hasFnAttribute(Attribute::NoCallback))))
17020b57cec5SDimitry Andric // Function calls a potentially recursive function.
1703349cc55cSDimitry Andric return;
17040b57cec5SDimitry Andric }
17050b57cec5SDimitry Andric
17060b57cec5SDimitry Andric // Every call was to a non-recursive function other than this function, and
17070b57cec5SDimitry Andric // we have no indirect recursion as the SCC size is one. This function cannot
17080b57cec5SDimitry Andric // recurse.
1709e8d8bef9SDimitry Andric F->setDoesNotRecurse();
1710e8d8bef9SDimitry Andric ++NumNoRecurse;
1711349cc55cSDimitry Andric Changed.insert(F);
1712e8d8bef9SDimitry Andric }
1713e8d8bef9SDimitry Andric
instructionDoesNotReturn(Instruction & I)1714e8d8bef9SDimitry Andric static bool instructionDoesNotReturn(Instruction &I) {
1715fe6060f1SDimitry Andric if (auto *CB = dyn_cast<CallBase>(&I))
1716fe6060f1SDimitry Andric return CB->hasFnAttr(Attribute::NoReturn);
1717e8d8bef9SDimitry Andric return false;
1718e8d8bef9SDimitry Andric }
1719e8d8bef9SDimitry Andric
1720e8d8bef9SDimitry Andric // A basic block can only return if it terminates with a ReturnInst and does not
1721e8d8bef9SDimitry Andric // contain calls to noreturn functions.
basicBlockCanReturn(BasicBlock & BB)1722e8d8bef9SDimitry Andric static bool basicBlockCanReturn(BasicBlock &BB) {
1723e8d8bef9SDimitry Andric if (!isa<ReturnInst>(BB.getTerminator()))
1724e8d8bef9SDimitry Andric return false;
1725e8d8bef9SDimitry Andric return none_of(BB, instructionDoesNotReturn);
1726e8d8bef9SDimitry Andric }
1727e8d8bef9SDimitry Andric
1728d781ede6SDimitry Andric // FIXME: this doesn't handle recursion.
canReturn(Function & F)1729d781ede6SDimitry Andric static bool canReturn(Function &F) {
1730d781ede6SDimitry Andric SmallVector<BasicBlock *, 16> Worklist;
1731d781ede6SDimitry Andric SmallPtrSet<BasicBlock *, 16> Visited;
1732d781ede6SDimitry Andric
1733d781ede6SDimitry Andric Visited.insert(&F.front());
1734d781ede6SDimitry Andric Worklist.push_back(&F.front());
1735d781ede6SDimitry Andric
1736d781ede6SDimitry Andric do {
1737d781ede6SDimitry Andric BasicBlock *BB = Worklist.pop_back_val();
1738d781ede6SDimitry Andric if (basicBlockCanReturn(*BB))
1739d781ede6SDimitry Andric return true;
1740d781ede6SDimitry Andric for (BasicBlock *Succ : successors(BB))
1741d781ede6SDimitry Andric if (Visited.insert(Succ).second)
1742d781ede6SDimitry Andric Worklist.push_back(Succ);
1743d781ede6SDimitry Andric } while (!Worklist.empty());
1744d781ede6SDimitry Andric
1745d781ede6SDimitry Andric return false;
1746d781ede6SDimitry Andric }
1747d781ede6SDimitry Andric
1748e8d8bef9SDimitry Andric // Set the noreturn function attribute if possible.
addNoReturnAttrs(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1749349cc55cSDimitry Andric static void addNoReturnAttrs(const SCCNodeSet &SCCNodes,
1750349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
1751e8d8bef9SDimitry Andric for (Function *F : SCCNodes) {
1752e8d8bef9SDimitry Andric if (!F || !F->hasExactDefinition() || F->hasFnAttribute(Attribute::Naked) ||
1753e8d8bef9SDimitry Andric F->doesNotReturn())
1754e8d8bef9SDimitry Andric continue;
1755e8d8bef9SDimitry Andric
1756d781ede6SDimitry Andric if (!canReturn(*F)) {
1757e8d8bef9SDimitry Andric F->setDoesNotReturn();
1758349cc55cSDimitry Andric Changed.insert(F);
1759e8d8bef9SDimitry Andric }
1760e8d8bef9SDimitry Andric }
1761e8d8bef9SDimitry Andric }
1762e8d8bef9SDimitry Andric
functionWillReturn(const Function & F)1763e8d8bef9SDimitry Andric static bool functionWillReturn(const Function &F) {
1764fe6060f1SDimitry Andric // We can infer and propagate function attributes only when we know that the
1765fe6060f1SDimitry Andric // definition we'll get at link time is *exactly* the definition we see now.
1766fe6060f1SDimitry Andric // For more details, see GlobalValue::mayBeDerefined.
1767fe6060f1SDimitry Andric if (!F.hasExactDefinition())
1768fe6060f1SDimitry Andric return false;
1769fe6060f1SDimitry Andric
1770e8d8bef9SDimitry Andric // Must-progress function without side-effects must return.
1771e8d8bef9SDimitry Andric if (F.mustProgress() && F.onlyReadsMemory())
1772e8d8bef9SDimitry Andric return true;
1773e8d8bef9SDimitry Andric
1774e8d8bef9SDimitry Andric // Can only analyze functions with a definition.
1775e8d8bef9SDimitry Andric if (F.isDeclaration())
1776e8d8bef9SDimitry Andric return false;
1777e8d8bef9SDimitry Andric
1778e8d8bef9SDimitry Andric // Functions with loops require more sophisticated analysis, as the loop
1779e8d8bef9SDimitry Andric // may be infinite. For now, don't try to handle them.
1780e8d8bef9SDimitry Andric SmallVector<std::pair<const BasicBlock *, const BasicBlock *>> Backedges;
1781e8d8bef9SDimitry Andric FindFunctionBackedges(F, Backedges);
1782e8d8bef9SDimitry Andric if (!Backedges.empty())
1783e8d8bef9SDimitry Andric return false;
1784e8d8bef9SDimitry Andric
1785e8d8bef9SDimitry Andric // If there are no loops, then the function is willreturn if all calls in
1786e8d8bef9SDimitry Andric // it are willreturn.
1787e8d8bef9SDimitry Andric return all_of(instructions(F), [](const Instruction &I) {
1788d409305fSDimitry Andric return I.willReturn();
1789e8d8bef9SDimitry Andric });
1790e8d8bef9SDimitry Andric }
1791e8d8bef9SDimitry Andric
1792e8d8bef9SDimitry Andric // Set the willreturn function attribute if possible.
addWillReturn(const SCCNodeSet & SCCNodes,SmallSet<Function *,8> & Changed)1793349cc55cSDimitry Andric static void addWillReturn(const SCCNodeSet &SCCNodes,
1794349cc55cSDimitry Andric SmallSet<Function *, 8> &Changed) {
1795e8d8bef9SDimitry Andric for (Function *F : SCCNodes) {
1796e8d8bef9SDimitry Andric if (!F || F->willReturn() || !functionWillReturn(*F))
1797e8d8bef9SDimitry Andric continue;
1798e8d8bef9SDimitry Andric
1799e8d8bef9SDimitry Andric F->setWillReturn();
1800e8d8bef9SDimitry Andric NumWillReturn++;
1801349cc55cSDimitry Andric Changed.insert(F);
1802e8d8bef9SDimitry Andric }
1803e8d8bef9SDimitry Andric }
1804e8d8bef9SDimitry Andric
createSCCNodeSet(ArrayRef<Function * > Functions)1805e8d8bef9SDimitry Andric static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
1806e8d8bef9SDimitry Andric SCCNodesResult Res;
1807e8d8bef9SDimitry Andric Res.HasUnknownCall = false;
1808e8d8bef9SDimitry Andric for (Function *F : Functions) {
1809349cc55cSDimitry Andric if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked) ||
1810349cc55cSDimitry Andric F->isPresplitCoroutine()) {
1811e8d8bef9SDimitry Andric // Treat any function we're trying not to optimize as if it were an
1812e8d8bef9SDimitry Andric // indirect call and omit it from the node set used below.
1813e8d8bef9SDimitry Andric Res.HasUnknownCall = true;
1814e8d8bef9SDimitry Andric continue;
1815e8d8bef9SDimitry Andric }
1816e8d8bef9SDimitry Andric // Track whether any functions in this SCC have an unknown call edge.
1817e8d8bef9SDimitry Andric // Note: if this is ever a performance hit, we can common it with
1818e8d8bef9SDimitry Andric // subsequent routines which also do scans over the instructions of the
1819e8d8bef9SDimitry Andric // function.
1820e8d8bef9SDimitry Andric if (!Res.HasUnknownCall) {
1821e8d8bef9SDimitry Andric for (Instruction &I : instructions(*F)) {
1822e8d8bef9SDimitry Andric if (auto *CB = dyn_cast<CallBase>(&I)) {
1823e8d8bef9SDimitry Andric if (!CB->getCalledFunction()) {
1824e8d8bef9SDimitry Andric Res.HasUnknownCall = true;
1825e8d8bef9SDimitry Andric break;
1826e8d8bef9SDimitry Andric }
1827e8d8bef9SDimitry Andric }
1828e8d8bef9SDimitry Andric }
1829e8d8bef9SDimitry Andric }
1830e8d8bef9SDimitry Andric Res.SCCNodes.insert(F);
1831e8d8bef9SDimitry Andric }
1832e8d8bef9SDimitry Andric return Res;
18330b57cec5SDimitry Andric }
18340b57cec5SDimitry Andric
18350b57cec5SDimitry Andric template <typename AARGetterT>
1836349cc55cSDimitry Andric static SmallSet<Function *, 8>
deriveAttrsInPostOrder(ArrayRef<Function * > Functions,AARGetterT && AARGetter,bool ArgAttrsOnly)18375f757f3fSDimitry Andric deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter,
18385f757f3fSDimitry Andric bool ArgAttrsOnly) {
1839e8d8bef9SDimitry Andric SCCNodesResult Nodes = createSCCNodeSet(Functions);
18400b57cec5SDimitry Andric
18410b57cec5SDimitry Andric // Bail if the SCC only contains optnone functions.
1842e8d8bef9SDimitry Andric if (Nodes.SCCNodes.empty())
1843349cc55cSDimitry Andric return {};
18440b57cec5SDimitry Andric
1845349cc55cSDimitry Andric SmallSet<Function *, 8> Changed;
18465f757f3fSDimitry Andric if (ArgAttrsOnly) {
18475f757f3fSDimitry Andric addArgumentAttrs(Nodes.SCCNodes, Changed);
18485f757f3fSDimitry Andric return Changed;
18495f757f3fSDimitry Andric }
1850349cc55cSDimitry Andric
1851349cc55cSDimitry Andric addArgumentReturnedAttrs(Nodes.SCCNodes, Changed);
185281ad6265SDimitry Andric addMemoryAttrs(Nodes.SCCNodes, AARGetter, Changed);
1853349cc55cSDimitry Andric addArgumentAttrs(Nodes.SCCNodes, Changed);
1854349cc55cSDimitry Andric inferConvergent(Nodes.SCCNodes, Changed);
1855349cc55cSDimitry Andric addNoReturnAttrs(Nodes.SCCNodes, Changed);
1856349cc55cSDimitry Andric addWillReturn(Nodes.SCCNodes, Changed);
1857647cbc5dSDimitry Andric addNoUndefAttrs(Nodes.SCCNodes, Changed);
18580b57cec5SDimitry Andric
18590b57cec5SDimitry Andric // If we have no external nodes participating in the SCC, we can deduce some
18600b57cec5SDimitry Andric // more precise attributes as well.
1861e8d8bef9SDimitry Andric if (!Nodes.HasUnknownCall) {
1862349cc55cSDimitry Andric addNoAliasAttrs(Nodes.SCCNodes, Changed);
1863349cc55cSDimitry Andric addNonNullAttrs(Nodes.SCCNodes, Changed);
1864349cc55cSDimitry Andric inferAttrsFromFunctionBodies(Nodes.SCCNodes, Changed);
1865349cc55cSDimitry Andric addNoRecurseAttrs(Nodes.SCCNodes, Changed);
18660b57cec5SDimitry Andric }
18670b57cec5SDimitry Andric
1868fe6060f1SDimitry Andric // Finally, infer the maximal set of attributes from the ones we've inferred
1869fe6060f1SDimitry Andric // above. This is handling the cases where one attribute on a signature
1870fe6060f1SDimitry Andric // implies another, but for implementation reasons the inference rule for
1871fe6060f1SDimitry Andric // the later is missing (or simply less sophisticated).
1872fe6060f1SDimitry Andric for (Function *F : Nodes.SCCNodes)
1873fe6060f1SDimitry Andric if (F)
1874349cc55cSDimitry Andric if (inferAttributesFromOthers(*F))
1875349cc55cSDimitry Andric Changed.insert(F);
1876fe6060f1SDimitry Andric
18770b57cec5SDimitry Andric return Changed;
18780b57cec5SDimitry Andric }
18790b57cec5SDimitry Andric
run(LazyCallGraph::SCC & C,CGSCCAnalysisManager & AM,LazyCallGraph & CG,CGSCCUpdateResult &)18800b57cec5SDimitry Andric PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
18810b57cec5SDimitry Andric CGSCCAnalysisManager &AM,
18820b57cec5SDimitry Andric LazyCallGraph &CG,
18830b57cec5SDimitry Andric CGSCCUpdateResult &) {
188406c3fb27SDimitry Andric // Skip non-recursive functions if requested.
18855f757f3fSDimitry Andric // Only infer argument attributes for non-recursive functions, because
18865f757f3fSDimitry Andric // it can affect optimization behavior in conjunction with noalias.
18875f757f3fSDimitry Andric bool ArgAttrsOnly = false;
188806c3fb27SDimitry Andric if (C.size() == 1 && SkipNonRecursive) {
188906c3fb27SDimitry Andric LazyCallGraph::Node &N = *C.begin();
189006c3fb27SDimitry Andric if (!N->lookup(N))
18915f757f3fSDimitry Andric ArgAttrsOnly = true;
189206c3fb27SDimitry Andric }
189306c3fb27SDimitry Andric
18940b57cec5SDimitry Andric FunctionAnalysisManager &FAM =
18950b57cec5SDimitry Andric AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
18960b57cec5SDimitry Andric
18970b57cec5SDimitry Andric // We pass a lambda into functions to wire them up to the analysis manager
18980b57cec5SDimitry Andric // for getting function analyses.
18990b57cec5SDimitry Andric auto AARGetter = [&](Function &F) -> AAResults & {
19000b57cec5SDimitry Andric return FAM.getResult<AAManager>(F);
19010b57cec5SDimitry Andric };
19020b57cec5SDimitry Andric
1903e8d8bef9SDimitry Andric SmallVector<Function *, 8> Functions;
19040b57cec5SDimitry Andric for (LazyCallGraph::Node &N : C) {
1905e8d8bef9SDimitry Andric Functions.push_back(&N.getFunction());
19060b57cec5SDimitry Andric }
19070b57cec5SDimitry Andric
19085f757f3fSDimitry Andric auto ChangedFunctions =
19095f757f3fSDimitry Andric deriveAttrsInPostOrder(Functions, AARGetter, ArgAttrsOnly);
1910349cc55cSDimitry Andric if (ChangedFunctions.empty())
1911349cc55cSDimitry Andric return PreservedAnalyses::all();
1912349cc55cSDimitry Andric
1913349cc55cSDimitry Andric // Invalidate analyses for modified functions so that we don't have to
1914349cc55cSDimitry Andric // invalidate all analyses for all functions in this SCC.
1915349cc55cSDimitry Andric PreservedAnalyses FuncPA;
1916349cc55cSDimitry Andric // We haven't changed the CFG for modified functions.
1917349cc55cSDimitry Andric FuncPA.preserveSet<CFGAnalyses>();
1918349cc55cSDimitry Andric for (Function *Changed : ChangedFunctions) {
1919349cc55cSDimitry Andric FAM.invalidate(*Changed, FuncPA);
1920349cc55cSDimitry Andric // Also invalidate any direct callers of changed functions since analyses
1921349cc55cSDimitry Andric // may care about attributes of direct callees. For example, MemorySSA cares
1922349cc55cSDimitry Andric // about whether or not a call's callee modifies memory and queries that
1923349cc55cSDimitry Andric // through function attributes.
1924349cc55cSDimitry Andric for (auto *U : Changed->users()) {
1925349cc55cSDimitry Andric if (auto *Call = dyn_cast<CallBase>(U)) {
1926349cc55cSDimitry Andric if (Call->getCalledFunction() == Changed)
1927349cc55cSDimitry Andric FAM.invalidate(*Call->getFunction(), FuncPA);
1928349cc55cSDimitry Andric }
1929349cc55cSDimitry Andric }
1930fe6060f1SDimitry Andric }
19310b57cec5SDimitry Andric
1932349cc55cSDimitry Andric PreservedAnalyses PA;
1933349cc55cSDimitry Andric // We have not added or removed functions.
1934349cc55cSDimitry Andric PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
1935349cc55cSDimitry Andric // We already invalidated all relevant function analyses above.
1936349cc55cSDimitry Andric PA.preserveSet<AllAnalysesOn<Function>>();
1937349cc55cSDimitry Andric return PA;
19380b57cec5SDimitry Andric }
19390b57cec5SDimitry Andric
printPipeline(raw_ostream & OS,function_ref<StringRef (StringRef)> MapClassName2PassName)194006c3fb27SDimitry Andric void PostOrderFunctionAttrsPass::printPipeline(
194106c3fb27SDimitry Andric raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
194206c3fb27SDimitry Andric static_cast<PassInfoMixin<PostOrderFunctionAttrsPass> *>(this)->printPipeline(
194306c3fb27SDimitry Andric OS, MapClassName2PassName);
194406c3fb27SDimitry Andric if (SkipNonRecursive)
19455f757f3fSDimitry Andric OS << "<skip-non-recursive-function-attrs>";
19460b57cec5SDimitry Andric }
19470b57cec5SDimitry Andric
19480b57cec5SDimitry Andric template <typename AARGetterT>
runImpl(CallGraphSCC & SCC,AARGetterT AARGetter)19490b57cec5SDimitry Andric static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) {
1950e8d8bef9SDimitry Andric SmallVector<Function *, 8> Functions;
19510b57cec5SDimitry Andric for (CallGraphNode *I : SCC) {
1952e8d8bef9SDimitry Andric Functions.push_back(I->getFunction());
19530b57cec5SDimitry Andric }
19540b57cec5SDimitry Andric
1955349cc55cSDimitry Andric return !deriveAttrsInPostOrder(Functions, AARGetter).empty();
19560b57cec5SDimitry Andric }
19570b57cec5SDimitry Andric
addNoRecurseAttrsTopDown(Function & F)19580b57cec5SDimitry Andric static bool addNoRecurseAttrsTopDown(Function &F) {
19590b57cec5SDimitry Andric // We check the preconditions for the function prior to calling this to avoid
19600b57cec5SDimitry Andric // the cost of building up a reversible post-order list. We assert them here
19610b57cec5SDimitry Andric // to make sure none of the invariants this relies on were violated.
19620b57cec5SDimitry Andric assert(!F.isDeclaration() && "Cannot deduce norecurse without a definition!");
19630b57cec5SDimitry Andric assert(!F.doesNotRecurse() &&
19640b57cec5SDimitry Andric "This function has already been deduced as norecurs!");
19650b57cec5SDimitry Andric assert(F.hasInternalLinkage() &&
19660b57cec5SDimitry Andric "Can only do top-down deduction for internal linkage functions!");
19670b57cec5SDimitry Andric
19680b57cec5SDimitry Andric // If F is internal and all of its uses are calls from a non-recursive
19690b57cec5SDimitry Andric // functions, then none of its calls could in fact recurse without going
19700b57cec5SDimitry Andric // through a function marked norecurse, and so we can mark this function too
19710b57cec5SDimitry Andric // as norecurse. Note that the uses must actually be calls -- otherwise
19720b57cec5SDimitry Andric // a pointer to this function could be returned from a norecurse function but
19730b57cec5SDimitry Andric // this function could be recursively (indirectly) called. Note that this
19740b57cec5SDimitry Andric // also detects if F is directly recursive as F is not yet marked as
19750b57cec5SDimitry Andric // a norecurse function.
197681ad6265SDimitry Andric for (auto &U : F.uses()) {
197781ad6265SDimitry Andric auto *I = dyn_cast<Instruction>(U.getUser());
19780b57cec5SDimitry Andric if (!I)
19790b57cec5SDimitry Andric return false;
19805ffd83dbSDimitry Andric CallBase *CB = dyn_cast<CallBase>(I);
198181ad6265SDimitry Andric if (!CB || !CB->isCallee(&U) ||
198281ad6265SDimitry Andric !CB->getParent()->getParent()->doesNotRecurse())
19830b57cec5SDimitry Andric return false;
19840b57cec5SDimitry Andric }
1985e8d8bef9SDimitry Andric F.setDoesNotRecurse();
1986e8d8bef9SDimitry Andric ++NumNoRecurse;
1987e8d8bef9SDimitry Andric return true;
19880b57cec5SDimitry Andric }
19890b57cec5SDimitry Andric
deduceFunctionAttributeInRPO(Module & M,LazyCallGraph & CG)199006c3fb27SDimitry Andric static bool deduceFunctionAttributeInRPO(Module &M, LazyCallGraph &CG) {
19910b57cec5SDimitry Andric // We only have a post-order SCC traversal (because SCCs are inherently
19920b57cec5SDimitry Andric // discovered in post-order), so we accumulate them in a vector and then walk
19930b57cec5SDimitry Andric // it in reverse. This is simpler than using the RPO iterator infrastructure
19940b57cec5SDimitry Andric // because we need to combine SCC detection and the PO walk of the call
19950b57cec5SDimitry Andric // graph. We can also cheat egregiously because we're primarily interested in
19960b57cec5SDimitry Andric // synthesizing norecurse and so we can only save the singular SCCs as SCCs
19970b57cec5SDimitry Andric // with multiple functions in them will clearly be recursive.
199806c3fb27SDimitry Andric
19990b57cec5SDimitry Andric SmallVector<Function *, 16> Worklist;
200006c3fb27SDimitry Andric CG.buildRefSCCs();
200106c3fb27SDimitry Andric for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) {
200206c3fb27SDimitry Andric for (LazyCallGraph::SCC &SCC : RC) {
200306c3fb27SDimitry Andric if (SCC.size() != 1)
20040b57cec5SDimitry Andric continue;
200506c3fb27SDimitry Andric Function &F = SCC.begin()->getFunction();
200606c3fb27SDimitry Andric if (!F.isDeclaration() && !F.doesNotRecurse() && F.hasInternalLinkage())
200706c3fb27SDimitry Andric Worklist.push_back(&F);
20080b57cec5SDimitry Andric }
200906c3fb27SDimitry Andric }
20100b57cec5SDimitry Andric bool Changed = false;
20110b57cec5SDimitry Andric for (auto *F : llvm::reverse(Worklist))
20120b57cec5SDimitry Andric Changed |= addNoRecurseAttrsTopDown(*F);
20130b57cec5SDimitry Andric
20140b57cec5SDimitry Andric return Changed;
20150b57cec5SDimitry Andric }
20160b57cec5SDimitry Andric
20170b57cec5SDimitry Andric PreservedAnalyses
run(Module & M,ModuleAnalysisManager & AM)20180b57cec5SDimitry Andric ReversePostOrderFunctionAttrsPass::run(Module &M, ModuleAnalysisManager &AM) {
201906c3fb27SDimitry Andric auto &CG = AM.getResult<LazyCallGraphAnalysis>(M);
20200b57cec5SDimitry Andric
20210b57cec5SDimitry Andric if (!deduceFunctionAttributeInRPO(M, CG))
20220b57cec5SDimitry Andric return PreservedAnalyses::all();
20230b57cec5SDimitry Andric
20240b57cec5SDimitry Andric PreservedAnalyses PA;
202506c3fb27SDimitry Andric PA.preserve<LazyCallGraphAnalysis>();
20260b57cec5SDimitry Andric return PA;
20270b57cec5SDimitry Andric }
2028