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 &&
637 ConstantLength->getValue().isStrictlyPositive()) {
640 APInt(64, *
Offset + ConstantLength->getSExtValue(),
true));
644 if (
auto *SI = dyn_cast<StoreInst>(
I)) {
645 if (
SI->isSimple() && &
SI->getOperandUse(1) == ArgUse.U) {
650 if (
auto TypeAccessRange =
651 GetTypeAccessRange(
SI->getAccessType(), ArgUse.Offset))
652 AccessRanges.
insert(*TypeAccessRange);
653 return {ArgumentAccessInfo::AccessType::Write, std::move(AccessRanges)};
655 }
else if (
auto *LI = dyn_cast<LoadInst>(
I)) {
656 if (LI->isSimple()) {
657 assert(&LI->getOperandUse(0) == ArgUse.U);
661 if (
auto TypeAccessRange =
662 GetTypeAccessRange(LI->getAccessType(), ArgUse.Offset))
663 return {ArgumentAccessInfo::AccessType::Read, {*TypeAccessRange}};
665 }
else if (
auto *MemSet = dyn_cast<MemSetInst>(
I)) {
666 if (!MemSet->isVolatile()) {
668 if (
auto AccessRange =
669 GetConstantIntRange(MemSet->getLength(), ArgUse.Offset))
670 AccessRanges.
insert(*AccessRange);
671 return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
673 }
else if (
auto *MTI = dyn_cast<MemTransferInst>(
I)) {
674 if (!MTI->isVolatile()) {
675 if (&MTI->getOperandUse(0) == ArgUse.U) {
677 if (
auto AccessRange =
678 GetConstantIntRange(MTI->getLength(), ArgUse.Offset))
679 AccessRanges.
insert(*AccessRange);
680 return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
681 }
else if (&MTI->getOperandUse(1) == ArgUse.U) {
682 if (
auto AccessRange =
683 GetConstantIntRange(MTI->getLength(), ArgUse.Offset))
684 return {ArgumentAccessInfo::AccessType::Read, {*AccessRange}};
687 }
else if (
auto *CB = dyn_cast<CallBase>(
I)) {
691 bool IsInitialize = CB->
paramHasAttr(ArgNo, Attribute::Initializes);
692 if (IsInitialize && ArgUse.Offset) {
696 ? ArgumentAccessInfo::AccessType::Write
697 : ArgumentAccessInfo::AccessType::WriteWithSideEffect;
703 CR.getUpper() + *ArgUse.Offset));
704 return {
Access, AccessRanges};
709 return {ArgumentAccessInfo::AccessType::Unknown, {}};
714 auto &
DL =
F.getParent()->getDataLayout();
716 DL.getIndexSizeInBits(
A.getType()->getPointerAddressSpace());
717 ArgumentUsesSummary
Result;
721 for (
Use &U :
A.uses())
727 auto *BB =
I->getParent();
728 auto &BBInfo =
Result.UsesPerBlock[BB];
729 bool AlreadyVisitedInst = BBInfo.Insts.contains(
I);
730 auto &IInfo = BBInfo.Insts[
I];
734 if (AlreadyVisitedInst) {
735 IInfo = {ArgumentAccessInfo::AccessType::Unknown, {}};
736 BBInfo.HasUnknownAccess =
true;
740 IInfo = std::move(Info);
741 BBInfo.HasUnknownAccess |=
742 IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown;
744 (IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
745 IInfo.ArgAccessType ==
746 ArgumentAccessInfo::AccessType::WriteWithSideEffect) &&
747 !IInfo.AccessRanges.empty();
748 BBInfo.HasWrites |= InfoHasWrites;
749 return InfoHasWrites;
754 while (!Worklist.
empty()) {
756 User *
U = ArgUse.U->getUser();
759 if (
auto *
GEP = dyn_cast<GEPOperator>(U)) {
760 std::optional<int64_t> NewOffset = std::nullopt;
764 NewOffset = *ArgUse.Offset +
Offset.getSExtValue();
766 for (
Use &U :
GEP->uses())
771 auto *
I = cast<Instruction>(U);
772 bool HasWrite = UpdateUseInfo(
I, getArgmentAccessInfo(
I, ArgUse,
DL));
774 Result.HasAnyWrite |= HasWrite;
776 if (HasWrite &&
I->getParent() != &EntryBB)
777 Result.HasWriteOutsideEntryBB =
true;
816 if (
A->hasInAllocaAttr() ||
A->hasPreallocatedAttr())
820 bool IsWrite =
false;
822 for (
Use &U :
A->uses()) {
827 while (!Worklist.
empty()) {
828 if (IsWrite && IsRead)
835 switch (
I->getOpcode()) {
836 case Instruction::BitCast:
837 case Instruction::GetElementPtr:
838 case Instruction::PHI:
839 case Instruction::Select:
840 case Instruction::AddrSpaceCast:
842 for (
Use &UU :
I->uses())
843 if (Visited.
insert(&UU).second)
847 case Instruction::Call:
848 case Instruction::Invoke: {
867 if (Visited.
insert(&UU).second)
877 if (!
I->getType()->isVoidTy())
878 for (
Use &UU :
I->uses())
879 if (Visited.
insert(&UU).second)
889 SCCNodes.
count(
F->getArg(UseIndex)))
910 case Instruction::Load:
913 if (cast<LoadInst>(
I)->isVolatile())
919 case Instruction::Store:
920 if (cast<StoreInst>(
I)->getValueOperand() == *U)
926 if (cast<StoreInst>(
I)->isVolatile())
932 case Instruction::ICmp:
933 case Instruction::Ret:
941 if (IsWrite && IsRead)
944 return Attribute::ReadOnly;
946 return Attribute::WriteOnly;
948 return Attribute::ReadNone;
959 if (!
F->hasExactDefinition())
962 if (
F->getReturnType()->isVoidTy())
966 if (
F->getAttributes().hasAttrSomewhere(Attribute::Returned))
969 auto FindRetArg = [&]() ->
Argument * {
972 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator())) {
976 dyn_cast<Argument>(Ret->getReturnValue()->stripPointerCasts());
977 if (!RetVal || RetVal->getType() !=
F->getReturnType())
982 else if (RetArg != RetVal)
989 if (
Argument *RetArg = FindRetArg()) {
990 RetArg->
addAttr(Attribute::Returned);
1005 bool Changed =
false;
1016 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
1018 for (
auto &CSArg : CalledFunc->args()) {
1019 if (!CSArg.hasNonNullAttr(
false))
1025 auto *FArg = dyn_cast<Argument>(CB->
getArgOperand(CSArg.getArgNo()));
1026 if (FArg && !FArg->hasNonNullAttr()) {
1027 FArg->addAttr(Attribute::NonNull);
1041 assert((R == Attribute::ReadOnly || R == Attribute::ReadNone ||
1042 R == Attribute::WriteOnly)
1043 &&
"Must be an access attribute.");
1044 assert(
A &&
"Argument must not be null.");
1047 if (
A->hasAttribute(R))
1052 A->removeAttr(Attribute::WriteOnly);
1053 A->removeAttr(Attribute::ReadOnly);
1054 A->removeAttr(Attribute::ReadNone);
1056 if (R == Attribute::ReadNone || R == Attribute::ReadOnly)
1057 A->removeAttr(Attribute::Writable);
1059 if (R == Attribute::ReadOnly)
1061 else if (R == Attribute::WriteOnly)
1069 auto ArgumentUses = collectArgumentUsesPerBlock(
A,
F);
1071 if (!ArgumentUses.HasAnyWrite)
1074 auto &UsesPerBlock = ArgumentUses.UsesPerBlock;
1083 auto UPB = UsesPerBlock.find(BB);
1090 if (UPB == UsesPerBlock.end() || !UPB->second.HasUnknownAccess) {
1091 bool HasAddedSuccessor =
false;
1093 if (
auto SuccI = Initialized.
find(Succ); SuccI != Initialized.
end()) {
1094 if (HasAddedSuccessor) {
1097 CRL = SuccI->second;
1098 HasAddedSuccessor =
true;
1107 if (UPB != UsesPerBlock.end()) {
1111 sort(Insts, [](std::pair<Instruction *, ArgumentAccessInfo> &
LHS,
1112 std::pair<Instruction *, ArgumentAccessInfo> &
RHS) {
1113 return LHS.first->comesBefore(
RHS.first);
1119 if (
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown ||
1120 Info.ArgAccessType ==
1121 ArgumentAccessInfo::AccessType::WriteWithSideEffect)
1123 if (!
Info.AccessRanges.empty()) {
1124 if (
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
1125 Info.ArgAccessType ==
1126 ArgumentAccessInfo::AccessType::WriteWithSideEffect) {
1129 assert(
Info.ArgAccessType == ArgumentAccessInfo::AccessType::Read);
1130 for (
const auto &ReadRange :
Info.AccessRanges)
1142 bool OnlyScanEntryBlock = !ArgumentUses.HasWriteOutsideEntryBB;
1143 if (!OnlyScanEntryBlock)
1144 if (
auto EntryUPB = UsesPerBlock.find(&EntryBB);
1145 EntryUPB != UsesPerBlock.end())
1146 OnlyScanEntryBlock = EntryUPB->second.HasUnknownAccess;
1147 if (OnlyScanEntryBlock) {
1148 EntryCRL = VisitBlock(&EntryBB);
1149 if (EntryCRL.
empty())
1160 Initialized[BB] = CRL;
1163 auto EntryCRLI = Initialized.
find(&EntryBB);
1164 if (EntryCRLI == Initialized.
end())
1167 EntryCRL = EntryCRLI->second;
1171 "should have bailed already if EntryCRL is empty");
1173 if (
A.hasAttribute(Attribute::Initializes)) {
1175 A.getAttribute(Attribute::Initializes).getValueAsConstantRangeList();
1176 if (PreviousCRL == EntryCRL)
1178 EntryCRL = EntryCRL.
unionWith(PreviousCRL);
1190 bool SkipInitializes) {
1199 if (!
F->hasExactDefinition())
1207 if (
F->onlyReadsMemory() &&
F->doesNotThrow() &&
1208 F->getReturnType()->isVoidTy()) {
1210 if (
A.getType()->isPointerTy() && !
A.hasNoCaptureAttr()) {
1211 A.addAttr(Attribute::NoCapture);
1220 if (!
A.getType()->isPointerTy())
1222 bool HasNonLocalUses =
false;
1223 if (!
A.hasNoCaptureAttr()) {
1224 ArgumentUsesTracker Tracker(SCCNodes);
1226 if (!Tracker.Captured) {
1227 if (Tracker.Uses.empty()) {
1229 A.addAttr(Attribute::NoCapture);
1236 ArgumentGraphNode *
Node = AG[&
A];
1238 Node->Uses.push_back(AG[
Use]);
1240 HasNonLocalUses =
true;
1246 if (!HasNonLocalUses && !
A.onlyReadsMemory()) {
1258 if (!SkipInitializes && !
A.onlyReadsMemory()) {
1273 const std::vector<ArgumentGraphNode *> &ArgumentSCC = *
I;
1274 if (ArgumentSCC.size() == 1) {
1275 if (!ArgumentSCC[0]->Definition)
1279 if (ArgumentSCC[0]->
Uses.size() == 1 &&
1280 ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
1281 Argument *
A = ArgumentSCC[0]->Definition;
1282 A->addAttr(Attribute::NoCapture);
1284 Changed.
insert(
A->getParent());
1296 bool SCCCaptured =
false;
1297 for (ArgumentGraphNode *
Node : ArgumentSCC) {
1298 if (
Node->Uses.empty() && !
Node->Definition->hasNoCaptureAttr()) {
1309 for (ArgumentGraphNode *
I : ArgumentSCC) {
1310 ArgumentSCCNodes.
insert(
I->Definition);
1313 for (ArgumentGraphNode *
N : ArgumentSCC) {
1314 for (ArgumentGraphNode *
Use :
N->Uses) {
1316 if (
A->hasNoCaptureAttr() || ArgumentSCCNodes.
count(
A))
1327 for (ArgumentGraphNode *
N : ArgumentSCC) {
1329 A->addAttr(Attribute::NoCapture);
1331 Changed.
insert(
A->getParent());
1348 if (
A == Attribute::ReadNone)
1350 if (
B == Attribute::ReadNone)
1356 for (ArgumentGraphNode *
N : ArgumentSCC) {
1359 AccessAttr = meetAccessAttr(AccessAttr, K);
1365 for (ArgumentGraphNode *
N : ArgumentSCC) {
1368 Changed.
insert(
A->getParent());
1381 if (
ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1382 FlowsToReturn.
insert(Ret->getReturnValue());
1384 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1385 Value *RetVal = FlowsToReturn[i];
1387 if (
Constant *
C = dyn_cast<Constant>(RetVal)) {
1388 if (!
C->isNullValue() && !isa<UndefValue>(
C))
1394 if (isa<Argument>(RetVal))
1397 if (
Instruction *RVI = dyn_cast<Instruction>(RetVal))
1398 switch (RVI->getOpcode()) {
1400 case Instruction::BitCast:
1401 case Instruction::GetElementPtr:
1402 case Instruction::AddrSpaceCast:
1403 FlowsToReturn.
insert(RVI->getOperand(0));
1405 case Instruction::Select: {
1407 FlowsToReturn.
insert(SI->getTrueValue());
1408 FlowsToReturn.
insert(SI->getFalseValue());
1411 case Instruction::PHI: {
1412 PHINode *PN = cast<PHINode>(RVI);
1414 FlowsToReturn.
insert(IncValue);
1419 case Instruction::Alloca:
1421 case Instruction::Call:
1422 case Instruction::Invoke: {
1423 CallBase &CB = cast<CallBase>(*RVI);
1448 if (
F->returnDoesNotAlias())
1454 if (!
F->hasExactDefinition())
1459 if (!
F->getReturnType()->isPointerTy())
1467 if (
F->returnDoesNotAlias() ||
1468 !
F->getReturnType()->isPointerTy())
1471 F->setReturnDoesNotAlias();
1485 bool &Speculative) {
1486 assert(
F->getReturnType()->isPointerTy() &&
1487 "nonnull only meaningful on pointer types");
1488 Speculative =
false;
1492 if (
auto *Ret = dyn_cast<ReturnInst>(BB.getTerminator()))
1493 FlowsToReturn.
insert(Ret->getReturnValue());
1495 auto &
DL =
F->getDataLayout();
1497 for (
unsigned i = 0; i != FlowsToReturn.
size(); ++i) {
1498 Value *RetVal = FlowsToReturn[i];
1511 case Instruction::BitCast:
1512 case Instruction::AddrSpaceCast:
1515 case Instruction::GetElementPtr:
1516 if (cast<GEPOperator>(RVI)->isInBounds()) {
1521 case Instruction::Select: {
1523 FlowsToReturn.
insert(SI->getTrueValue());
1524 FlowsToReturn.
insert(SI->getFalseValue());
1527 case Instruction::PHI: {
1528 PHINode *PN = cast<PHINode>(RVI);
1533 case Instruction::Call:
1534 case Instruction::Invoke: {
1535 CallBase &CB = cast<CallBase>(*RVI);
1539 if (Callee && SCCNodes.count(Callee)) {
1559 bool SCCReturnsNonNull =
true;
1565 if (
F->getAttributes().hasRetAttr(Attribute::NonNull))
1571 if (!
F->hasExactDefinition())
1576 if (!
F->getReturnType()->isPointerTy())
1579 bool Speculative =
false;
1585 <<
" as nonnull\n");
1586 F->addRetAttr(Attribute::NonNull);
1594 SCCReturnsNonNull =
false;
1597 if (SCCReturnsNonNull) {
1599 if (
F->getAttributes().hasRetAttr(Attribute::NonNull) ||
1600 !
F->getReturnType()->isPointerTy())
1603 LLVM_DEBUG(
dbgs() <<
"SCC marking " <<
F->getName() <<
" as nonnull\n");
1604 F->addRetAttr(Attribute::NonNull);
1619 if (Attrs.hasRetAttr(Attribute::NoUndef))
1625 if (!
F->hasExactDefinition())
1631 if (
F->hasFnAttribute(Attribute::SanitizeMemory))
1634 if (
F->getReturnType()->isVoidTy())
1641 Value *RetVal = Ret->getReturnValue();
1642 if (!isGuaranteedNotToBeUndefOrPoison(RetVal))
1648 if (Attrs.hasRetAttr(Attribute::NonNull) &&
1649 !isKnownNonZero(RetVal, DL))
1652 if (MaybeAlign Align = Attrs.getRetAlignment())
1653 if (RetVal->getPointerAlignment(DL) < *Align)
1656 Attribute Attr = Attrs.getRetAttr(Attribute::Range);
1657 if (Attr.isValid() &&
1658 !Attr.getRange().contains(
1659 computeConstantRange(RetVal, false)))
1664 F->addRetAttr(Attribute::NoUndef);
1679class AttributeInferer {
1682 struct InferenceDescriptor {
1694 std::function<void(
Function &)> SetAttribute;
1701 bool RequiresExactDefinition;
1704 std::function<
bool(
const Function &)> SkipFunc,
1706 std::function<
void(
Function &)> SetAttr,
1708 : SkipFunction(SkipFunc), InstrBreaksAttribute(InstrScan),
1709 SetAttribute(SetAttr), AKind(AK),
1710 RequiresExactDefinition(ReqExactDef) {}
1717 void registerAttrInference(InferenceDescriptor AttrInference) {
1718 InferenceDescriptors.
push_back(AttrInference);
1726void AttributeInferer::run(
const SCCNodeSet &SCCNodes,
1735 if (InferInSCC.
empty())
1740 if (
ID.SkipFunction(*
F))
1745 return F->isDeclaration() ||
1746 (
ID.RequiresExactDefinition && !
F->hasExactDefinition());
1753 InferInSCC, std::back_inserter(InferInThisFunc),
1754 [
F](
const InferenceDescriptor &
ID) {
return !
ID.SkipFunction(*
F); });
1756 if (InferInThisFunc.empty())
1762 if (!
ID.InstrBreaksAttribute(
I))
1767 return D.AKind == ID.AKind;
1773 if (InferInThisFunc.empty())
1778 if (InferInSCC.
empty())
1786 for (
auto &
ID : InferInSCC) {
1787 if (
ID.SkipFunction(*
F))
1790 ID.SetAttribute(*
F);
1794struct SCCNodesResult {
1795 SCCNodeSet SCCNodes;
1796 bool HasUnknownCall;
1803 const SCCNodeSet &SCCNodes) {
1804 const CallBase *CB = dyn_cast<CallBase>(&
I);
1813 if (!
I.mayThrow(
true))
1815 if (
const auto *CI = dyn_cast<CallInst>(&
I)) {
1816 if (
Function *Callee = CI->getCalledFunction()) {
1820 if (SCCNodes.contains(Callee))
1838 if (SCCNodes.contains(Callee))
1853 if (
auto *FI = dyn_cast<FenceInst>(
I))
1856 else if (isa<AtomicCmpXchgInst>(
I) || isa<AtomicRMWInst>(
I))
1858 else if (
auto *SI = dyn_cast<StoreInst>(
I))
1859 return !SI->isUnordered();
1860 else if (
auto *LI = dyn_cast<LoadInst>(
I))
1861 return !LI->isUnordered();
1876 auto *CB = dyn_cast<CallBase>(&
I);
1887 if (
auto *
MI = dyn_cast<MemIntrinsic>(&
I))
1888 if (!
MI->isVolatile())
1893 if (SCCNodes.contains(Callee))
1904 AttributeInferer AI;
1911 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1912 Attribute::Convergent,
1914 [](
const Function &
F) {
return !
F.isConvergent(); },
1920 LLVM_DEBUG(
dbgs() <<
"Removing convergent attr from fn " <<
F.getName()
1922 F.setNotConvergent();
1926 AI.run(SCCNodes, Changed);
1935 AttributeInferer AI;
1943 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1944 Attribute::NoUnwind,
1946 [](
const Function &
F) {
return F.doesNotThrow(); },
1953 <<
"Adding nounwind attr to fn " <<
F.getName() <<
"\n");
1954 F.setDoesNotThrow();
1966 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1969 [](
const Function &
F) {
return F.doesNotFreeMemory(); },
1976 <<
"Adding nofree attr to fn " <<
F.getName() <<
"\n");
1977 F.setDoesNotFreeMemory();
1982 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1985 [](
const Function &
F) {
return F.hasNoSync(); },
1992 <<
"Adding nosync attr to fn " <<
F.getName() <<
"\n");
1999 AI.run(SCCNodes, Changed);
2007 if (SCCNodes.size() != 1)
2011 if (!
F || !
F->hasExactDefinition() ||
F->doesNotRecurse())
2018 for (
auto &
I : BB.instructionsWithoutDebug())
2019 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
2021 if (!Callee || Callee ==
F ||
2022 (!Callee->doesNotRecurse() &&
2023 !(Callee->isDeclaration() &&
2024 Callee->hasFnAttribute(Attribute::NoCallback))))
2032 F->setDoesNotRecurse();
2038 if (
auto *CB = dyn_cast<CallBase>(&
I))
2039 return CB->
hasFnAttr(Attribute::NoReturn);
2064 if (Visited.
insert(Succ).second)
2066 }
while (!Worklist.
empty());
2076 if (!
F || !
F->hasExactDefinition() ||
F->hasFnAttribute(Attribute::Naked) ||
2081 F->setDoesNotReturn();
2089 ColdPaths[&
F.front()] =
false;
2093 while (!Jobs.
empty()) {
2100 if (
auto *CB = dyn_cast<CallBase>(&
I))
2104 ColdPaths[BB] =
true;
2121 auto [Iter, Inserted] = ColdPaths.
try_emplace(Succ,
false);
2137 if (!
F || !
F->hasExactDefinition() ||
F->hasFnAttribute(Attribute::Naked) ||
2138 F->hasFnAttribute(Attribute::Cold) ||
F->hasFnAttribute(Attribute::Hot))
2143 F->addFnAttr(Attribute::Cold);
2155 if (!
F.hasExactDefinition())
2159 if (
F.mustProgress() &&
F.onlyReadsMemory())
2163 if (
F.isDeclaration())
2170 if (!Backedges.
empty())
2176 return I.willReturn();
2195 Res.HasUnknownCall =
false;
2197 if (!
F ||
F->hasOptNone() ||
F->hasFnAttribute(Attribute::Naked) ||
2198 F->isPresplitCoroutine()) {
2201 Res.HasUnknownCall =
true;
2208 if (!Res.HasUnknownCall) {
2210 if (
auto *CB = dyn_cast<CallBase>(&
I)) {
2212 Res.HasUnknownCall =
true;
2218 Res.SCCNodes.insert(
F);
2223template <
typename AARGetterT>
2226 bool ArgAttrsOnly) {
2230 if (Nodes.SCCNodes.empty())
2253 if (!Nodes.HasUnknownCall) {
2279 bool ArgAttrsOnly =
false;
2280 if (
C.size() == 1 && SkipNonRecursive) {
2283 ArgAttrsOnly =
true;
2300 auto ChangedFunctions =
2302 if (ChangedFunctions.empty())
2310 for (
Function *Changed : ChangedFunctions) {
2316 for (
auto *U : Changed->users()) {
2317 if (
auto *Call = dyn_cast<CallBase>(U)) {
2318 if (Call->getCalledFunction() == Changed)
2335 OS, MapClassName2PassName);
2336 if (SkipNonRecursive)
2337 OS <<
"<skip-non-recursive-function-attrs>";
2340template <
typename AARGetterT>
2354 assert(!
F.isDeclaration() &&
"Cannot deduce norecurse without a definition!");
2356 "This function has already been deduced as norecurs!");
2357 assert(
F.hasInternalLinkage() &&
2358 "Can only do top-down deduction for internal linkage functions!");
2368 for (
auto &U :
F.uses()) {
2369 auto *
I = dyn_cast<Instruction>(U.getUser());
2374 !CB->
getParent()->getParent()->doesNotRecurse())
2377 F.setDoesNotRecurse();
2395 if (SCC.size() != 1)
2397 Function &
F = SCC.begin()->getFunction();
2398 if (!
F.isDeclaration() && !
F.doesNotRecurse() &&
F.hasInternalLinkage())
2402 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.