71#define DEBUG_TYPE "function-attrs"
73STATISTIC(NumMemoryAttr,
"Number of functions with improved memory attribute");
74STATISTIC(NumNoCapture,
"Number of arguments marked nocapture");
75STATISTIC(NumReturned,
"Number of arguments marked returned");
76STATISTIC(NumReadNoneArg,
"Number of arguments marked readnone");
77STATISTIC(NumReadOnlyArg,
"Number of arguments marked readonly");
78STATISTIC(NumWriteOnlyArg,
"Number of arguments marked writeonly");
79STATISTIC(NumNoAlias,
"Number of function returns marked noalias");
80STATISTIC(NumNonNullReturn,
"Number of function returns marked nonnull");
81STATISTIC(NumNoUndefReturn,
"Number of function returns marked noundef");
82STATISTIC(NumNoRecurse,
"Number of functions marked as norecurse");
83STATISTIC(NumNoUnwind,
"Number of functions marked as nounwind");
84STATISTIC(NumNoFree,
"Number of functions marked as nofree");
85STATISTIC(NumWillReturn,
"Number of functions marked as willreturn");
86STATISTIC(NumNoSync,
"Number of functions marked as nosync");
87STATISTIC(NumCold,
"Number of functions marked as cold");
90 "Number of functions marked as norecurse during thinlink");
92 "Number of functions marked as nounwind during thinlink");
96 cl::desc(
"Try to propagate nonnull argument attributes from callsites to "
97 "caller functions."));
101 cl::desc(
"Stop inferring nounwind attribute during function-attrs pass"));
105 cl::desc(
"Stop inferring nofree attribute during function-attrs pass"));
109 cl::desc(
"Don't propagate function-attrs in thinLTO"));
125 if (isa<AllocaInst>(UO))
127 if (isa<Argument>(UO)) {
140 for (
const Value *Arg : Call->args()) {
141 if (!Arg->getType()->isPtrOrPtrVectorTy())
162static std::pair<MemoryEffects, MemoryEffects>
164 const SCCNodeSet &SCCNodes) {
178 if (
F.getAttributes().hasAttrSomewhere(Attribute::InAlloca) ||
179 F.getAttributes().hasAttrSomewhere(Attribute::Preallocated))
186 if (
auto *Call = dyn_cast<CallBase>(&
I)) {
192 if (!Call->hasOperandBundles() && Call->getCalledFunction() &&
193 SCCNodes.count(Call->getCalledFunction())) {
196 addArgLocs(RecursiveArgME, Call, ModRefInfo::ModRef, AAR);
210 if (isa<PseudoProbeInst>(
I))
224 if (ArgMR != ModRefInfo::NoModRef)
230 if (
I.mayWriteToMemory())
231 MR |= ModRefInfo::Mod;
232 if (
I.mayReadFromMemory())
233 MR |= ModRefInfo::Ref;
234 if (MR == ModRefInfo::NoModRef)
252 return {OrigME & ME, RecursiveArgME};
261template <
typename AARGetterT>
272 auto [FnME, FnRecursiveArgME] =
275 RecursiveArgME |= FnRecursiveArgME;
283 if (ArgMR != ModRefInfo::NoModRef)
289 if (NewME != OldME) {
291 F->setMemoryEffects(NewME);
295 A.removeAttr(Attribute::Writable);
309 if (CachedPrevailingSummary.
count(VI))
310 return CachedPrevailingSummary[VI];
352 CachedPrevailingSummary[VI] =
nullptr;
356 for (
const auto &GVS : VI.getSummaryList()) {
362 if (!FS || FS->fflags().HasUnknownCall)
365 const auto &Linkage = GVS->linkage();
370 <<
"ThinLTO FunctionAttrs: Multiple Local Linkage, bailing on "
372 << VI.name() <<
" from " << FS->modulePath() <<
". Previous module "
373 <<
Local->modulePath() <<
"\n");
378 assert(IsPrevailing(VI.getGUID(), GVS.get()));
385 if (IsPrevailing(VI.getGUID(), GVS.get())) {
397 CachedPrevailingSummary[VI] =
Local;
398 }
else if (Prevailing) {
400 CachedPrevailingSummary[VI] = Prevailing;
403 return CachedPrevailingSummary[VI];
416 bool Changed =
false;
418 auto PropagateAttributes = [&](std::vector<ValueInfo> &SCCNodes) {
421 InferredFlags.
NoRecurse = (SCCNodes.size() == 1);
424 for (
auto &V : SCCNodes) {
435 for (
const auto &Callee : CallerSummary->
calls()) {
437 Callee.first, CachedPrevailingSummary, IsPrevailing);
455 for (
auto &V : SCCNodes) {
457 LLVM_DEBUG(
dbgs() <<
"ThinLTO FunctionAttrs: Propagated NoRecurse to "
458 << V.name() <<
"\n");
459 ++NumThinLinkNoRecurse;
463 LLVM_DEBUG(
dbgs() <<
"ThinLTO FunctionAttrs: Propagated NoUnwind to "
464 << V.name() <<
"\n");
465 ++NumThinLinkNoUnwind;
468 for (
const auto &S : V.getSummaryList()) {
469 if (
auto *FS = dyn_cast<FunctionSummary>(S.get())) {
484 std::vector<ValueInfo> Nodes(*
I);
485 PropagateAttributes(Nodes);
495struct ArgumentGraphNode {
503 using ArgumentMapTy = std::map<Argument *, ArgumentGraphNode>;
505 ArgumentMapTy ArgumentMap;
513 ArgumentGraphNode SyntheticRoot;
516 ArgumentGraph() { SyntheticRoot.Definition =
nullptr; }
520 iterator
begin() {
return SyntheticRoot.Uses.begin(); }
521 iterator
end() {
return SyntheticRoot.Uses.end(); }
522 ArgumentGraphNode *getEntryNode() {
return &SyntheticRoot; }
524 ArgumentGraphNode *operator[](
Argument *
A) {
525 ArgumentGraphNode &
Node = ArgumentMap[
A];
527 SyntheticRoot.Uses.push_back(&
Node);
536 ArgumentUsesTracker(
const SCCNodeSet &SCCNodes) : SCCNodes(SCCNodes) {}
541 CallBase *CB = dyn_cast<CallBase>(
U->getUser());
548 if (!
F || !
F->hasExactDefinition() || !SCCNodes.count(
F)) {
567 if (UseIndex >=
F->arg_size()) {
568 assert(
F->isVarArg() &&
"More params than args in non-varargs call");
573 Uses.push_back(&*std::next(
F->arg_begin(), UseIndex));
578 bool Captured =
false;
583 const SCCNodeSet &SCCNodes;
591 std::optional<int64_t>
Offset;
598struct ArgumentAccessInfo {
600 AccessType ArgAccessType;
605struct UsesPerBlockInfo {
607 bool HasWrites =
false;
608 bool HasUnknownAccess =
false;
612struct ArgumentUsesSummary {
613 bool HasAnyWrite =
false;
614 bool HasWriteOutsideEntryBB =
false;
618ArgumentAccessInfo getArgmentAccessInfo(
const Instruction *
I,
619 const ArgumentUse &ArgUse,
621 auto GetTypeAccessRange =
623 std::optional<int64_t>
Offset) -> std::optional<ConstantRange> {
632 auto GetConstantIntRange =
634 std::optional<int64_t>
Offset) -> std::optional<ConstantRange> {
635 auto *ConstantLength = dyn_cast<ConstantInt>(
Length);
636 if (ConstantLength &&
Offset)
639 APInt(64, *
Offset + ConstantLength->getSExtValue(),
true));
642 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
643 if (
SI->isSimple() && &
SI->getOperandUse(1) == ArgUse.U) {
648 if (
auto TypeAccessRange =
649 GetTypeAccessRange(
SI->getAccessType(), ArgUse.Offset))
650 AccessRanges.
insert(*TypeAccessRange);
651 return {ArgumentAccessInfo::AccessType::Write, std::move(AccessRanges)};
653 }
else if (
auto *LI = dyn_cast<LoadInst>(
I)) {
654 if (LI->isSimple()) {
655 assert(&LI->getOperandUse(0) == ArgUse.U);
659 if (
auto TypeAccessRange =
660 GetTypeAccessRange(LI->getAccessType(), ArgUse.Offset))
661 return {ArgumentAccessInfo::AccessType::Read, {*TypeAccessRange}};
663 }
else if (
auto *MemSet = dyn_cast<MemSetInst>(
I)) {
664 if (!MemSet->isVolatile()) {
666 if (
auto AccessRange =
667 GetConstantIntRange(MemSet->getLength(), ArgUse.Offset))
668 AccessRanges.
insert(*AccessRange);
669 return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
671 }
else if (
auto *MTI = dyn_cast<MemTransferInst>(
I)) {
672 if (!MTI->isVolatile()) {
673 if (&MTI->getOperandUse(0) == ArgUse.U) {
675 if (
auto AccessRange =
676 GetConstantIntRange(MTI->getLength(), ArgUse.Offset))
677 AccessRanges.
insert(*AccessRange);
678 return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
679 }
else if (&MTI->getOperandUse(1) == ArgUse.U) {
680 if (
auto AccessRange =
681 GetConstantIntRange(MTI->getLength(), ArgUse.Offset))
682 return {ArgumentAccessInfo::AccessType::Read, {*AccessRange}};
685 }
else if (
auto *CB = dyn_cast<CallBase>(
I)) {
688 bool IsInitialize = CB->
paramHasAttr(ArgNo, Attribute::Initializes);
693 ? ArgumentAccessInfo::AccessType::Write
694 : ArgumentAccessInfo::AccessType::WriteWithSideEffect;
696 if (IsInitialize && ArgUse.Offset) {
701 CR.getUpper() + *ArgUse.Offset));
702 return {
Access, AccessRanges};
707 return {ArgumentAccessInfo::AccessType::Unknown, {}};
712 auto &
DL =
F.getParent()->getDataLayout();
714 DL.getIndexSizeInBits(
A.getType()->getPointerAddressSpace());
715 ArgumentUsesSummary
Result;
719 for (
Use &U :
A.uses())
725 auto *BB =
I->getParent();
726 auto &BBInfo =
Result.UsesPerBlock[BB];
727 bool AlreadyVisitedInst = BBInfo.Insts.contains(
I);
728 auto &IInfo = BBInfo.Insts[
I];
732 if (AlreadyVisitedInst) {
733 IInfo = {ArgumentAccessInfo::AccessType::Unknown, {}};
734 BBInfo.HasUnknownAccess =
true;
738 IInfo = std::move(Info);
739 BBInfo.HasUnknownAccess |=
740 IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown;
742 (IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
743 IInfo.ArgAccessType ==
744 ArgumentAccessInfo::AccessType::WriteWithSideEffect) &&
745 !IInfo.AccessRanges.empty();
746 BBInfo.HasWrites |= InfoHasWrites;
747 return InfoHasWrites;
752 while (!Worklist.
empty()) {
754 User *
U = ArgUse.U->getUser();
757 if (
auto *
GEP = dyn_cast<GEPOperator>(U)) {
758 std::optional<int64_t> NewOffset = std::nullopt;
762 NewOffset = *ArgUse.Offset +
Offset.getSExtValue();
764 for (
Use &U :
GEP->uses())
769 auto *
I = cast<Instruction>(U);
770 bool HasWrite = UpdateUseInfo(
I, getArgmentAccessInfo(
I, ArgUse,
DL));
772 Result.HasAnyWrite |= HasWrite;
774 if (HasWrite &&
I->getParent() != &EntryBB)
775 Result.HasWriteOutsideEntryBB =
true;
814 if (
A->hasInAllocaAttr() ||
A->hasPreallocatedAttr())
818 bool IsWrite =
false;
820 for (
Use &U :
A->uses()) {
825 while (!Worklist.
empty()) {
826 if (IsWrite && IsRead)
833 switch (
I->getOpcode()) {
834 case Instruction::BitCast:
835 case Instruction::GetElementPtr:
836 case Instruction::PHI:
837 case Instruction::Select:
838 case Instruction::AddrSpaceCast:
840 for (
Use &UU :
I->uses())
841 if (Visited.
insert(&UU).second)
845 case Instruction::Call:
846 case Instruction::Invoke: {
865 if (Visited.
insert(&UU).second)
875 if (!
I->getType()->isVoidTy())
876 for (
Use &UU :
I->uses())
877 if (Visited.
insert(&UU).second)
887 SCCNodes.
count(
F->getArg(UseIndex)))
908 case Instruction::Load:
911 if (cast<LoadInst>(
I)->isVolatile())
917 case Instruction::Store:
918 if (cast<StoreInst>(
I)->getValueOperand() == *U)
924 if (cast<StoreInst>(
I)->isVolatile())
930 case Instruction::ICmp:
931 case Instruction::Ret:
939 if (IsWrite && IsRead)
942 return Attribute::ReadOnly;
944 return Attribute::WriteOnly;
946 return Attribute::ReadNone;
957 if (!
F->hasExactDefinition())
960 if (
F->getReturnType()->isVoidTy())
964 if (
F->getAttributes().hasAttrSomewhere(Attribute::Returned))
967 auto FindRetArg = [&]() ->
Argument * {
970 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) {
974 dyn_cast<Argument>(Ret->getReturnValue()->stripPointerCasts());
975 if (!RetVal || RetVal->getType() !=
F->getReturnType())
980 else if (RetArg != RetVal)
987 if (
Argument *RetArg = FindRetArg()) {
988 RetArg->
addAttr(Attribute::Returned);
1003 bool Changed =
false;
1014 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
1016 for (
auto &CSArg : CalledFunc->args()) {
1017 if (!CSArg.hasNonNullAttr(
false))
1023 auto *FArg = dyn_cast<Argument>(CB->
getArgOperand(CSArg.getArgNo()));
1024 if (FArg && !FArg->hasNonNullAttr()) {
1025 FArg->addAttr(Attribute::NonNull);
1039 assert((R == Attribute::ReadOnly || R == Attribute::ReadNone ||
1040 R == Attribute::WriteOnly)
1041 &&
"Must be an access attribute.");
1042 assert(
A &&
"Argument must not be null.");
1045 if (
A->hasAttribute(R))
1050 A->removeAttr(Attribute::WriteOnly);
1051 A->removeAttr(Attribute::ReadOnly);
1052 A->removeAttr(Attribute::ReadNone);
1054 if (R == Attribute::ReadNone || R == Attribute::ReadOnly)
1055 A->removeAttr(Attribute::Writable);
1057 if (R == Attribute::ReadOnly)
1059 else if (R == Attribute::WriteOnly)
1067 auto ArgumentUses = collectArgumentUsesPerBlock(
A,
F);
1069 if (!ArgumentUses.HasAnyWrite)
1072 auto &UsesPerBlock = ArgumentUses.UsesPerBlock;
1081 auto UPB = UsesPerBlock.find(BB);
1088 if (UPB == UsesPerBlock.end() || !UPB->second.HasUnknownAccess) {
1089 bool HasAddedSuccessor =
false;
1091 if (
auto SuccI = Initialized.
find(Succ); SuccI != Initialized.
end()) {
1092 if (HasAddedSuccessor) {
1095 CRL = SuccI->second;
1096 HasAddedSuccessor =
true;
1105 if (UPB != UsesPerBlock.end()) {
1109 sort(Insts, [](std::pair<Instruction *, ArgumentAccessInfo> &
LHS,
1110 std::pair<Instruction *, ArgumentAccessInfo> &
RHS) {
1111 return LHS.first->comesBefore(
RHS.first);
1117 if (
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown ||
1118 Info.ArgAccessType ==
1119 ArgumentAccessInfo::AccessType::WriteWithSideEffect)
1121 if (!
Info.AccessRanges.empty()) {
1122 if (
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
1123 Info.ArgAccessType ==
1124 ArgumentAccessInfo::AccessType::WriteWithSideEffect) {
1127 assert(
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Read);
1128 for (
const auto &ReadRange :
Info.AccessRanges)
1140 bool OnlyScanEntryBlock = !ArgumentUses.HasWriteOutsideEntryBB;
1141 if (!OnlyScanEntryBlock)
1142 if (
auto EntryUPB = UsesPerBlock.find(&EntryBB);
1143 EntryUPB != UsesPerBlock.end())
1144 OnlyScanEntryBlock = EntryUPB->second.HasUnknownAccess;
1145 if (OnlyScanEntryBlock) {
1146 EntryCRL = VisitBlock(&EntryBB);
1147 if (EntryCRL.
empty())
1158 Initialized[BB] = CRL;
1161 auto EntryCRLI = Initialized.
find(&EntryBB);
1162 if (EntryCRLI == Initialized.
end())
1165 EntryCRL = EntryCRLI->second;
1169 "should have bailed already if EntryCRL is empty");
1171 if (
A.hasAttribute(Attribute::Initializes)) {
1173 A.getAttribute(Attribute::Initializes).getValueAsConstantRangeList();
1174 if (PreviousCRL == EntryCRL)
1176 EntryCRL = EntryCRL.
unionWith(PreviousCRL);
1188 bool SkipInitializes) {
1197 if (!
F->hasExactDefinition())
1205 if (
F->onlyReadsMemory() &&
F->doesNotThrow() &&
1206 F->getReturnType()->isVoidTy()) {
1208 if (
A.getType()->isPointerTy() && !
A.hasNoCaptureAttr()) {
1209 A.addAttr(Attribute::NoCapture);
1218 if (!
A.getType()->isPointerTy())
1220 bool HasNonLocalUses =
false;
1221 if (!
A.hasNoCaptureAttr()) {
1222 ArgumentUsesTracker Tracker(SCCNodes);
1224 if (!Tracker.Captured) {
1225 if (Tracker.Uses.empty()) {
1227 A.addAttr(Attribute::NoCapture);
1234 ArgumentGraphNode *
Node = AG[&
A];
1236 Node->Uses.push_back(AG[
Use]);
1238 HasNonLocalUses =
true;
1244 if (!HasNonLocalUses && !
A.onlyReadsMemory()) {
1256 if (!SkipInitializes && !
A.onlyReadsMemory()) {
1271 const std::vector<ArgumentGraphNode *> &ArgumentSCC = *
I;
1272 if (ArgumentSCC.size() == 1) {
1273 if (!ArgumentSCC[0]->Definition)
1277 if (ArgumentSCC[0]->
Uses.size() == 1 &&
1278 ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
1279 Argument *
A = ArgumentSCC[0]->Definition;
1280 A->addAttr(Attribute::NoCapture);
1282 Changed.
insert(
A->getParent());
1294 bool SCCCaptured =
false;
1295 for (ArgumentGraphNode *
Node : ArgumentSCC) {
1296 if (
Node->Uses.empty() && !
Node->Definition->hasNoCaptureAttr()) {
1307 for (ArgumentGraphNode *
I : ArgumentSCC) {
1308 ArgumentSCCNodes.
insert(
I->Definition);
1311 for (ArgumentGraphNode *
N : ArgumentSCC) {
1312 for (ArgumentGraphNode *
Use :
N->Uses) {
1314 if (
A->hasNoCaptureAttr() || ArgumentSCCNodes.
count(
A))
1325 for (ArgumentGraphNode *
N : ArgumentSCC) {
1327 A->addAttr(Attribute::NoCapture);
1329 Changed.
insert(
A->getParent());
1346 if (
A == Attribute::ReadNone)
1348 if (
B == Attribute::ReadNone)
1354 for (ArgumentGraphNode *
N : ArgumentSCC) {
1357 AccessAttr = meetAccessAttr(AccessAttr, K);
1363 for (ArgumentGraphNode *
N : ArgumentSCC) {
1366 Changed.
insert(
A->getParent());
1379 if (
ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1380 FlowsToReturn.
insert(Ret->getReturnValue());
1382 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1383 Value *RetVal = FlowsToReturn[i];
1385 if (
Constant *
C = dyn_cast<Constant>(RetVal)) {
1386 if (!
C->isNullValue() && !isa<UndefValue>(
C))
1392 if (isa<Argument>(RetVal))
1395 if (
Instruction *RVI = dyn_cast<Instruction>(RetVal))
1396 switch (RVI->getOpcode()) {
1398 case Instruction::BitCast:
1399 case Instruction::GetElementPtr:
1400 case Instruction::AddrSpaceCast:
1401 FlowsToReturn.
insert(RVI->getOperand(0));
1403 case Instruction::Select: {
1405 FlowsToReturn.
insert(SI->getTrueValue());
1406 FlowsToReturn.
insert(SI->getFalseValue());
1409 case Instruction::PHI: {
1410 PHINode *PN = cast<PHINode>(RVI);
1412 FlowsToReturn.
insert(IncValue);
1417 case Instruction::Alloca:
1419 case Instruction::Call:
1420 case Instruction::Invoke: {
1421 CallBase &CB = cast<CallBase>(*RVI);
1446 if (
F->returnDoesNotAlias())
1452 if (!
F->hasExactDefinition())
1457 if (!
F->getReturnType()->isPointerTy())
1465 if (
F->returnDoesNotAlias() ||
1466 !
F->getReturnType()->isPointerTy())
1469 F->setReturnDoesNotAlias();
1483 bool &Speculative) {
1484 assert(
F->getReturnType()->isPointerTy() &&
1485 "nonnull only meaningful on pointer types");
1486 Speculative =
false;
1490 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1491 FlowsToReturn.
insert(Ret->getReturnValue());
1493 auto &
DL =
F->getDataLayout();
1495 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1496 Value *RetVal = FlowsToReturn[i];
1509 case Instruction::BitCast:
1510 case Instruction::AddrSpaceCast:
1513 case Instruction::GetElementPtr:
1514 if (cast<GEPOperator>(RVI)->isInBounds()) {
1519 case Instruction::Select: {
1521 FlowsToReturn.
insert(SI->getTrueValue());
1522 FlowsToReturn.
insert(SI->getFalseValue());
1525 case Instruction::PHI: {
1526 PHINode *PN = cast<PHINode>(RVI);
1531 case Instruction::Call:
1532 case Instruction::Invoke: {
1533 CallBase &CB = cast<CallBase>(*RVI);
1537 if (Callee && SCCNodes.count(Callee)) {
1557 bool SCCReturnsNonNull =
true;
1563 if (
F->getAttributes().hasRetAttr(Attribute::NonNull))
1569 if (!
F->hasExactDefinition())
1574 if (!
F->getReturnType()->isPointerTy())
1577 bool Speculative =
false;
1583 <<
" as nonnull\n");
1584 F->addRetAttr(Attribute::NonNull);
1592 SCCReturnsNonNull =
false;
1595 if (SCCReturnsNonNull) {
1597 if (
F->getAttributes().hasRetAttr(Attribute::NonNull) ||
1598 !
F->getReturnType()->isPointerTy())
1601 LLVM_DEBUG(
dbgs() <<
"SCC marking " <<
F->getName() <<
" as nonnull\n");
1602 F->addRetAttr(Attribute::NonNull);
1617 if (Attrs.hasRetAttr(Attribute::NoUndef))
1623 if (!
F->hasExactDefinition())
1629 if (
F->hasFnAttribute(Attribute::SanitizeMemory))
1632 if (
F->getReturnType()->isVoidTy())
1639 Value *RetVal = Ret->getReturnValue();
1640 if (!isGuaranteedNotToBeUndefOrPoison(RetVal))
1646 if (Attrs.hasRetAttr(Attribute::NonNull) &&
1647 !isKnownNonZero(RetVal, DL))
1650 if (MaybeAlign Align = Attrs.getRetAlignment())
1651 if (RetVal->getPointerAlignment(DL) < *Align)
1654 Attribute Attr = Attrs.getRetAttr(Attribute::Range);
1655 if (Attr.isValid() &&
1656 !Attr.getRange().contains(
1657 computeConstantRange(RetVal, false)))
1662 F->addRetAttr(Attribute::NoUndef);
1677class AttributeInferer {
1680 struct InferenceDescriptor {
1692 std::function<void(
Function &)> SetAttribute;
1699 bool RequiresExactDefinition;
1702 std::function<
bool(
const Function &)> SkipFunc,
1704 std::function<
void(
Function &)> SetAttr,
1706 : SkipFunction(SkipFunc), InstrBreaksAttribute(InstrScan),
1707 SetAttribute(SetAttr), AKind(AK),
1708 RequiresExactDefinition(ReqExactDef) {}
1715 void registerAttrInference(InferenceDescriptor AttrInference) {
1716 InferenceDescriptors.
push_back(AttrInference);
1724void AttributeInferer::run(
const SCCNodeSet &SCCNodes,
1733 if (InferInSCC.
empty())
1738 if (
ID.SkipFunction(*
F))
1743 return F->isDeclaration() ||
1744 (
ID.RequiresExactDefinition && !
F->hasExactDefinition());
1751 InferInSCC, std::back_inserter(InferInThisFunc),
1752 [
F](
const InferenceDescriptor &
ID) {
return !
ID.SkipFunction(*
F); });
1754 if (InferInThisFunc.empty())
1760 if (!
ID.InstrBreaksAttribute(
I))
1765 return D.AKind == ID.AKind;
1771 if (InferInThisFunc.empty())
1776 if (InferInSCC.
empty())
1784 for (
auto &
ID : InferInSCC) {
1785 if (
ID.SkipFunction(*
F))
1788 ID.SetAttribute(*
F);
1792struct SCCNodesResult {
1793 SCCNodeSet SCCNodes;
1794 bool HasUnknownCall;
1801 const SCCNodeSet &SCCNodes) {
1802 const CallBase *CB = dyn_cast<CallBase>(&
I);
1811 if (!
I.mayThrow(
true))
1813 if (
const auto *CI = dyn_cast<CallInst>(&
I)) {
1814 if (
Function *Callee = CI->getCalledFunction()) {
1818 if (SCCNodes.contains(Callee))
1836 if (SCCNodes.contains(Callee))
1851 if (
auto *FI = dyn_cast<FenceInst>(
I))
1854 else if (isa<AtomicCmpXchgInst>(
I) || isa<AtomicRMWInst>(
I))
1856 else if (
auto *SI = dyn_cast<StoreInst>(
I))
1857 return !SI->isUnordered();
1858 else if (
auto *LI = dyn_cast<LoadInst>(
I))
1859 return !LI->isUnordered();
1874 auto *CB = dyn_cast<CallBase>(&
I);
1885 if (
auto *
MI = dyn_cast<MemIntrinsic>(&
I))
1886 if (!
MI->isVolatile())
1891 if (SCCNodes.contains(Callee))
1902 AttributeInferer AI;
1909 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1910 Attribute::Convergent,
1912 [](
const Function &
F) {
return !
F.isConvergent(); },
1918 LLVM_DEBUG(
dbgs() <<
"Removing convergent attr from fn " <<
F.getName()
1920 F.setNotConvergent();
1924 AI.run(SCCNodes, Changed);
1933 AttributeInferer AI;
1941 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1942 Attribute::NoUnwind,
1944 [](
const Function &
F) {
return F.doesNotThrow(); },
1951 <<
"Adding nounwind attr to fn " <<
F.getName() <<
"\n");
1952 F.setDoesNotThrow();
1964 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1967 [](
const Function &
F) {
return F.doesNotFreeMemory(); },
1974 <<
"Adding nofree attr to fn " <<
F.getName() <<
"\n");
1975 F.setDoesNotFreeMemory();
1980 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1983 [](
const Function &
F) {
return F.hasNoSync(); },
1990 <<
"Adding nosync attr to fn " <<
F.getName() <<
"\n");
1997 AI.run(SCCNodes, Changed);
2005 if (SCCNodes.size() != 1)
2009 if (!
F || !
F->hasExactDefinition() ||
F->doesNotRecurse())
2016 for (
auto &
I : BB.instructionsWithoutDebug())
2017 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
2019 if (!Callee || Callee ==
F ||
2020 (!Callee->doesNotRecurse() &&
2021 !(Callee->isDeclaration() &&
2022 Callee->hasFnAttribute(Attribute::NoCallback))))
2030 F->setDoesNotRecurse();
2036 if (
auto *CB = dyn_cast<CallBase>(&
I))
2037 return CB->
hasFnAttr(Attribute::NoReturn);
2062 if (Visited.
insert(Succ).second)
2064 }
while (!Worklist.
empty());
2074 if (!
F || !
F->hasExactDefinition() ||
F->hasFnAttribute(Attribute::Naked) ||
2079 F->setDoesNotReturn();
2087 ColdPaths[&
F.front()] =
false;
2091 while (!Jobs.
empty()) {
2098 if (
auto *CB = dyn_cast<CallBase>(&
I))
2102 ColdPaths[BB] =
true;
2119 auto [Iter, Inserted] = ColdPaths.
try_emplace(Succ,
false);
2135 if (!
F || !
F->hasExactDefinition() ||
F->hasFnAttribute(Attribute::Naked) ||
2136 F->hasFnAttribute(Attribute::Cold) ||
F->hasFnAttribute(Attribute::Hot))
2141 F->addFnAttr(Attribute::Cold);
2153 if (!
F.hasExactDefinition())
2157 if (
F.mustProgress() &&
F.onlyReadsMemory())
2161 if (
F.isDeclaration())
2168 if (!Backedges.
empty())
2174 return I.willReturn();
2193 Res.HasUnknownCall =
false;
2195 if (!
F ||
F->hasOptNone() ||
F->hasFnAttribute(Attribute::Naked) ||
2196 F->isPresplitCoroutine()) {
2199 Res.HasUnknownCall =
true;
2206 if (!Res.HasUnknownCall) {
2208 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
2210 Res.HasUnknownCall =
true;
2216 Res.SCCNodes.insert(
F);
2221template <
typename AARGetterT>
2224 bool ArgAttrsOnly) {
2228 if (Nodes.SCCNodes.empty())
2251 if (!Nodes.HasUnknownCall) {
2277 bool ArgAttrsOnly =
false;
2278 if (
C.size() == 1 && SkipNonRecursive) {
2281 ArgAttrsOnly =
true;
2298 auto ChangedFunctions =
2300 if (ChangedFunctions.empty())
2308 for (
Function *Changed : ChangedFunctions) {
2314 for (
auto *U : Changed->users()) {
2315 if (
auto *Call = dyn_cast<CallBase>(U)) {
2316 if (Call->getCalledFunction() == Changed)
2333 OS, MapClassName2PassName);
2334 if (SkipNonRecursive)
2335 OS <<
"<skip-non-recursive-function-attrs>";
2338template <
typename AARGetterT>
2352 assert(!
F.isDeclaration() &&
"Cannot deduce norecurse without a definition!");
2354 "This function has already been deduced as norecurs!");
2355 assert(
F.hasInternalLinkage() &&
2356 "Can only do top-down deduction for internal linkage functions!");
2366 for (
auto &U :
F.uses()) {
2367 auto *
I = dyn_cast<Instruction>(U.getUser());
2372 !CB->
getParent()->getParent()->doesNotRecurse())
2375 F.setDoesNotRecurse();
2393 if (SCC.size() != 1)
2395 Function &
F = SCC.begin()->getFunction();
2396 if (!
F.isDeclaration() && !
F.doesNotRecurse() &&
F.hasInternalLinkage())
2400 bool Changed =
false;
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
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.
Analysis containing CSE Info
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 inferInitializes(Argument &A, Function &F)
static bool allPathsGoThroughCold(Function &F)
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 void addNoUndefAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
Deduce noundef attributes for the SCC.
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 bool canReturn(Function &F)
static void addArgumentAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed, bool SkipInitializes)
Deduce nocapture attributes for the SCC.
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 void addColdAttrs(const SCCNodeSet &SCCNodes, SmallSet< Function *, 8 > &Changed)
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.
This header defines various interfaces for pass management in LLVM.
This defines the Use class.
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 file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
Remove Loads Into Fake Uses
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)
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.
Class for arbitrary precision integers.
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),...
static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
ArrayRef< ConstantRange > getValueAsConstantRangeList() const
Return the attribute's value as a ConstantRange array.
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 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...
MemoryEffects getMemoryEffects() const
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 paramHasAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Determine whether the argument or parameter has the given attribute.
Attribute getParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) const
Get the attribute of a given kind from a given arg.
bool dataOperandHasImpliedAttr(unsigned i, Attribute::AttrKind Kind) const
Return true if the data operand at index i has the attribute A.
bool onlyWritesMemory(unsigned OpNo) const
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 getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
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 class represents a list of constant ranges.
void subtract(const ConstantRange &SubRange)
void insert(const ConstantRange &NewRange)
Insert a new range to Ranges and keep the list ordered.
bool empty() const
Return true if this list contains no members.
ArrayRef< ConstantRange > rangesRef() const
ConstantRangeList intersectWith(const ConstantRangeList &CRL) const
Return the range list that results from the intersection of this ConstantRangeList with another Const...
ConstantRangeList unionWith(const ConstantRangeList &CRL) const
Return the range list that results from the union of this ConstantRangeList with another ConstantRang...
This class represents a range of values.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
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.
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)
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.
The instances of the Type class are immutable: once they are created, they are never changed.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
LLVM Value Representation.
iterator_range< use_iterator > uses()
constexpr ScalarTy getFixedValue() const
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
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.
constexpr uint64_t PointerSize
aarch64 pointer size.
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 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)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
iterator_range< po_iterator< T > > post_order(const T &G)
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.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
bool isIntrinsicReturningPointerAliasingArgumentWithoutCapturing(const CallBase *Call, bool MustPreserveNullness)
{launder,strip}.invariant.group returns pointer that aliases its argument, and it only captures point...
bool isModSet(const ModRefInfo MRI)
void sort(IteratorTy Start, IteratorTy End)
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.
bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth=0)
Return true if the given value is known to be non-zero when defined.
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
@ ArgMem
Access to memory via argument pointers.
const Value * getUnderlyingObjectAggressive(const Value *V)
Like getUnderlyingObject(), but will try harder to find a single underlying object.
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.
bool isRefSet(const ModRefInfo MRI)
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.