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 && !ConstantLength->isNegative())
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)))
911 case Instruction::Load:
914 if (cast<LoadInst>(
I)->isVolatile())
920 case Instruction::Store:
921 if (cast<StoreInst>(
I)->getValueOperand() == *U)
927 if (cast<StoreInst>(
I)->isVolatile())
933 case Instruction::ICmp:
934 case Instruction::Ret:
942 if (IsWrite && IsRead)
945 return Attribute::ReadOnly;
947 return Attribute::WriteOnly;
949 return Attribute::ReadNone;
960 if (!
F->hasExactDefinition())
963 if (
F->getReturnType()->isVoidTy())
967 if (
F->getAttributes().hasAttrSomewhere(Attribute::Returned))
970 auto FindRetArg = [&]() ->
Argument * {
973 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) {
977 dyn_cast<Argument>(Ret->getReturnValue()->stripPointerCasts());
978 if (!RetVal || RetVal->getType() !=
F->getReturnType())
983 else if (RetArg != RetVal)
990 if (
Argument *RetArg = FindRetArg()) {
991 RetArg->
addAttr(Attribute::Returned);
1006 bool Changed =
false;
1017 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
1019 for (
auto &CSArg : CalledFunc->args()) {
1020 if (!CSArg.hasNonNullAttr(
false))
1026 auto *FArg = dyn_cast<Argument>(CB->
getArgOperand(CSArg.getArgNo()));
1027 if (FArg && !FArg->hasNonNullAttr()) {
1028 FArg->addAttr(Attribute::NonNull);
1042 assert((R == Attribute::ReadOnly || R == Attribute::ReadNone ||
1043 R == Attribute::WriteOnly)
1044 &&
"Must be an access attribute.");
1045 assert(
A &&
"Argument must not be null.");
1048 if (
A->hasAttribute(R))
1053 A->removeAttr(Attribute::WriteOnly);
1054 A->removeAttr(Attribute::ReadOnly);
1055 A->removeAttr(Attribute::ReadNone);
1057 if (R == Attribute::ReadNone || R == Attribute::ReadOnly)
1058 A->removeAttr(Attribute::Writable);
1060 if (R == Attribute::ReadOnly)
1062 else if (R == Attribute::WriteOnly)
1070 auto ArgumentUses = collectArgumentUsesPerBlock(
A,
F);
1072 if (!ArgumentUses.HasAnyWrite)
1075 auto &UsesPerBlock = ArgumentUses.UsesPerBlock;
1084 auto UPB = UsesPerBlock.find(BB);
1091 if (UPB == UsesPerBlock.end() || !UPB->second.HasUnknownAccess) {
1092 bool HasAddedSuccessor =
false;
1094 if (
auto SuccI = Initialized.
find(Succ); SuccI != Initialized.
end()) {
1095 if (HasAddedSuccessor) {
1098 CRL = SuccI->second;
1099 HasAddedSuccessor =
true;
1108 if (UPB != UsesPerBlock.end()) {
1112 sort(Insts, [](std::pair<Instruction *, ArgumentAccessInfo> &
LHS,
1113 std::pair<Instruction *, ArgumentAccessInfo> &
RHS) {
1114 return LHS.first->comesBefore(
RHS.first);
1120 if (
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown ||
1121 Info.ArgAccessType ==
1122 ArgumentAccessInfo::AccessType::WriteWithSideEffect)
1124 if (!
Info.AccessRanges.empty()) {
1125 if (
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
1126 Info.ArgAccessType ==
1127 ArgumentAccessInfo::AccessType::WriteWithSideEffect) {
1130 assert(
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Read);
1131 for (
const auto &ReadRange :
Info.AccessRanges)
1143 bool OnlyScanEntryBlock = !ArgumentUses.HasWriteOutsideEntryBB;
1144 if (!OnlyScanEntryBlock)
1145 if (
auto EntryUPB = UsesPerBlock.find(&EntryBB);
1146 EntryUPB != UsesPerBlock.end())
1147 OnlyScanEntryBlock = EntryUPB->second.HasUnknownAccess;
1148 if (OnlyScanEntryBlock) {
1149 EntryCRL = VisitBlock(&EntryBB);
1150 if (EntryCRL.
empty())
1161 Initialized[BB] = CRL;
1164 auto EntryCRLI = Initialized.
find(&EntryBB);
1165 if (EntryCRLI == Initialized.
end())
1168 EntryCRL = EntryCRLI->second;
1172 "should have bailed already if EntryCRL is empty");
1174 if (
A.hasAttribute(Attribute::Initializes)) {
1176 A.getAttribute(Attribute::Initializes).getValueAsConstantRangeList();
1177 if (PreviousCRL == EntryCRL)
1179 EntryCRL = EntryCRL.
unionWith(PreviousCRL);
1191 bool SkipInitializes) {
1200 if (!
F->hasExactDefinition())
1208 if (
F->onlyReadsMemory() &&
F->doesNotThrow() &&
1209 F->getReturnType()->isVoidTy()) {
1211 if (
A.getType()->isPointerTy() && !
A.hasNoCaptureAttr()) {
1212 A.addAttr(Attribute::NoCapture);
1221 if (!
A.getType()->isPointerTy())
1223 bool HasNonLocalUses =
false;
1224 if (!
A.hasNoCaptureAttr()) {
1225 ArgumentUsesTracker Tracker(SCCNodes);
1227 if (!Tracker.Captured) {
1228 if (Tracker.Uses.empty()) {
1230 A.addAttr(Attribute::NoCapture);
1237 ArgumentGraphNode *
Node = AG[&
A];
1239 Node->Uses.push_back(AG[
Use]);
1241 HasNonLocalUses =
true;
1247 if (!HasNonLocalUses && !
A.onlyReadsMemory()) {
1259 if (!SkipInitializes && !
A.onlyReadsMemory()) {
1274 const std::vector<ArgumentGraphNode *> &ArgumentSCC = *
I;
1275 if (ArgumentSCC.size() == 1) {
1276 if (!ArgumentSCC[0]->Definition)
1280 if (ArgumentSCC[0]->
Uses.size() == 1 &&
1281 ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
1282 Argument *
A = ArgumentSCC[0]->Definition;
1283 A->addAttr(Attribute::NoCapture);
1285 Changed.
insert(
A->getParent());
1297 bool SCCCaptured =
false;
1298 for (ArgumentGraphNode *
Node : ArgumentSCC) {
1299 if (
Node->Uses.empty() && !
Node->Definition->hasNoCaptureAttr()) {
1310 for (ArgumentGraphNode *
I : ArgumentSCC) {
1311 ArgumentSCCNodes.
insert(
I->Definition);
1314 for (ArgumentGraphNode *
N : ArgumentSCC) {
1315 for (ArgumentGraphNode *
Use :
N->Uses) {
1317 if (
A->hasNoCaptureAttr() || ArgumentSCCNodes.
count(
A))
1328 for (ArgumentGraphNode *
N : ArgumentSCC) {
1330 A->addAttr(Attribute::NoCapture);
1332 Changed.
insert(
A->getParent());
1349 if (
A == Attribute::ReadNone)
1351 if (
B == Attribute::ReadNone)
1357 for (ArgumentGraphNode *
N : ArgumentSCC) {
1360 AccessAttr = meetAccessAttr(AccessAttr, K);
1366 for (ArgumentGraphNode *
N : ArgumentSCC) {
1369 Changed.
insert(
A->getParent());
1382 if (
ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1383 FlowsToReturn.
insert(Ret->getReturnValue());
1385 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1386 Value *RetVal = FlowsToReturn[i];
1388 if (
Constant *
C = dyn_cast<Constant>(RetVal)) {
1389 if (!
C->isNullValue() && !isa<UndefValue>(
C))
1395 if (isa<Argument>(RetVal))
1398 if (
Instruction *RVI = dyn_cast<Instruction>(RetVal))
1399 switch (RVI->getOpcode()) {
1401 case Instruction::BitCast:
1402 case Instruction::GetElementPtr:
1403 case Instruction::AddrSpaceCast:
1404 FlowsToReturn.
insert(RVI->getOperand(0));
1406 case Instruction::Select: {
1408 FlowsToReturn.
insert(SI->getTrueValue());
1409 FlowsToReturn.
insert(SI->getFalseValue());
1412 case Instruction::PHI: {
1413 PHINode *PN = cast<PHINode>(RVI);
1415 FlowsToReturn.
insert(IncValue);
1420 case Instruction::Alloca:
1422 case Instruction::Call:
1423 case Instruction::Invoke: {
1424 CallBase &CB = cast<CallBase>(*RVI);
1449 if (
F->returnDoesNotAlias())
1455 if (!
F->hasExactDefinition())
1460 if (!
F->getReturnType()->isPointerTy())
1468 if (
F->returnDoesNotAlias() ||
1469 !
F->getReturnType()->isPointerTy())
1472 F->setReturnDoesNotAlias();
1486 bool &Speculative) {
1487 assert(
F->getReturnType()->isPointerTy() &&
1488 "nonnull only meaningful on pointer types");
1489 Speculative =
false;
1493 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1494 FlowsToReturn.
insert(Ret->getReturnValue());
1496 auto &
DL =
F->getDataLayout();
1498 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1499 Value *RetVal = FlowsToReturn[i];
1512 case Instruction::BitCast:
1513 case Instruction::AddrSpaceCast:
1516 case Instruction::GetElementPtr:
1517 if (cast<GEPOperator>(RVI)->isInBounds()) {
1522 case Instruction::Select: {
1524 FlowsToReturn.
insert(SI->getTrueValue());
1525 FlowsToReturn.
insert(SI->getFalseValue());
1528 case Instruction::PHI: {
1529 PHINode *PN = cast<PHINode>(RVI);
1534 case Instruction::Call:
1535 case Instruction::Invoke: {
1536 CallBase &CB = cast<CallBase>(*RVI);
1540 if (Callee && SCCNodes.count(Callee)) {
1560 bool SCCReturnsNonNull =
true;
1566 if (
F->getAttributes().hasRetAttr(Attribute::NonNull))
1572 if (!
F->hasExactDefinition())
1577 if (!
F->getReturnType()->isPointerTy())
1580 bool Speculative =
false;
1586 <<
" as nonnull\n");
1587 F->addRetAttr(Attribute::NonNull);
1595 SCCReturnsNonNull =
false;
1598 if (SCCReturnsNonNull) {
1600 if (
F->getAttributes().hasRetAttr(Attribute::NonNull) ||
1601 !
F->getReturnType()->isPointerTy())
1604 LLVM_DEBUG(
dbgs() <<
"SCC marking " <<
F->getName() <<
" as nonnull\n");
1605 F->addRetAttr(Attribute::NonNull);
1620 if (Attrs.hasRetAttr(Attribute::NoUndef))
1626 if (!
F->hasExactDefinition())
1632 if (
F->hasFnAttribute(Attribute::SanitizeMemory))
1635 if (
F->getReturnType()->isVoidTy())
1642 Value *RetVal = Ret->getReturnValue();
1643 if (!isGuaranteedNotToBeUndefOrPoison(RetVal))
1649 if (Attrs.hasRetAttr(Attribute::NonNull) &&
1650 !isKnownNonZero(RetVal, DL))
1653 if (MaybeAlign Align = Attrs.getRetAlignment())
1654 if (RetVal->getPointerAlignment(DL) < *Align)
1657 Attribute Attr = Attrs.getRetAttr(Attribute::Range);
1658 if (Attr.isValid() &&
1659 !Attr.getRange().contains(
1660 computeConstantRange(RetVal, false)))
1665 F->addRetAttr(Attribute::NoUndef);
1680class AttributeInferer {
1683 struct InferenceDescriptor {
1695 std::function<void(
Function &)> SetAttribute;
1702 bool RequiresExactDefinition;
1705 std::function<
bool(
const Function &)> SkipFunc,
1707 std::function<
void(
Function &)> SetAttr,
1709 : SkipFunction(SkipFunc), InstrBreaksAttribute(InstrScan),
1710 SetAttribute(SetAttr), AKind(AK),
1711 RequiresExactDefinition(ReqExactDef) {}
1718 void registerAttrInference(InferenceDescriptor AttrInference) {
1719 InferenceDescriptors.
push_back(AttrInference);
1727void AttributeInferer::run(
const SCCNodeSet &SCCNodes,
1736 if (InferInSCC.
empty())
1741 if (
ID.SkipFunction(*
F))
1746 return F->isDeclaration() ||
1747 (
ID.RequiresExactDefinition && !
F->hasExactDefinition());
1754 InferInSCC, std::back_inserter(InferInThisFunc),
1755 [
F](
const InferenceDescriptor &
ID) {
return !
ID.SkipFunction(*
F); });
1757 if (InferInThisFunc.empty())
1763 if (!
ID.InstrBreaksAttribute(
I))
1768 return D.AKind == ID.AKind;
1774 if (InferInThisFunc.empty())
1779 if (InferInSCC.
empty())
1787 for (
auto &
ID : InferInSCC) {
1788 if (
ID.SkipFunction(*
F))
1791 ID.SetAttribute(*
F);
1795struct SCCNodesResult {
1796 SCCNodeSet SCCNodes;
1797 bool HasUnknownCall;
1804 const SCCNodeSet &SCCNodes) {
1805 const CallBase *CB = dyn_cast<CallBase>(&
I);
1814 if (!
I.mayThrow(
true))
1816 if (
const auto *CI = dyn_cast<CallInst>(&
I)) {
1817 if (
Function *Callee = CI->getCalledFunction()) {
1821 if (SCCNodes.contains(Callee))
1839 if (SCCNodes.contains(Callee))
1854 if (
auto *FI = dyn_cast<FenceInst>(
I))
1857 else if (isa<AtomicCmpXchgInst>(
I) || isa<AtomicRMWInst>(
I))
1859 else if (
auto *SI = dyn_cast<StoreInst>(
I))
1860 return !SI->isUnordered();
1861 else if (
auto *LI = dyn_cast<LoadInst>(
I))
1862 return !LI->isUnordered();
1877 auto *CB = dyn_cast<CallBase>(&
I);
1888 if (
auto *
MI = dyn_cast<MemIntrinsic>(&
I))
1889 if (!
MI->isVolatile())
1894 if (SCCNodes.contains(Callee))
1905 AttributeInferer AI;
1912 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1913 Attribute::Convergent,
1915 [](
const Function &
F) {
return !
F.isConvergent(); },
1921 LLVM_DEBUG(
dbgs() <<
"Removing convergent attr from fn " <<
F.getName()
1923 F.setNotConvergent();
1927 AI.run(SCCNodes, Changed);
1936 AttributeInferer AI;
1944 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1945 Attribute::NoUnwind,
1947 [](
const Function &
F) {
return F.doesNotThrow(); },
1954 <<
"Adding nounwind attr to fn " <<
F.getName() <<
"\n");
1955 F.setDoesNotThrow();
1967 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1970 [](
const Function &
F) {
return F.doesNotFreeMemory(); },
1977 <<
"Adding nofree attr to fn " <<
F.getName() <<
"\n");
1978 F.setDoesNotFreeMemory();
1983 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1986 [](
const Function &
F) {
return F.hasNoSync(); },
1993 <<
"Adding nosync attr to fn " <<
F.getName() <<
"\n");
2000 AI.run(SCCNodes, Changed);
2008 if (SCCNodes.size() != 1)
2012 if (!
F || !
F->hasExactDefinition() ||
F->doesNotRecurse())
2019 for (
auto &
I : BB.instructionsWithoutDebug())
2020 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
2022 if (!Callee || Callee ==
F ||
2023 (!Callee->doesNotRecurse() &&
2024 !(Callee->isDeclaration() &&
2025 Callee->hasFnAttribute(Attribute::NoCallback))))
2033 F->setDoesNotRecurse();
2039 if (
auto *CB = dyn_cast<CallBase>(&
I))
2040 return CB->
hasFnAttr(Attribute::NoReturn);
2065 if (Visited.
insert(Succ).second)
2067 }
while (!Worklist.
empty());
2077 if (!
F || !
F->hasExactDefinition() ||
F->hasFnAttribute(Attribute::Naked) ||
2082 F->setDoesNotReturn();
2090 ColdPaths[&
F.front()] =
false;
2094 while (!Jobs.
empty()) {
2101 if (
auto *CB = dyn_cast<CallBase>(&
I))
2105 ColdPaths[BB] =
true;
2122 auto [Iter, Inserted] = ColdPaths.
try_emplace(Succ,
false);
2138 if (!
F || !
F->hasExactDefinition() ||
F->hasFnAttribute(Attribute::Naked) ||
2139 F->hasFnAttribute(Attribute::Cold) ||
F->hasFnAttribute(Attribute::Hot))
2144 F->addFnAttr(Attribute::Cold);
2156 if (!
F.hasExactDefinition())
2160 if (
F.mustProgress() &&
F.onlyReadsMemory())
2164 if (
F.isDeclaration())
2171 if (!Backedges.
empty())
2177 return I.willReturn();
2196 Res.HasUnknownCall =
false;
2198 if (!
F ||
F->hasOptNone() ||
F->hasFnAttribute(Attribute::Naked) ||
2199 F->isPresplitCoroutine()) {
2202 Res.HasUnknownCall =
true;
2209 if (!Res.HasUnknownCall) {
2211 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
2213 Res.HasUnknownCall =
true;
2219 Res.SCCNodes.insert(
F);
2224template <
typename AARGetterT>
2227 bool ArgAttrsOnly) {
2231 if (Nodes.SCCNodes.empty())
2254 if (!Nodes.HasUnknownCall) {
2280 bool ArgAttrsOnly =
false;
2281 if (
C.size() == 1 && SkipNonRecursive) {
2284 ArgAttrsOnly =
true;
2301 auto ChangedFunctions =
2303 if (ChangedFunctions.empty())
2311 for (
Function *Changed : ChangedFunctions) {
2317 for (
auto *U : Changed->users()) {
2318 if (
auto *Call = dyn_cast<CallBase>(U)) {
2319 if (Call->getCalledFunction() == Changed)
2336 OS, MapClassName2PassName);
2337 if (SkipNonRecursive)
2338 OS <<
"<skip-non-recursive-function-attrs>";
2341template <
typename AARGetterT>
2355 assert(!
F.isDeclaration() &&
"Cannot deduce norecurse without a definition!");
2357 "This function has already been deduced as norecurs!");
2358 assert(
F.hasInternalLinkage() &&
2359 "Can only do top-down deduction for internal linkage functions!");
2369 for (
auto &U :
F.uses()) {
2370 auto *
I = dyn_cast<Instruction>(U.getUser());
2375 !CB->
getParent()->getParent()->doesNotRecurse())
2378 F.setDoesNotRecurse();
2396 if (SCC.size() != 1)
2398 Function &
F = SCC.begin()->getFunction();
2399 if (!
F.isDeclaration() && !
F.doesNotRecurse() &&
F.hasInternalLinkage())
2403 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 isByValArgument(unsigned ArgNo) const
Determine whether this argument is passed by value.
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 LLVM_LIFETIME_BOUND, Style style=Style::native)
Get begin iterator over path.
const_iterator end(StringRef path LLVM_LIFETIME_BOUND)
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.