69#define DEBUG_TYPE "function-attrs"
71STATISTIC(NumMemoryAttr,
"Number of functions with improved memory attribute");
72STATISTIC(NumNoCapture,
"Number of arguments marked nocapture");
73STATISTIC(NumReturned,
"Number of arguments marked returned");
74STATISTIC(NumReadNoneArg,
"Number of arguments marked readnone");
75STATISTIC(NumReadOnlyArg,
"Number of arguments marked readonly");
76STATISTIC(NumWriteOnlyArg,
"Number of arguments marked writeonly");
77STATISTIC(NumNoAlias,
"Number of function returns marked noalias");
78STATISTIC(NumNonNullReturn,
"Number of function returns marked nonnull");
79STATISTIC(NumNoRecurse,
"Number of functions marked as norecurse");
80STATISTIC(NumNoUnwind,
"Number of functions marked as nounwind");
81STATISTIC(NumNoFree,
"Number of functions marked as nofree");
82STATISTIC(NumWillReturn,
"Number of functions marked as willreturn");
83STATISTIC(NumNoSync,
"Number of functions marked as nosync");
86 "Number of functions marked as norecurse during thinlink");
88 "Number of functions marked as nounwind during thinlink");
92 cl::desc(
"Try to propagate nonnull argument attributes from callsites to "
93 "caller functions."));
97 cl::desc(
"Stop inferring nounwind attribute during function-attrs pass"));
101 cl::desc(
"Stop inferring nofree attribute during function-attrs pass"));
105 cl::desc(
"Don't propagate function-attrs in thinLTO"));
121 assert(!isa<AllocaInst>(UO) &&
122 "Should have been handled by getModRefInfoMask()");
123 if (isa<Argument>(UO)) {
136 for (
const Value *Arg : Call->args()) {
137 if (!Arg->getType()->isPtrOrPtrVectorTy())
158static std::pair<MemoryEffects, MemoryEffects>
160 const SCCNodeSet &SCCNodes) {
174 if (
F.getAttributes().hasAttrSomewhere(Attribute::InAlloca) ||
175 F.getAttributes().hasAttrSomewhere(Attribute::Preallocated))
182 if (
auto *Call = dyn_cast<CallBase>(&
I)) {
188 if (!Call->hasOperandBundles() && Call->getCalledFunction() &&
189 SCCNodes.count(Call->getCalledFunction())) {
192 addArgLocs(RecursiveArgME, Call, ModRefInfo::ModRef, AAR);
206 if (isa<PseudoProbeInst>(
I))
220 if (ArgMR != ModRefInfo::NoModRef)
226 if (
I.mayWriteToMemory())
227 MR |= ModRefInfo::Mod;
228 if (
I.mayReadFromMemory())
229 MR |= ModRefInfo::Ref;
230 if (MR == ModRefInfo::NoModRef)
248 return {OrigME & ME, RecursiveArgME};
257template <
typename AARGetterT>
268 auto [FnME, FnRecursiveArgME] =
271 RecursiveArgME |= FnRecursiveArgME;
279 if (ArgMR != ModRefInfo::NoModRef)
285 if (NewME != OldME) {
287 F->setMemoryEffects(NewME);
301 if (CachedPrevailingSummary.
count(VI))
302 return CachedPrevailingSummary[VI];
344 CachedPrevailingSummary[VI] =
nullptr;
348 for (
const auto &GVS : VI.getSummaryList()) {
354 if (!FS || FS->fflags().HasUnknownCall)
357 const auto &Linkage = GVS->linkage();
362 <<
"ThinLTO FunctionAttrs: Multiple Local Linkage, bailing on "
364 << VI.name() <<
" from " << FS->modulePath() <<
". Previous module "
365 << Local->modulePath() <<
"\n");
370 assert(IsPrevailing(VI.getGUID(), GVS.get()));
377 if (IsPrevailing(VI.getGUID(), GVS.get())) {
389 CachedPrevailingSummary[VI] = Local;
390 }
else if (Prevailing) {
392 CachedPrevailingSummary[VI] = Prevailing;
395 return CachedPrevailingSummary[VI];
408 bool Changed =
false;
410 auto PropagateAttributes = [&](std::vector<ValueInfo> &SCCNodes) {
413 InferredFlags.
NoRecurse = (SCCNodes.size() == 1);
416 for (
auto &V : SCCNodes) {
427 for (
const auto &Callee : CallerSummary->
calls()) {
429 Callee.first, CachedPrevailingSummary, IsPrevailing);
447 for (
auto &V : SCCNodes) {
449 LLVM_DEBUG(
dbgs() <<
"ThinLTO FunctionAttrs: Propagated NoRecurse to "
450 << V.name() <<
"\n");
451 ++NumThinLinkNoRecurse;
455 LLVM_DEBUG(
dbgs() <<
"ThinLTO FunctionAttrs: Propagated NoUnwind to "
456 << V.name() <<
"\n");
457 ++NumThinLinkNoUnwind;
460 for (
const auto &S : V.getSummaryList()) {
461 if (
auto *FS = dyn_cast<FunctionSummary>(S.get())) {
476 std::vector<ValueInfo> Nodes(*
I);
477 PropagateAttributes(Nodes);
487struct ArgumentGraphNode {
495 using ArgumentMapTy = std::map<Argument *, ArgumentGraphNode>;
497 ArgumentMapTy ArgumentMap;
505 ArgumentGraphNode SyntheticRoot;
508 ArgumentGraph() { SyntheticRoot.Definition =
nullptr; }
512 iterator
begin() {
return SyntheticRoot.Uses.begin(); }
513 iterator
end() {
return SyntheticRoot.Uses.end(); }
514 ArgumentGraphNode *getEntryNode() {
return &SyntheticRoot; }
516 ArgumentGraphNode *operator[](
Argument *
A) {
517 ArgumentGraphNode &
Node = ArgumentMap[
A];
519 SyntheticRoot.Uses.push_back(&
Node);
528 ArgumentUsesTracker(
const SCCNodeSet &SCCNodes) : SCCNodes(SCCNodes) {}
533 CallBase *CB = dyn_cast<CallBase>(
U->getUser());
540 if (!
F || !
F->hasExactDefinition() || !SCCNodes.count(
F)) {
559 if (UseIndex >=
F->arg_size()) {
560 assert(
F->isVarArg() &&
"More params than args in non-varargs call");
565 Uses.push_back(&*std::next(
F->arg_begin(), UseIndex));
570 bool Captured =
false;
575 const SCCNodeSet &SCCNodes;
612 if (
A->hasInAllocaAttr() ||
A->hasPreallocatedAttr())
616 bool IsWrite =
false;
618 for (
Use &U :
A->uses()) {
623 while (!Worklist.
empty()) {
624 if (IsWrite && IsRead)
631 switch (
I->getOpcode()) {
632 case Instruction::BitCast:
633 case Instruction::GetElementPtr:
634 case Instruction::PHI:
635 case Instruction::Select:
636 case Instruction::AddrSpaceCast:
638 for (
Use &UU :
I->uses())
639 if (Visited.
insert(&UU).second)
643 case Instruction::Call:
644 case Instruction::Invoke: {
665 if (!
I->getType()->isVoidTy())
666 for (
Use &UU :
I->uses())
667 if (Visited.
insert(&UU).second)
676 SCCNodes.
count(
F->getArg(UseIndex)))
688 }
else if (CB.
hasFnAttr(Attribute::WriteOnly) ||
697 case Instruction::Load:
700 if (cast<LoadInst>(
I)->isVolatile())
706 case Instruction::Store:
707 if (cast<StoreInst>(
I)->getValueOperand() == *U)
713 if (cast<StoreInst>(
I)->isVolatile())
719 case Instruction::ICmp:
720 case Instruction::Ret:
728 if (IsWrite && IsRead)
731 return Attribute::ReadOnly;
733 return Attribute::WriteOnly;
735 return Attribute::ReadNone;
746 if (!
F->hasExactDefinition())
749 if (
F->getReturnType()->isVoidTy())
753 if (
F->getAttributes().hasAttrSomewhere(Attribute::Returned))
756 auto FindRetArg = [&]() ->
Argument * {
759 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) {
763 dyn_cast<Argument>(Ret->getReturnValue()->stripPointerCasts());
764 if (!RetVal || RetVal->getType() !=
F->getReturnType())
769 else if (RetArg != RetVal)
776 if (
Argument *RetArg = FindRetArg()) {
777 RetArg->
addAttr(Attribute::Returned);
792 bool Changed =
false;
803 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
805 for (
auto &CSArg : CalledFunc->args()) {
806 if (!CSArg.hasNonNullAttr(
false))
812 auto *FArg = dyn_cast<Argument>(CB->
getArgOperand(CSArg.getArgNo()));
813 if (FArg && !FArg->hasNonNullAttr()) {
814 FArg->addAttr(Attribute::NonNull);
828 assert((R == Attribute::ReadOnly || R == Attribute::ReadNone ||
829 R == Attribute::WriteOnly)
830 &&
"Must be an access attribute.");
831 assert(
A &&
"Argument must not be null.");
834 if (
A->hasAttribute(R))
839 A->removeAttr(Attribute::WriteOnly);
840 A->removeAttr(Attribute::ReadOnly);
841 A->removeAttr(Attribute::ReadNone);
843 if (R == Attribute::ReadOnly)
845 else if (R == Attribute::WriteOnly)
863 if (!
F->hasExactDefinition())
871 if (
F->onlyReadsMemory() &&
F->doesNotThrow() &&
872 F->getReturnType()->isVoidTy()) {
874 if (
A.getType()->isPointerTy() && !
A.hasNoCaptureAttr()) {
875 A.addAttr(Attribute::NoCapture);
884 if (!
A.getType()->isPointerTy())
886 bool HasNonLocalUses =
false;
887 if (!
A.hasNoCaptureAttr()) {
888 ArgumentUsesTracker Tracker(SCCNodes);
890 if (!Tracker.Captured) {
891 if (Tracker.Uses.empty()) {
893 A.addAttr(Attribute::NoCapture);
900 ArgumentGraphNode *
Node = AG[&
A];
904 HasNonLocalUses =
true;
910 if (!HasNonLocalUses && !
A.onlyReadsMemory()) {
933 const std::vector<ArgumentGraphNode *> &ArgumentSCC = *
I;
934 if (ArgumentSCC.size() == 1) {
935 if (!ArgumentSCC[0]->Definition)
939 if (ArgumentSCC[0]->
Uses.size() == 1 &&
940 ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
941 Argument *
A = ArgumentSCC[0]->Definition;
942 A->addAttr(Attribute::NoCapture);
944 Changed.
insert(
A->getParent());
956 bool SCCCaptured =
false;
957 for (ArgumentGraphNode *
Node : ArgumentSCC) {
958 if (
Node->Uses.empty() && !
Node->Definition->hasNoCaptureAttr()) {
969 for (ArgumentGraphNode *
I : ArgumentSCC) {
970 ArgumentSCCNodes.
insert(
I->Definition);
973 for (ArgumentGraphNode *
N : ArgumentSCC) {
974 for (ArgumentGraphNode *
Use :
N->Uses) {
976 if (
A->hasNoCaptureAttr() || ArgumentSCCNodes.
count(
A))
987 for (ArgumentGraphNode *
N : ArgumentSCC) {
989 A->addAttr(Attribute::NoCapture);
991 Changed.
insert(
A->getParent());
1008 if (
A == Attribute::ReadNone)
1010 if (
B == Attribute::ReadNone)
1016 for (ArgumentGraphNode *
N : ArgumentSCC) {
1019 AccessAttr = meetAccessAttr(AccessAttr, K);
1025 for (ArgumentGraphNode *
N : ArgumentSCC) {
1028 Changed.
insert(
A->getParent());
1041 if (
ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1042 FlowsToReturn.
insert(Ret->getReturnValue());
1044 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1045 Value *RetVal = FlowsToReturn[i];
1047 if (
Constant *
C = dyn_cast<Constant>(RetVal)) {
1048 if (!
C->isNullValue() && !isa<UndefValue>(
C))
1054 if (isa<Argument>(RetVal))
1057 if (
Instruction *RVI = dyn_cast<Instruction>(RetVal))
1058 switch (RVI->getOpcode()) {
1060 case Instruction::BitCast:
1061 case Instruction::GetElementPtr:
1062 case Instruction::AddrSpaceCast:
1063 FlowsToReturn.
insert(RVI->getOperand(0));
1065 case Instruction::Select: {
1067 FlowsToReturn.
insert(SI->getTrueValue());
1068 FlowsToReturn.
insert(SI->getFalseValue());
1071 case Instruction::PHI: {
1072 PHINode *PN = cast<PHINode>(RVI);
1074 FlowsToReturn.
insert(IncValue);
1079 case Instruction::Alloca:
1081 case Instruction::Call:
1082 case Instruction::Invoke: {
1083 CallBase &CB = cast<CallBase>(*RVI);
1108 if (
F->returnDoesNotAlias())
1114 if (!
F->hasExactDefinition())
1119 if (!
F->getReturnType()->isPointerTy())
1127 if (
F->returnDoesNotAlias() ||
1128 !
F->getReturnType()->isPointerTy())
1131 F->setReturnDoesNotAlias();
1145 bool &Speculative) {
1146 assert(
F->getReturnType()->isPointerTy() &&
1147 "nonnull only meaningful on pointer types");
1148 Speculative =
false;
1152 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1153 FlowsToReturn.
insert(Ret->getReturnValue());
1155 auto &
DL =
F->getParent()->getDataLayout();
1157 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1158 Value *RetVal = FlowsToReturn[i];
1171 case Instruction::BitCast:
1172 case Instruction::GetElementPtr:
1173 case Instruction::AddrSpaceCast:
1176 case Instruction::Select: {
1178 FlowsToReturn.
insert(SI->getTrueValue());
1179 FlowsToReturn.
insert(SI->getFalseValue());
1182 case Instruction::PHI: {
1183 PHINode *PN = cast<PHINode>(RVI);
1188 case Instruction::Call:
1189 case Instruction::Invoke: {
1190 CallBase &CB = cast<CallBase>(*RVI);
1194 if (Callee && SCCNodes.count(Callee)) {
1214 bool SCCReturnsNonNull =
true;
1220 if (
F->getAttributes().hasRetAttr(Attribute::NonNull))
1226 if (!
F->hasExactDefinition())
1231 if (!
F->getReturnType()->isPointerTy())
1234 bool Speculative =
false;
1240 <<
" as nonnull\n");
1241 F->addRetAttr(Attribute::NonNull);
1249 SCCReturnsNonNull =
false;
1252 if (SCCReturnsNonNull) {
1254 if (
F->getAttributes().hasRetAttr(Attribute::NonNull) ||
1255 !
F->getReturnType()->isPointerTy())
1258 LLVM_DEBUG(
dbgs() <<
"SCC marking " <<
F->getName() <<
" as nonnull\n");
1259 F->addRetAttr(Attribute::NonNull);
1274class AttributeInferer {
1277 struct InferenceDescriptor {
1289 std::function<void(
Function &)> SetAttribute;
1296 bool RequiresExactDefinition;
1299 std::function<
bool(
const Function &)> SkipFunc,
1301 std::function<
void(
Function &)> SetAttr,
1303 : SkipFunction(SkipFunc), InstrBreaksAttribute(InstrScan),
1304 SetAttribute(SetAttr), AKind(AK),
1305 RequiresExactDefinition(ReqExactDef) {}
1312 void registerAttrInference(InferenceDescriptor AttrInference) {
1313 InferenceDescriptors.
push_back(AttrInference);
1321void AttributeInferer::run(
const SCCNodeSet &SCCNodes,
1330 if (InferInSCC.
empty())
1335 if (
ID.SkipFunction(*
F))
1340 return F->isDeclaration() ||
1341 (
ID.RequiresExactDefinition && !
F->hasExactDefinition());
1348 InferInSCC, std::back_inserter(InferInThisFunc),
1349 [
F](
const InferenceDescriptor &
ID) {
return !
ID.SkipFunction(*
F); });
1351 if (InferInThisFunc.empty())
1357 if (!
ID.InstrBreaksAttribute(
I))
1362 return D.AKind == ID.AKind;
1368 if (InferInThisFunc.empty())
1373 if (InferInSCC.
empty())
1381 for (
auto &
ID : InferInSCC) {
1382 if (
ID.SkipFunction(*
F))
1385 ID.SetAttribute(*
F);
1389struct SCCNodesResult {
1390 SCCNodeSet SCCNodes;
1391 bool HasUnknownCall;
1398 const SCCNodeSet &SCCNodes) {
1399 const CallBase *CB = dyn_cast<CallBase>(&
I);
1408 if (!
I.mayThrow(
true))
1410 if (
const auto *CI = dyn_cast<CallInst>(&
I)) {
1411 if (
Function *Callee = CI->getCalledFunction()) {
1415 if (SCCNodes.contains(Callee))
1433 if (SCCNodes.contains(Callee))
1448 if (
auto *FI = dyn_cast<FenceInst>(
I))
1451 else if (isa<AtomicCmpXchgInst>(
I) || isa<AtomicRMWInst>(
I))
1453 else if (
auto *SI = dyn_cast<StoreInst>(
I))
1454 return !SI->isUnordered();
1455 else if (
auto *LI = dyn_cast<LoadInst>(
I))
1456 return !LI->isUnordered();
1471 auto *CB = dyn_cast<CallBase>(&
I);
1482 if (
auto *
MI = dyn_cast<MemIntrinsic>(&
I))
1483 if (!
MI->isVolatile())
1488 if (SCCNodes.contains(Callee))
1499 AttributeInferer AI;
1506 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1507 Attribute::Convergent,
1509 [](
const Function &
F) {
return !
F.isConvergent(); },
1515 LLVM_DEBUG(
dbgs() <<
"Removing convergent attr from fn " <<
F.getName()
1517 F.setNotConvergent();
1521 AI.run(SCCNodes, Changed);
1530 AttributeInferer AI;
1538 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1539 Attribute::NoUnwind,
1541 [](
const Function &
F) {
return F.doesNotThrow(); },
1548 <<
"Adding nounwind attr to fn " <<
F.getName() <<
"\n");
1549 F.setDoesNotThrow();
1561 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1564 [](
const Function &
F) {
return F.doesNotFreeMemory(); },
1571 <<
"Adding nofree attr to fn " <<
F.getName() <<
"\n");
1572 F.setDoesNotFreeMemory();
1577 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1580 [](
const Function &
F) {
return F.hasNoSync(); },
1587 <<
"Adding nosync attr to fn " <<
F.getName() <<
"\n");
1594 AI.run(SCCNodes, Changed);
1602 if (SCCNodes.size() != 1)
1606 if (!
F || !
F->hasExactDefinition() ||
F->doesNotRecurse())
1613 for (
auto &
I : BB.instructionsWithoutDebug())
1614 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
1616 if (!Callee || Callee ==
F || !Callee->doesNotRecurse())
1624 F->setDoesNotRecurse();
1630 if (
auto *CB = dyn_cast<CallBase>(&
I))
1631 return CB->
hasFnAttr(Attribute::NoReturn);
1656 if (Visited.
insert(Succ).second)
1658 }
while (!Worklist.
empty());
1667 if (!
F || !
F->hasExactDefinition() ||
F->hasFnAttribute(Attribute::Naked) ||
1672 F->setDoesNotReturn();
1682 if (!
F.hasExactDefinition())
1686 if (
F.mustProgress() &&
F.onlyReadsMemory())
1690 if (
F.isDeclaration())
1697 if (!Backedges.
empty())
1703 return I.willReturn();
1722 Res.HasUnknownCall =
false;
1724 if (!
F ||
F->hasOptNone() ||
F->hasFnAttribute(Attribute::Naked) ||
1725 F->isPresplitCoroutine()) {
1728 Res.HasUnknownCall =
true;
1735 if (!Res.HasUnknownCall) {
1737 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
1739 Res.HasUnknownCall =
true;
1745 Res.SCCNodes.insert(
F);
1750template <
typename AARGetterT>
1753 bool ArgAttrsOnly) {
1757 if (Nodes.SCCNodes.empty())
1775 if (!Nodes.HasUnknownCall) {
1801 bool ArgAttrsOnly =
false;
1802 if (
C.size() == 1 && SkipNonRecursive) {
1805 ArgAttrsOnly =
true;
1822 auto ChangedFunctions =
1824 if (ChangedFunctions.empty())
1832 for (
Function *Changed : ChangedFunctions) {
1838 for (
auto *U : Changed->users()) {
1839 if (
auto *Call = dyn_cast<CallBase>(U)) {
1840 if (Call->getCalledFunction() == Changed)
1857 OS, MapClassName2PassName);
1858 if (SkipNonRecursive)
1859 OS <<
"<skip-non-recursive-function-attrs>";
1862template <
typename AARGetterT>
1876 assert(!
F.isDeclaration() &&
"Cannot deduce norecurse without a definition!");
1878 "This function has already been deduced as norecurs!");
1879 assert(
F.hasInternalLinkage() &&
1880 "Can only do top-down deduction for internal linkage functions!");
1890 for (
auto &U :
F.uses()) {
1891 auto *
I = dyn_cast<Instruction>(U.getUser());
1899 F.setDoesNotRecurse();
1917 if (SCC.size() != 1)
1919 Function &
F = SCC.begin()->getFunction();
1920 if (!
F.isDeclaration() && !
F.doesNotRecurse() &&
F.hasInternalLinkage())
1924 bool Changed =
false;
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the simple types necessary to represent the attributes associated with functions a...
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
This header provides classes for managing passes over SCCs of the call graph.
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseMap class.
static bool runImpl(Function &F, const TargetLowering &TLI)
static void addNoReturnAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
static Attribute::AttrKind determinePointerAccessAttrs(Argument *A, const SmallPtrSet< Argument *, 8 > &SCCNodes)
Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
static cl::opt< bool > DisableNoFreeInference("disable-nofree-inference", cl::Hidden, cl::desc("Stop inferring nofree attribute during function-attrs pass"))
static bool addAccessAttr(Argument *A, Attribute::AttrKind R)
static FunctionSummary * calculatePrevailingSummary(ValueInfo VI, DenseMap< ValueInfo, FunctionSummary * > &CachedPrevailingSummary, function_ref< bool(GlobalValue::GUID, const GlobalValueSummary *)> IsPrevailing)
static bool addArgumentAttrsFromCallsites(Function &F)
If a callsite has arguments that are also arguments to the parent function, try to propagate attribut...
static bool isOrderedAtomic(Instruction *I)
static void addArgLocs(MemoryEffects &ME, const CallBase *Call, ModRefInfo ArgMR, AAResults &AAR)
static bool isFunctionMallocLike(Function *F, const SCCNodeSet &SCCNodes)
Tests whether a function is "malloc-like".
static void addArgumentAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
Deduce nocapture attributes for the SCC.
static bool canReturn(Function &F)
static cl::opt< bool > DisableNoUnwindInference("disable-nounwind-inference", cl::Hidden, cl::desc("Stop inferring nounwind attribute during function-attrs pass"))
static void inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
Infer attributes from all functions in the SCC by scanning every instruction for compliance to the at...
static std::pair< MemoryEffects, MemoryEffects > checkFunctionMemoryAccess(Function &F, bool ThisBody, AAResults &AAR, const SCCNodeSet &SCCNodes)
Returns the memory access attribute for function F using AAR for AA results, where SCCNodes is the cu...
static bool InstrBreaksNonThrowing(Instruction &I, const SCCNodeSet &SCCNodes)
Helper for NoUnwind inference predicate InstrBreaksAttribute.
static bool basicBlockCanReturn(BasicBlock &BB)
static bool isReturnNonNull(Function *F, const SCCNodeSet &SCCNodes, bool &Speculative)
Tests whether this function is known to not return null.
static cl::opt< bool > EnableNonnullArgPropagation("enable-nonnull-arg-prop", cl::init(true), cl::Hidden, cl::desc("Try to propagate nonnull argument attributes from callsites to " "caller functions."))
static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter, SmallSet< Function *, 8 > &Changed)
Deduce readonly/readnone/writeonly attributes for the SCC.
static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
static void inferConvergent(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
Attempt to remove convergent function attribute when possible.
static bool InstrBreaksNoSync(Instruction &I, const SCCNodeSet &SCCNodes)
static bool deduceFunctionAttributeInRPO(Module &M, LazyCallGraph &CG)
static SmallSet< Function *, 8 > deriveAttrsInPostOrder(ArrayRef< Function * > Functions, AARGetterT &&AARGetter, bool ArgAttrsOnly)
static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes)
Helper for NoFree inference predicate InstrBreaksAttribute.
static void addNoAliasAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
Deduce noalias attributes for the SCC.
static bool addNoRecurseAttrsTopDown(Function &F)
static bool instructionDoesNotReturn(Instruction &I)
static void addWillReturn(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
static void addLocAccess(MemoryEffects &ME, const MemoryLocation &Loc, ModRefInfo MR, AAResults &AAR)
static cl::opt< bool > DisableThinLTOPropagation("disable-thinlto-funcattrs", cl::init(true), cl::Hidden, cl::desc("Don't propagate function-attrs in thinLTO"))
static SCCNodesResult createSCCNodeSet(ArrayRef< Function * > Functions)
static bool InstrBreaksNonConvergent(Instruction &I, const SCCNodeSet &SCCNodes)
Helper for non-Convergent inference predicate InstrBreaksAttribute.
static void addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
Deduce returned attributes for the SCC.
static bool functionWillReturn(const Function &F)
static void addNonNullAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
Deduce nonnull attributes for the SCC.
Provides passes for computing function attributes based on interprocedural analyses.
Rewrite Partial Register Uses
Select target instructions out of generic instructions
Implements a lazy call graph analysis and related passes for the new pass manager.
This file provides utility analysis objects describing memory locations.
ModuleSummaryIndex.h This file contains the declarations the classes that hold the module index and s...
FunctionAnalysisManager FAM
This header defines various interfaces for pass management in LLVM.
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
This defines the Use class.
A manager for alias analyses.
ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, bool IgnoreLocals=false)
Returns a bitmask that should be unconditionally applied to the ModRef info of a memory location.
MemoryEffects getMemoryEffects(const CallBase *Call)
Return the behavior of the given call site.
This templated class represents "all analyses that operate over <a particular IR unit>" (e....
A container for analyses that lazily runs them and caches their results.
void invalidate(IRUnitT &IR, const PreservedAnalyses &PA)
Invalidate cached analyses for an IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This class represents an incoming formal argument to a Function.
void addAttr(Attribute::AttrKind Kind)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
@ None
No attributes have been set.
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
Represents analyses that only rely on functions' control flow.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
bool doesNotCapture(unsigned OpNo) const
Determine whether this data operand is not captured.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool doesNotAccessMemory(unsigned OpNo) const
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
bool hasRetAttr(Attribute::AttrKind Kind) const
Determine whether the return value has the given attribute.
unsigned getDataOperandNo(Value::const_user_iterator UI) const
Given a value use iterator, return the data operand corresponding to it.
bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const
Return true if the data operand at index i has the attribute A.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
bool onlyReadsMemory(unsigned OpNo) const
Value * getArgOperand(unsigned i) const
bool isConvergent() const
Determine if the invoke is convergent.
unsigned arg_size() const
bool isArgOperand(const Use *U) const
bool hasOperandBundles() const
Return true if this User has any operand bundles.
A node in the call graph for a module.
CallGraphSCC - This is a single SCC that a CallGraphSCCPass is run on.
This is an important base class in LLVM.
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
A proxy from a FunctionAnalysisManager to an SCC.
Function summary information to aid decisions and implementation of importing.
ArrayRef< EdgeTy > calls() const
Return the list of <CalleeValueInfo, CalleeInfo> pairs.
FFlags fflags() const
Get function summary flags.
bool doesNotRecurse() const
Determine if the function is known not to recurse, directly or indirectly.
Function and variable summary information to aid decisions and implementation of importing.
static bool isWeakAnyLinkage(LinkageTypes Linkage)
static bool isLinkOnceAnyLinkage(LinkageTypes Linkage)
static bool isLocalLinkage(LinkageTypes Linkage)
static bool isWeakODRLinkage(LinkageTypes Linkage)
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
static bool isExternalLinkage(LinkageTypes Linkage)
static bool isLinkOnceODRLinkage(LinkageTypes Linkage)
const BasicBlock * getParent() const
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
An analysis pass which computes the call graph for a module.
A node in the call graph.
A RefSCC of the call graph.
An SCC of the call graph.
A lazily constructed view of the call graph of a module.
iterator_range< postorder_ref_scc_iterator > postorder_ref_sccs()
MemoryEffectsBase getWithoutLoc(Location Loc) const
Get new MemoryEffectsBase with NoModRef on the given Loc.
bool doesNotAccessMemory() const
Whether this function accesses no memory.
static MemoryEffectsBase argMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
Create MemoryEffectsBase that can only access argument memory.
static MemoryEffectsBase inaccessibleMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
Create MemoryEffectsBase that can only access inaccessible memory.
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
static MemoryEffectsBase none()
Create MemoryEffectsBase that cannot read or write any memory.
static MemoryEffectsBase unknown()
Create MemoryEffectsBase that can read and write any memory.
Representation for a specific memory location.
static MemoryLocation getBeforeOrAfter(const Value *Ptr, const AAMDNodes &AATags=AAMDNodes())
Return a location that may access any location before or after Ptr, while remaining within the underl...
const Value * Ptr
The address of the start of the location.
static std::optional< MemoryLocation > getOrNone(const Instruction *Inst)
Class to hold module path string table and global value map, and encapsulate methods for operating on...
A Module instance is used to store all the information related to an LLVM module.
op_range incoming_values()
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserveSet()
Mark an analysis set as preserved.
void preserve()
Mark an analysis as preserved.
Return a value (possibly void), from a function.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
This class represents the LLVM 'select' instruction.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
typename SuperClass::iterator iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
LLVM Value Representation.
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Enumerate the SCCs of a directed graph in reverse topological order of the SCC DAG.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
const_iterator end(StringRef path)
Get end iterator over path.
This is an optimization pass for GlobalISel generic memory operations.
bool isKnownNonZero(const Value *V, const DataLayout &DL, unsigned Depth=0, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true)
Return true if the given value is known to be non-zero when defined.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
auto successors(const MachineBasicBlock *BB)
const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=6)
This method strips off any GEP address adjustments and pointer casts from the specified value,...
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
bool thinLTOPropagateFunctionAttrs(ModuleSummaryIndex &Index, function_ref< bool(GlobalValue::GUID, const GlobalValueSummary *)> isPrevailing)
Propagate function attributes for function summaries along the index's callgraph during thinlink.
OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P)
Provide wrappers to std::copy_if which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, bool StoreCaptures, unsigned MaxUsesToExplore=0)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)
Return true if this function can prove that the instruction I will always transfer execution to one o...
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
bool inferAttributesFromOthers(Function &F)
If we can infer one attribute from another on the declaration of a function, explicitly materialize t...
bool isNoModRef(const ModRefInfo MRI)
void FindFunctionBackedges(const Function &F, SmallVectorImpl< std::pair< const BasicBlock *, const BasicBlock * > > &Result)
Analyze the specified function to find all of the loop backedges in the function and return them.
bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
Support structure for SCC passes to communicate updates the call graph back to the CGSCC pass manager...
This callback is used in conjunction with PointerMayBeCaptured.
virtual void tooManyUses()=0
tooManyUses - The depth of traversal has breached a limit.
virtual bool captured(const Use *U)=0
captured - Information about the pointer was captured by the user of use U.
Flags specific to function summaries.
SmallVectorImpl< ArgumentGraphNode * >::iterator ChildIteratorType
static ChildIteratorType child_begin(NodeRef N)
static ChildIteratorType child_end(NodeRef N)
ArgumentGraphNode * NodeRef
static NodeRef getEntryNode(NodeRef A)
static ChildIteratorType nodes_end(ArgumentGraph *AG)
static NodeRef getEntryNode(ArgumentGraph *AG)
static ChildIteratorType nodes_begin(ArgumentGraph *AG)
A CRTP mix-in to automatically provide informational APIs needed for passes.
PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)
Struct that holds a reference to a particular GUID in a global value summary.