LLVM: lib/Transforms/IPO/FunctionAttrs.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
62#include
63#include
64#include
65#include
66#include
67
68using namespace llvm;
69
70#define DEBUG_TYPE "function-attrs"
71
72STATISTIC(NumMemoryAttr, "Number of functions with improved memory attribute");
73STATISTIC(NumCapturesNone, "Number of arguments marked captures(none)");
74STATISTIC(NumCapturesPartial, "Number of arguments marked with captures "
75 "attribute other than captures(none)");
76STATISTIC(NumReturned, "Number of arguments marked returned");
77STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
78STATISTIC(NumReadOnlyArg, "Number of arguments marked readonly");
79STATISTIC(NumWriteOnlyArg, "Number of arguments marked writeonly");
80STATISTIC(NumNoAlias, "Number of function returns marked noalias");
81STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull");
82STATISTIC(NumNoUndefReturn, "Number of function returns marked noundef");
83STATISTIC(NumNoRecurse, "Number of functions marked as norecurse");
84STATISTIC(NumNoUnwind, "Number of functions marked as nounwind");
85STATISTIC(NumNoFree, "Number of functions marked as nofree");
86STATISTIC(NumWillReturn, "Number of functions marked as willreturn");
87STATISTIC(NumNoSync, "Number of functions marked as nosync");
88STATISTIC(NumCold, "Number of functions marked as cold");
89
91 "Number of functions marked as norecurse during thinlink");
93 "Number of functions marked as nounwind during thinlink");
94
97 cl::desc("Try to propagate nonnull argument attributes from callsites to "
98 "caller functions."));
99
101 "disable-nounwind-inference", cl::Hidden,
102 cl::desc("Stop inferring nounwind attribute during function-attrs pass"));
103
105 "disable-nofree-inference", cl::Hidden,
106 cl::desc("Stop inferring nofree attribute during function-attrs pass"));
107
110 cl::desc("Don't propagate function-attrs in thinLTO"));
111
114 ++NumCapturesNone;
115 else
116 ++NumCapturesPartial;
117}
118
119namespace {
120
122
123}
124
127
130 return;
131
134 return;
137 return;
138 }
139
140
145}
146
149 for (const Value *Arg : Call->args()) {
150 if (!Arg->getType()->isPtrOrPtrVectorTy())
151 continue;
152
155 ArgMR, AAR);
156 }
157}
158
159
160
161
162
163
164
165
166
167
168
169
170
171static std::pair<MemoryEffects, MemoryEffects>
173 const SCCNodeSet &SCCNodes) {
176
178
179 if (!ThisBody)
181
183
185
186
187 if (F.getAttributes().hasAttrSomewhere(Attribute::InAlloca) ||
188 F.getAttributes().hasAttrSomewhere(Attribute::Preallocated))
190
191
193
194
196
197
198
199
200
201 if (->hasOperandBundles() && Call->getCalledFunction() &&
202 SCCNodes.count(Call->getCalledFunction())) {
203
204
206 continue;
207 }
208
210
211
213 continue;
214
215
216
217
218
220 continue;
221
222
223
224
226
227
228
229
232
233
234
238 continue;
239 }
240
242 if (I.mayWriteToMemory())
244 if (I.mayReadFromMemory())
247 continue;
248
250 if () {
251
252
254 continue;
255 }
256
257
258 if (I.isVolatile())
260
262 }
263
264 return {OrigME & ME, RecursiveArgME};
265}
266
271
272
273template
274static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
279
281
282
283
284 auto [FnME, FnRecursiveArgME] =
286 ME |= FnME;
287 RecursiveArgME |= FnRecursiveArgME;
288
290 return;
291 }
292
293
297
301 if (NewME != OldME) {
302 ++NumMemoryAttr;
303 F->setMemoryEffects(NewME);
304
307 A.removeAttr(Attribute::Writable);
309 }
310 }
311}
312
313
314
319 IsPrevailing) {
320
321 auto [It, Inserted] = CachedPrevailingSummary.try_emplace(VI);
322 if (!Inserted)
323 return It->second;
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
367
368 for (const auto &GVS : VI.getSummaryList()) {
369 if (!GVS->isLive())
370 continue;
371
373
374 if (!FS || FS->fflags().HasUnknownCall)
375 return nullptr;
376
377 const auto &Linkage = GVS->linkage();
382 << "ThinLTO FunctionAttrs: Multiple Local Linkage, bailing on "
383 "function "
384 << VI.name() << " from " << FS->modulePath() << ". Previous module "
385 << Local->modulePath() << "\n");
386 return nullptr;
387 }
390 assert(IsPrevailing(VI.getGUID(), GVS.get()));
391 Prevailing = FS;
392 break;
397 if (IsPrevailing(VI.getGUID(), GVS.get())) {
398 Prevailing = FS;
399 break;
400 }
402
403 continue;
404 }
405 }
406
407 auto &CPS = CachedPrevailingSummary[VI];
411 } else if (Prevailing) {
413 CPS = Prevailing;
414 }
415
416 return CPS;
417}
418
422 IsPrevailing) {
423
424
426 return false;
427
430
431 auto PropagateAttributes = [&](std::vector &SCCNodes) {
432
434 InferredFlags.NoRecurse = (SCCNodes.size() == 1);
435 InferredFlags.NoUnwind = true;
436
437 for (auto &V : SCCNodes) {
440
441
442 if (!CallerSummary)
443 return;
444
446 InferredFlags.NoUnwind = false;
447
448 for (const auto &Callee : CallerSummary->calls()) {
450 Callee.first, CachedPrevailingSummary, IsPrevailing);
451
452 if (!CalleeSummary)
453 return;
454
457
459 InferredFlags.NoUnwind = false;
460
462 break;
463 }
464 }
465
468 for (auto &V : SCCNodes) {
470 LLVM_DEBUG(dbgs() << "ThinLTO FunctionAttrs: Propagated NoRecurse to "
471 << V.name() << "\n");
472 ++NumThinLinkNoRecurse;
473 }
474
475 if (InferredFlags.NoUnwind) {
476 LLVM_DEBUG(dbgs() << "ThinLTO FunctionAttrs: Propagated NoUnwind to "
477 << V.name() << "\n");
478 ++NumThinLinkNoUnwind;
479 }
480
481 for (const auto &S : V.getSummaryList()) {
484 FS->setNoRecurse();
485
487 FS->setNoUnwind();
488 }
489 }
490 }
491 }
492 };
493
494
496 ++I) {
497 std::vector Nodes(*I);
498 PropagateAttributes(Nodes);
499 }
501}
502
503namespace {
504
505
506
507
508struct ArgumentGraphNode {
510
511
514};
515
516class ArgumentGraph {
517
518
519 using ArgumentMapTy = std::map<Argument *, ArgumentGraphNode>;
520
521 ArgumentMapTy ArgumentMap;
522
523
524
525
526
527
528
529 ArgumentGraphNode SyntheticRoot;
530
531public:
532 ArgumentGraph() { SyntheticRoot.Definition = nullptr; }
533
535
536 iterator begin() { return SyntheticRoot.Uses.begin(); }
537 iterator end() { return SyntheticRoot.Uses.end(); }
538 ArgumentGraphNode *getEntryNode() { return &SyntheticRoot; }
539
540 ArgumentGraphNode *operator[](Argument *A) {
541 ArgumentGraphNode &Node = ArgumentMap[A];
543 SyntheticRoot.Uses.push_back(&Node);
544 return &Node;
545 }
546};
547
548
549
550
552 ArgumentUsesTracker(const SCCNodeSet &SCCNodes) : SCCNodes(SCCNodes) {}
553
555
556 Action captured(const Use *U, UseCaptureInfo UseCI) override {
557 if (updateCaptureInfo(U, UseCI.UseCC)) {
558
559 if (capturesAll(CI.getOtherComponents()))
560 return Stop;
562 }
563
564
565
566 return ContinueIgnoringReturn;
567 }
568
571 if (!CB) {
574 else
575
576
577 CI |= CaptureInfo(CC);
578 return true;
579 }
580
582 if ( ||
->hasExactDefinition() || !SCCNodes.count(F)) {
583 CI |= CaptureInfo(CC);
584 return true;
585 }
586
587 assert(!CB->isCallee(U) && "callee operand reported captured?");
589 if (UseIndex >= CB->arg_size()) {
590
592
593
594
595
596
597 CI |= CaptureInfo(CC);
598 return true;
599 }
600
601 if (UseIndex >= F->arg_size()) {
602 assert(F->isVarArg() && "More params than args in non-varargs call");
603 CI |= CaptureInfo(CC);
604 return true;
605 }
606
607
608
609 Uses.push_back(&*std::next(F->arg_begin(), UseIndex));
610 return false;
611 }
612
613
615
616
618
619 const SCCNodeSet &SCCNodes;
620};
621
622
623
624
625struct ArgumentUse {
627 std::optional<int64_t> Offset;
628};
629
630
631
632
633
634struct ArgumentAccessInfo {
635 enum class AccessType : uint8_t { Write, WriteWithSideEffect, Read, Unknown };
636 AccessType ArgAccessType;
637 ConstantRangeList AccessRanges;
638};
639
640
641struct UsesPerBlockInfo {
642 SmallDenseMap<Instruction *, ArgumentAccessInfo, 4> Insts;
643 bool HasWrites = false;
644 bool HasUnknownAccess = false;
645};
646
647
648struct ArgumentUsesSummary {
649 bool HasAnyWrite = false;
650 bool HasWriteOutsideEntryBB = false;
651 SmallDenseMap<const BasicBlock *, UsesPerBlockInfo, 16> UsesPerBlock;
652};
653
654ArgumentAccessInfo getArgumentAccessInfo(const Instruction *I,
655 const ArgumentUse &ArgUse,
657 auto GetTypeAccessRange =
659 std::optional<int64_t> Offset) -> std::optional {
660 auto TypeSize = DL.getTypeStoreSize(Ty);
664 bool Overflow;
666
667 if (Overflow)
668 return std::nullopt;
670 }
671 return std::nullopt;
672 };
673 auto GetConstantIntRange =
675 std::optional<int64_t> Offset) -> std::optional {
677 if (ConstantLength && Offset) {
678 int64_t Len = ConstantLength->getSExtValue();
679
680
681 if (Len <= 0)
682 return std::nullopt;
683
685 bool Overflow;
687 if (Overflow)
688 return std::nullopt;
689
691 }
692 return std::nullopt;
693 };
694
696 if (SI->isSimple() && &SI->getOperandUse(1) == ArgUse.U) {
697
698
699
701 if (auto TypeAccessRange =
702 GetTypeAccessRange(SI->getAccessType(), ArgUse.Offset))
703 AccessRanges.insert(*TypeAccessRange);
704 return {ArgumentAccessInfo::AccessType::Write, std::move(AccessRanges)};
705 }
707 if (LI->isSimple()) {
708 assert(&LI->getOperandUse(0) == ArgUse.U);
709
710
711
712 if (auto TypeAccessRange =
713 GetTypeAccessRange(LI->getAccessType(), ArgUse.Offset))
714 return {ArgumentAccessInfo::AccessType::Read, {*TypeAccessRange}};
715 }
717 if (!MemSet->isVolatile()) {
719 if (auto AccessRange =
720 GetConstantIntRange(MemSet->getLength(), ArgUse.Offset))
721 AccessRanges.insert(*AccessRange);
722 return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
723 }
725 if (!MTI->isVolatile()) {
726 if (&MTI->getOperandUse(0) == ArgUse.U) {
728 if (auto AccessRange =
729 GetConstantIntRange(MTI->getLength(), ArgUse.Offset))
730 AccessRanges.insert(*AccessRange);
731 return {ArgumentAccessInfo::AccessType::Write, AccessRanges};
732 } else if (&MTI->getOperandUse(1) == ArgUse.U) {
733 if (auto AccessRange =
734 GetConstantIntRange(MTI->getLength(), ArgUse.Offset))
735 return {ArgumentAccessInfo::AccessType::Read, {*AccessRange}};
736 }
737 }
742 bool IsInitialize = CB->paramHasAttr(ArgNo, Attribute::Initializes);
743 if (IsInitialize && ArgUse.Offset) {
744
745
747 ? ArgumentAccessInfo::AccessType::Write
748 : ArgumentAccessInfo::AccessType::WriteWithSideEffect;
754 CR.getUpper() + *ArgUse.Offset));
755 return {Access, AccessRanges};
756 }
757 }
758 }
759
760 return {ArgumentAccessInfo::AccessType::Unknown, {}};
761}
762
763
764ArgumentUsesSummary collectArgumentUsesPerBlock(Argument &A, Function &F) {
765 auto &DL = F.getParent()->getDataLayout();
767 DL.getIndexSizeInBits(A.getType()->getPointerAddressSpace());
768 ArgumentUsesSummary Result;
769
774
775
776
778 auto *BB = I->getParent();
779 auto &BBInfo = Result.UsesPerBlock[BB];
780 auto [It, Inserted] = BBInfo.Insts.try_emplace(I);
781 auto &IInfo = It->second;
782
783
784
785 if (!Inserted) {
786 IInfo = {ArgumentAccessInfo::AccessType::Unknown, {}};
787 BBInfo.HasUnknownAccess = true;
788 return false;
789 }
790
791 IInfo = std::move(Info);
792 BBInfo.HasUnknownAccess |=
793 IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown;
794 bool InfoHasWrites =
795 (IInfo.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
796 IInfo.ArgAccessType ==
797 ArgumentAccessInfo::AccessType::WriteWithSideEffect) &&
798 !IInfo.AccessRanges.empty();
799 BBInfo.HasWrites |= InfoHasWrites;
800 return InfoHasWrites;
801 };
802
803
804
805 while (!Worklist.empty()) {
806 ArgumentUse ArgUse = Worklist.pop_back_val();
807 User *U = ArgUse.U->getUser();
808
809
811 std::optional<int64_t> NewOffset = std::nullopt;
812 if (ArgUse.Offset) {
814 if (GEP->accumulateConstantOffset(DL, Offset))
815 NewOffset = *ArgUse.Offset + Offset.getSExtValue();
816 }
817 for (Use &U : GEP->uses())
818 Worklist.push_back({&U, NewOffset});
819 continue;
820 }
821
823 bool HasWrite = UpdateUseInfo(I, getArgumentAccessInfo(I, ArgUse, DL));
824
825 Result.HasAnyWrite |= HasWrite;
826
827 if (HasWrite && I->getParent() != &EntryBB)
828 Result.HasWriteOutsideEntryBB = true;
829 }
831}
832
833}
834
835namespace llvm {
836
845
846template <>
849
851 return AG->begin();
852 }
853
855};
856
857}
858
859
865
866
867 if (A->hasInAllocaAttr() || A->hasPreallocatedAttr())
869
870 bool IsRead = false;
871 bool IsWrite = false;
872
873 for (Use &U : A->uses()) {
876 }
877
878 while (!Worklist.empty()) {
879 if (IsWrite && IsRead)
880
882
885
886 switch (I->getOpcode()) {
887 case Instruction::BitCast:
888 case Instruction::GetElementPtr:
889 case Instruction::PHI:
890 case Instruction::Select:
891 case Instruction::AddrSpaceCast:
892
894 if (Visited.insert(&UU).second)
896 break;
897
898 case Instruction::Call:
899 case Instruction::Invoke: {
902 IsRead = true;
903
904
905 continue;
906 }
907
908
909
911
912
913
914
916 &CB, false)) {
918 if (Visited.insert(&UU).second)
922
923
924
925
927
928 if (->getType()->isVoidTy())
930 if (Visited.insert(&UU).second)
932 }
933
936 continue;
937
939 if (CB.isArgOperand(U) && UseIndex < F->arg_size() &&
940 SCCNodes.count(F->getArg(UseIndex)))
941
942
943
944 break;
945
946
947
949
951 IsRead = true;
952 } else if ((ArgMR) ||
954 IsWrite = true;
955 } else {
957 }
958 break;
959 }
960
961 case Instruction::Load:
962
963
966
967 IsRead = true;
968 break;
969
970 case Instruction::Store:
972
974
975
976
979
980 IsWrite = true;
981 break;
982
983 case Instruction::ICmp:
984 case Instruction::Ret:
985 break;
986
987 default:
989 }
990 }
991
992 if (IsWrite && IsRead)
994 else if (IsRead)
995 return Attribute::ReadOnly;
996 else if (IsWrite)
997 return Attribute::WriteOnly;
998 else
999 return Attribute::ReadNone;
1000}
1001
1002
1005
1007
1008
1009
1010 if (->hasExactDefinition())
1011 continue;
1012
1013 if (F->getReturnType()->isVoidTy())
1014 continue;
1015
1016
1017 if (F->getAttributes().hasAttrSomewhere(Attribute::Returned))
1018 continue;
1019
1020 auto FindRetArg = [&]() -> Argument * {
1024
1025
1026 auto *RetVal =
1028 if (!RetVal || RetVal->getType() != F->getReturnType())
1029 return nullptr;
1030
1031 if (!RetArg)
1032 RetArg = RetVal;
1033 else if (RetArg != RetVal)
1034 return nullptr;
1035 }
1036
1037 return RetArg;
1038 };
1039
1040 if (Argument *RetArg = FindRetArg()) {
1041 RetArg->addAttr(Attribute::Returned);
1042 ++NumReturned;
1044 }
1045 }
1046}
1047
1048
1049
1050
1051
1054 return false;
1055
1057
1058
1059
1060
1061
1062
1063
1064
1069 for (auto &CSArg : CalledFunc->args()) {
1070 if (!CSArg.hasNonNullAttr( false))
1071 continue;
1072
1073
1074
1075
1077 if (FArg && !FArg->hasNonNullAttr()) {
1078 FArg->addAttr(Attribute::NonNull);
1080 }
1081 }
1082 }
1083 }
1085 break;
1086 }
1087
1089}
1090
1092 assert((R == Attribute::ReadOnly || R == Attribute::ReadNone ||
1093 R == Attribute::WriteOnly)
1094 && "Must be an access attribute.");
1095 assert(A && "Argument must not be null.");
1096
1097
1098 if (A->hasAttribute(R))
1099 return false;
1100
1101
1102
1103 A->removeAttr(Attribute::WriteOnly);
1104 A->removeAttr(Attribute::ReadOnly);
1105 A->removeAttr(Attribute::ReadNone);
1106
1107 if (R == Attribute::ReadNone || R == Attribute::ReadOnly)
1108 A->removeAttr(Attribute::Writable);
1109 A->addAttr(R);
1110 if (R == Attribute::ReadOnly)
1111 ++NumReadOnlyArg;
1112 else if (R == Attribute::WriteOnly)
1113 ++NumWriteOnlyArg;
1114 else
1115 ++NumReadNoneArg;
1116 return true;
1117}
1118
1120 auto ArgumentUses = collectArgumentUsesPerBlock(A, F);
1121
1122 if (!ArgumentUses.HasAnyWrite)
1123 return false;
1124
1125 auto &UsesPerBlock = ArgumentUses.UsesPerBlock;
1126 BasicBlock &EntryBB = F.getEntryBlock();
1127
1128
1130
1131
1132
1134 auto UPB = UsesPerBlock.find(BB);
1136
1137
1138
1139
1140
1141 if (UPB == UsesPerBlock.end() || !UPB->second.HasUnknownAccess) {
1142 bool HasAddedSuccessor = false;
1144 if (auto SuccI = Initialized.find(Succ); SuccI != Initialized.end()) {
1145 if (HasAddedSuccessor) {
1147 } else {
1148 CRL = SuccI->second;
1149 HasAddedSuccessor = true;
1150 }
1151 } else {
1153 break;
1154 }
1155 }
1156 }
1157
1158 if (UPB != UsesPerBlock.end()) {
1159
1162 sort(Insts, [](std::pair<Instruction *, ArgumentAccessInfo> &LHS,
1163 std::pair<Instruction *, ArgumentAccessInfo> &RHS) {
1164 return LHS.first->comesBefore(RHS.first);
1165 });
1166
1167
1168
1170 if (Info.ArgAccessType == ArgumentAccessInfo::AccessType::Unknown ||
1171 Info.ArgAccessType ==
1172 ArgumentAccessInfo::AccessType::WriteWithSideEffect)
1174 if (.AccessRanges.empty()) {
1175 if (Info.ArgAccessType == ArgumentAccessInfo::AccessType::Write ||
1176 Info.ArgAccessType ==
1177 ArgumentAccessInfo::AccessType::WriteWithSideEffect) {
1179 } else {
1180 assert(Info.ArgAccessType == ArgumentAccessInfo::AccessType::Read);
1181 for (const auto &ReadRange : Info.AccessRanges)
1183 }
1184 }
1185 }
1186 }
1187 return CRL;
1188 };
1189
1191
1192
1193 bool OnlyScanEntryBlock = !ArgumentUses.HasWriteOutsideEntryBB;
1194 if (!OnlyScanEntryBlock)
1195 if (auto EntryUPB = UsesPerBlock.find(&EntryBB);
1196 EntryUPB != UsesPerBlock.end())
1197 OnlyScanEntryBlock = EntryUPB->second.HasUnknownAccess;
1198 if (OnlyScanEntryBlock) {
1199 EntryCRL = VisitBlock(&EntryBB);
1200 if (EntryCRL.empty())
1201 return false;
1202 } else {
1203
1204
1205
1206
1207
1210 if (!CRL.empty())
1211 Initialized[BB] = CRL;
1212 }
1213
1214 auto EntryCRLI = Initialized.find(&EntryBB);
1215 if (EntryCRLI == Initialized.end())
1216 return false;
1217
1218 EntryCRL = EntryCRLI->second;
1219 }
1220
1222 "should have bailed already if EntryCRL is empty");
1223
1224 if (A.hasAttribute(Attribute::Initializes)) {
1226 A.getAttribute(Attribute::Initializes).getValueAsConstantRangeList();
1227 if (PreviousCRL == EntryCRL)
1228 return false;
1229 EntryCRL = EntryCRL.unionWith(PreviousCRL);
1230 }
1231
1232 A.addAttr(Attribute::get(A.getContext(), Attribute::Initializes,
1234
1235 return true;
1236}
1237
1238
1241 bool SkipInitializes) {
1242 ArgumentGraph AG;
1243
1244 auto DetermineAccessAttrsForSingleton = [](Argument *A) {
1250 return false;
1251 };
1252
1253
1254
1256
1257
1258
1259 if (->hasExactDefinition())
1260 continue;
1261
1264
1265
1266
1267 if (F->onlyReadsMemory() && F->doesNotThrow() && F->willReturn() &&
1268 F->getReturnType()->isVoidTy()) {
1270 if (A.getType()->isPointerTy() && .hasNoCaptureAttr()) {
1273 ++NumCapturesNone;
1275 }
1276 }
1277 continue;
1278 }
1279
1281 if (.getType()->isPointerTy())
1282 continue;
1283 bool HasNonLocalUses = false;
1284 CaptureInfo OrigCI = A.getAttributes().getCaptureInfo();
1286 ArgumentUsesTracker Tracker(SCCNodes);
1288 CaptureInfo NewCI = Tracker.CI & OrigCI;
1289 if (NewCI != OrigCI) {
1290 if (Tracker.Uses.empty()) {
1291
1295 } else {
1296
1297
1298
1299 ArgumentGraphNode *Node = AG[&A];
1302 Node->Uses.push_back(AG[Use]);
1304 HasNonLocalUses = true;
1305 }
1306 }
1307 }
1308
1309 }
1310 if (!HasNonLocalUses && .onlyReadsMemory()) {
1311
1312
1313
1314
1315 if (DetermineAccessAttrsForSingleton(&A))
1317 }
1318 if (!SkipInitializes && .onlyReadsMemory()) {
1321 }
1322 }
1323 }
1324
1325
1326
1327
1328
1329
1330
1331
1333 const std::vector<ArgumentGraphNode *> &ArgumentSCC = *I;
1334 if (ArgumentSCC.size() == 1) {
1335 if (!ArgumentSCC[0]->Definition)
1336 continue;
1337
1338
1339 if (ArgumentSCC[0]->Uses.size() == 1 &&
1340 ArgumentSCC[0]->Uses[0] == ArgumentSCC[0]) {
1341 Argument *A = ArgumentSCC[0]->Definition;
1342 CaptureInfo OrigCI = A->getAttributes().getCaptureInfo();
1344 if (NewCI != OrigCI) {
1347 Changed.insert(A->getParent());
1348 }
1349
1350
1351 if (DetermineAccessAttrsForSingleton(A))
1352 Changed.insert(A->getParent());
1353 }
1354 continue;
1355 }
1356
1358
1359
1360 for (ArgumentGraphNode *I : ArgumentSCC) {
1361 ArgumentSCCNodes.insert(I->Definition);
1362 }
1363
1364
1365
1366
1368 for (ArgumentGraphNode *N : ArgumentSCC) {
1369 for (ArgumentGraphNode *Use : N->Uses) {
1371 if (ArgumentSCCNodes.count(A))
1372 CC |= Use->CC;
1373 else
1375 break;
1376 }
1378 break;
1379 }
1380
1382 for (ArgumentGraphNode *N : ArgumentSCC) {
1384 CaptureInfo OrigCI = A->getAttributes().getCaptureInfo();
1386 if (NewCI != OrigCI) {
1389 Changed.insert(A->getParent());
1390 }
1391 }
1392 }
1393
1395
1396
1397 for (ArgumentGraphNode *N : ArgumentSCC) {
1398 if (DetermineAccessAttrsForSingleton(N->Definition))
1399 Changed.insert(N->Definition->getParent());
1400 }
1401 continue;
1402 }
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1417 return A;
1418 if (A == Attribute::ReadNone)
1419 return B;
1420 if (B == Attribute::ReadNone)
1421 return A;
1423 };
1424
1426 for (ArgumentGraphNode *N : ArgumentSCC) {
1429 AccessAttr = meetAccessAttr(AccessAttr, K);
1431 break;
1432 }
1433
1435 for (ArgumentGraphNode *N : ArgumentSCC) {
1438 Changed.insert(A->getParent());
1439 }
1440 }
1441 }
1442}
1443
1444
1445
1446
1447
1452 FlowsToReturn.insert(Ret->getReturnValue());
1453
1454 for (unsigned i = 0; i != FlowsToReturn.size(); ++i) {
1455 Value *RetVal = FlowsToReturn[i];
1456
1459 return false;
1460
1461 continue;
1462 }
1463
1465 return false;
1466
1468 switch (RVI->getOpcode()) {
1469
1470 case Instruction::BitCast:
1471 case Instruction::GetElementPtr:
1472 case Instruction::AddrSpaceCast:
1473 FlowsToReturn.insert(RVI->getOperand(0));
1474 continue;
1475 case Instruction::Select: {
1477 FlowsToReturn.insert(SI->getTrueValue());
1478 FlowsToReturn.insert(SI->getFalseValue());
1479 continue;
1480 }
1481 case Instruction::PHI: {
1484 continue;
1485 }
1486
1487
1488 case Instruction::Alloca:
1489 break;
1490 case Instruction::Call:
1491 case Instruction::Invoke: {
1493 if (CB.hasRetAttr(Attribute::NoAlias))
1494 break;
1496 break;
1497 [[fallthrough]];
1498 }
1499 default:
1500 return false;
1501 }
1502
1504 return false;
1505 }
1506
1507 return true;
1508}
1509
1510
1513
1514
1516
1517 if (F->returnDoesNotAlias())
1518 continue;
1519
1520
1521
1522
1523 if (->hasExactDefinition())
1524 return;
1525
1526
1527
1528 if (->getReturnType()->isPointerTy())
1529 continue;
1530
1532 return;
1533 }
1534
1536 if (F->returnDoesNotAlias() ||
1537 ->getReturnType()->isPointerTy())
1538 continue;
1539
1540 F->setReturnDoesNotAlias();
1541 ++NumNoAlias;
1543 }
1544}
1545
1546
1547
1548
1549
1550
1551
1552
1554 bool &Speculative) {
1555 assert(F->getReturnType()->isPointerTy() &&
1556 "nonnull only meaningful on pointer types");
1557 Speculative = false;
1558
1562 FlowsToReturn.insert(Ret->getReturnValue());
1563
1564 auto &DL = F->getDataLayout();
1565
1566 for (unsigned i = 0; i != FlowsToReturn.size(); ++i) {
1567 Value *RetVal = FlowsToReturn[i];
1568
1569
1571 continue;
1572
1573
1574
1576 if (!RVI)
1577 return false;
1579
1580 case Instruction::BitCast:
1581 case Instruction::AddrSpaceCast:
1583 continue;
1584 case Instruction::GetElementPtr:
1587 continue;
1588 }
1589 return false;
1590 case Instruction::Select: {
1592 FlowsToReturn.insert(SI->getTrueValue());
1593 FlowsToReturn.insert(SI->getFalseValue());
1594 continue;
1595 }
1596 case Instruction::PHI: {
1600 continue;
1601 }
1602 case Instruction::Call:
1603 case Instruction::Invoke: {
1606
1607
1608 if (Callee && SCCNodes.count(Callee)) {
1609 Speculative = true;
1610 continue;
1611 }
1612 return false;
1613 }
1614 default:
1615 return false;
1616 };
1617 llvm_unreachable("should have either continued or returned");
1618 }
1619
1620 return true;
1621}
1622
1623
1626
1627
1628 bool SCCReturnsNonNull = true;
1629
1630
1631
1633
1634 if (F->getAttributes().hasRetAttr(Attribute::NonNull))
1635 continue;
1636
1637
1638
1639
1640 if (->hasExactDefinition())
1641 return;
1642
1643
1644
1645 if (->getReturnType()->isPointerTy())
1646 continue;
1647
1648 bool Speculative = false;
1650 if (!Speculative) {
1651
1652
1654 << " as nonnull\n");
1655 F->addRetAttr(Attribute::NonNull);
1656 ++NumNonNullReturn;
1658 }
1659 continue;
1660 }
1661
1662
1663 SCCReturnsNonNull = false;
1664 }
1665
1666 if (SCCReturnsNonNull) {
1668 if (F->getAttributes().hasRetAttr(Attribute::NonNull) ||
1669 ->getReturnType()->isPointerTy())
1670 continue;
1671
1672 LLVM_DEBUG(dbgs() << "SCC marking " << F->getName() << " as nonnull\n");
1673 F->addRetAttr(Attribute::NonNull);
1674 ++NumNonNullReturn;
1676 }
1677 }
1678}
1679
1680
1683
1684
1686
1687 AttributeList Attrs = F->getAttributes();
1688 if (Attrs.hasRetAttr(Attribute::NoUndef))
1689 continue;
1690
1691
1692
1693
1694 if (->hasExactDefinition())
1695 return;
1696
1697
1698
1699
1700 if (F->hasFnAttribute(Attribute::SanitizeMemory))
1701 continue;
1702
1703 if (F->getReturnType()->isVoidTy())
1704 continue;
1705
1709
1710 Value *RetVal = Ret->getReturnValue();
1712 return false;
1713
1714
1715
1716
1717 if (Attrs.hasRetAttr(Attribute::NonNull) &&
1719 return false;
1720
1723 return false;
1724
1725 Attribute Attr = Attrs.getRetAttr(Attribute::Range);
1729 return false;
1730 }
1731 return true;
1732 })) {
1733 F->addRetAttr(Attribute::NoUndef);
1734 ++NumNoUndefReturn;
1736 }
1737 }
1738}
1739
1740namespace {
1741
1742
1743
1744
1745
1746
1747
1748class AttributeInferer {
1749public:
1750
1751 struct InferenceDescriptor {
1752
1753
1754
1755
1756
1757 std::function<bool(const Function &)> SkipFunction;
1758
1759
1760 std::function<bool(Instruction &)> InstrBreaksAttribute;
1761
1762
1763 std::function<void(Function &)> SetAttribute;
1764
1765
1766 Attribute::AttrKind AKind;
1767
1768
1769
1770 bool RequiresExactDefinition;
1771
1772 InferenceDescriptor(Attribute::AttrKind AK,
1773 std::function<bool(const Function &)> SkipFunc,
1774 std::function<bool(Instruction &)> InstrScan,
1775 std::function<void(Function &)> SetAttr,
1776 bool ReqExactDef)
1777 : SkipFunction(SkipFunc), InstrBreaksAttribute(InstrScan),
1778 SetAttribute(SetAttr), AKind(AK),
1779 RequiresExactDefinition(ReqExactDef) {}
1780 };
1781
1782private:
1784
1785public:
1786 void registerAttrInference(InferenceDescriptor AttrInference) {
1787 InferenceDescriptors.push_back(AttrInference);
1788 }
1789
1790 void run(const SCCNodeSet &SCCNodes, SmallPtrSet<Function *, 8> &Changed);
1791};
1792
1793
1794
1795void AttributeInferer::run(const SCCNodeSet &SCCNodes,
1796 SmallPtrSet<Function *, 8> &Changed) {
1798
1799
1800
1801 for (Function *F : SCCNodes) {
1802
1803
1804 if (InferInSCC.empty())
1805 return;
1806
1807
1810 return false;
1811
1812
1813
1814 return F->isDeclaration() ||
1815 (ID.RequiresExactDefinition && ->hasExactDefinition());
1816 });
1817
1818
1819
1822 InferInSCC, std::back_inserter(InferInThisFunc),
1823 [F](const InferenceDescriptor &ID) { return .SkipFunction(*F); });
1824
1825 if (InferInThisFunc.empty())
1826 continue;
1827
1828
1830 llvm::erase_if(InferInThisFunc, [&](const InferenceDescriptor &ID) {
1831 if (.InstrBreaksAttribute(I))
1832 return false;
1833
1834
1835 llvm::erase_if(InferInSCC, [&ID](const InferenceDescriptor &D) {
1836 return D.AKind == ID.AKind;
1837 });
1838
1839 return true;
1840 });
1841
1842 if (InferInThisFunc.empty())
1843 break;
1844 }
1845 }
1846
1847 if (InferInSCC.empty())
1848 return;
1849
1850 for (Function *F : SCCNodes)
1851
1852
1853
1854
1855 for (auto &ID : InferInSCC) {
1857 continue;
1860 }
1861}
1862
1863struct SCCNodesResult {
1864 SCCNodeSet SCCNodes;
1865};
1866
1867}
1868
1869
1871 const SCCNodeSet &SCCNodes) {
1873
1874
1877}
1878
1879
1881 if (.mayThrow( true))
1882 return false;
1884 if (Function *Callee = CI->getCalledFunction()) {
1885
1886
1887
1888 if (SCCNodes.contains(Callee))
1889 return false;
1890 }
1891 }
1892 return true;
1893}
1894
1895
1898 if (!CB)
1899 return false;
1900
1901 if (CB->hasFnAttr(Attribute::NoFree))
1902 return false;
1903
1904
1906 if (SCCNodes.contains(Callee))
1907 return false;
1908
1909 return true;
1910}
1911
1912
1913
1914
1915
1916
1918 if (->isAtomic())
1919 return false;
1920
1922
1925 return true;
1927 return ->isUnordered();
1929 return !LI->isUnordered();
1930 else {
1932 }
1933}
1934
1936
1937 if (I.isVolatile())
1938 return true;
1939
1940
1942 return true;
1943
1945 if (!CB)
1946
1947 return false;
1948
1949 if (CB->hasFnAttr(Attribute::NoSync))
1950 return false;
1951
1952
1953
1954
1956 if (->isVolatile())
1957 return false;
1958
1959
1961 if (SCCNodes.contains(Callee))
1962 return false;
1963
1964 return true;
1965}
1966
1967
1968
1969
1972 AttributeInferer AI;
1973
1974
1975
1976
1977
1978
1979 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
1980 Attribute::Convergent,
1981
1982 [](const Function &F) { return .isConvergent(); },
1983
1986 },
1988 LLVM_DEBUG(dbgs() << "Removing convergent attr from fn " << F.getName()
1989 << "\n");
1990 F.setNotConvergent();
1991 },
1992 false});
1993
1994 AI.run(SCCNodes, Changed);
1995}
1996
1997
1998
1999
2000
2003 AttributeInferer AI;
2004
2006
2007
2008
2009
2010
2011 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
2012 Attribute::NoUnwind,
2013
2014 [](const Function &F) { return F.doesNotThrow(); },
2015
2018 },
2021 << "Adding nounwind attr to fn " << F.getName() << "\n");
2022 F.setDoesNotThrow();
2023 ++NumNoUnwind;
2024 },
2025 true});
2026
2028
2029
2030
2031
2032
2033
2034 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
2035 Attribute::NoFree,
2036
2037 [](const Function &F) { return F.doesNotFreeMemory(); },
2038
2041 },
2044 << "Adding nofree attr to fn " << F.getName() << "\n");
2045 F.setDoesNotFreeMemory();
2046 ++NumNoFree;
2047 },
2048 true});
2049
2050 AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
2051 Attribute::NoSync,
2052
2053 [](const Function &F) { return F.hasNoSync(); },
2054
2057 },
2060 << "Adding nosync attr to fn " << F.getName() << "\n");
2061 F.setNoSync();
2062 ++NumNoSync;
2063 },
2064 true});
2065
2066
2067 AI.run(SCCNodes, Changed);
2068}
2069
2070
2071
2072
2073
2074
2075
2076
2078 bool AnyFunctionsAddressIsTaken = true) {
2079 for (const auto &BB : F) {
2080 for (const auto &I : BB.instructionsWithoutDebug()) {
2083 if (!Callee || Callee == &F)
2084 return true;
2085
2086 if (Callee->doesNotRecurse())
2087 continue;
2088
2089 if (!AnyFunctionsAddressIsTaken ||
2090 (Callee->isDeclaration() &&
2091 Callee->hasFnAttribute(Attribute::NoCallback)))
2092 continue;
2093 return true;
2094 }
2095 }
2096 }
2097 return false;
2098}
2099
2102
2103
2104
2105 if (SCCNodes.size() != 1)
2106 return;
2107
2108 Function *F = *SCCNodes.begin();
2109 if ( ||
->hasExactDefinition() || F->doesNotRecurse())
2110 return;
2112
2113
2114
2115 F->setDoesNotRecurse();
2116 ++NumNoRecurse;
2118 }
2119}
2120
2121
2125 if ( ||
->hasExactDefinition() || F->hasFnAttribute(Attribute::Naked) ||
2126 F->doesNotReturn())
2127 continue;
2128
2130 F->setDoesNotReturn();
2132 }
2133 }
2134}
2135
2138 ColdPaths[&F.front()] = false;
2141
2142 while (!Jobs.empty()) {
2144
2145
2146
2147
2150 return CB->hasFnAttr(Attribute::Cold);
2151 return false;
2152 })) {
2153 ColdPaths[BB] = true;
2154 continue;
2155 }
2156
2158
2159 if (Succs.empty())
2160 return false;
2161
2162
2163
2164
2165
2166
2168
2169
2170 auto [Iter, Inserted] = ColdPaths.try_emplace(Succ, false);
2171 if (!Inserted) {
2172 if (Iter->second)
2173 continue;
2174 return false;
2175 }
2177 }
2178 }
2179 return true;
2180}
2181
2182
2186 if ( ||
->hasExactDefinition() || F->hasFnAttribute(Attribute::Naked) ||
2187 F->hasFnAttribute(Attribute::Cold) || F->hasFnAttribute(Attribute::Hot))
2188 continue;
2189
2190
2192 F->addFnAttr(Attribute::Cold);
2193 ++NumCold;
2195 continue;
2196 }
2197 }
2198}
2199
2201
2202
2203
2204 if (.hasExactDefinition())
2205 return false;
2206
2207
2208 if (F.mustProgress() && F.onlyReadsMemory())
2209 return true;
2210
2211
2212 if (F.isDeclaration())
2213 return false;
2214
2215
2216
2219 if (!Backedges.empty())
2220 return false;
2221
2222
2223
2225 return I.willReturn();
2226 });
2227}
2228
2229
2234 continue;
2235
2236 F->setWillReturn();
2237 NumWillReturn++;
2239 }
2240}
2241
2243 SCCNodesResult Res;
2245 if ( || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked) ||
2246 F->isPresplitCoroutine()) {
2247
2248 continue;
2249 }
2250
2251 Res.SCCNodes.insert(F);
2252 }
2253 return Res;
2254}
2255
2256template
2259 bool ArgAttrsOnly) {
2261
2262
2263 if (Nodes.SCCNodes.empty())
2264 return {};
2265
2267 if (ArgAttrsOnly) {
2268
2269
2270
2273 }
2274
2287
2288
2289
2290
2291
2292 for (Function *F : Nodes.SCCNodes)
2293 if (F)
2296
2298}
2299
2304
2305
2306
2307 bool ArgAttrsOnly = false;
2308 if (C.size() == 1 && SkipNonRecursive) {
2310 if (->lookup(N))
2311 ArgAttrsOnly = true;
2312 }
2313
2316
2317
2318
2321 };
2322
2325 Functions.push_back(&N.getFunction());
2326 }
2327
2328 auto ChangedFunctions =
2330 if (ChangedFunctions.empty())
2332
2333
2334
2336
2340
2341
2342
2343
2344 for (auto *U : Changed->users()) {
2346 if (Call->getCalledOperand() == Changed)
2347 FAM.invalidate(*Call->getFunction(), FuncPA);
2348 }
2349 }
2350 }
2351
2353
2355
2357 return PA;
2358}
2359
2363 OS, MapClassName2PassName);
2364 if (SkipNonRecursive)
2365 OS << "";
2366}
2367
2368template
2372 Functions.push_back(I->getFunction());
2373 }
2374
2376}
2377
2379
2380
2381
2382 assert(.isDeclaration() && "Cannot deduce norecurse without a definition!");
2383 assert(.doesNotRecurse() &&
2384 "This function has already been deduced as norecurs!");
2385 assert(F.hasInternalLinkage() &&
2386 "Can only do top-down deduction for internal linkage functions!");
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396 for (auto &U : F.uses()) {
2398 if ()
2399 return false;
2401 if (!CB || !CB->isCallee(&U) ||
2402 !CB->getParent()->getParent()->doesNotRecurse())
2403 return false;
2404 }
2405 F.setDoesNotRecurse();
2406 ++NumNoRecurse;
2407 return true;
2408}
2409
2411
2412
2413
2414
2415
2416
2417
2418
2423 if (SCC.size() != 1)
2424 continue;
2425 Function &F = SCC.begin()->getFunction();
2426 if (.isDeclaration() &&
.doesNotRecurse() && F.hasInternalLinkage())
2428 }
2429 }
2433
2435}
2436
2440
2443
2446 return PA;
2447}
2448
2451
2452
2453
2454
2455
2456
2457 bool AnyFunctionsAddressIsTaken = false;
2459 if (F.isDeclaration() || F.doesNotRecurse())
2460 continue;
2461 if (.hasLocalLinkage() || F.hasAddressTaken()) {
2462 AnyFunctionsAddressIsTaken = true;
2463 break;
2464 }
2465 }
2466
2467
2468
2472
2474
2475
2476 if (RC.size() > 1)
2477 continue;
2478
2479
2480
2482 if (S.size() > 1)
2483 continue;
2484
2485
2487 if (.hasExactDefinition() || F.doesNotRecurse())
2488 continue;
2489
2490
2491
2492
2494 F.setDoesNotRecurse();
2495 ++NumNoRecurse;
2497 }
2498 }
2499
2503 else
2505 return PA;
2506}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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, const LibcallLoweringInfo &Libcalls, AssumptionCache *AC)
static SmallPtrSet< Function *, 8 > deriveAttrsInPostOrder(ArrayRef< Function * > Functions, AARGetterT &&AARGetter, bool ArgAttrsOnly)
Definition FunctionAttrs.cpp:2258
static Attribute::AttrKind determinePointerAccessAttrs(Argument *A, const SmallPtrSet< Argument *, 8 > &SCCNodes)
Returns Attribute::None, Attribute::ReadOnly or Attribute::ReadNone.
Definition FunctionAttrs.cpp:861
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)
Definition FunctionAttrs.cpp:1119
static bool allPathsGoThroughCold(Function &F)
Definition FunctionAttrs.cpp:2136
static bool addAccessAttr(Argument *A, Attribute::AttrKind R)
Definition FunctionAttrs.cpp:1091
static FunctionSummary * calculatePrevailingSummary(ValueInfo VI, DenseMap< ValueInfo, FunctionSummary * > &CachedPrevailingSummary, function_ref< bool(GlobalValue::GUID, const GlobalValueSummary *)> IsPrevailing)
Definition FunctionAttrs.cpp:315
static void addMemoryAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter, SmallPtrSet< Function *, 8 > &Changed)
Deduce readonly/readnone/writeonly attributes for the SCC.
Definition FunctionAttrs.cpp:274
static bool addArgumentAttrsFromCallsites(Function &F)
If a callsite has arguments that are also arguments to the parent function, try to propagate attribut...
Definition FunctionAttrs.cpp:1052
static void addCapturesStat(CaptureInfo CI)
Definition FunctionAttrs.cpp:112
static bool isOrderedAtomic(Instruction *I)
Definition FunctionAttrs.cpp:1917
static void addArgLocs(MemoryEffects &ME, const CallBase *Call, ModRefInfo ArgMR, AAResults &AAR)
Definition FunctionAttrs.cpp:147
static bool isFunctionMallocLike(Function *F, const SCCNodeSet &SCCNodes)
Tests whether a function is "malloc-like".
Definition FunctionAttrs.cpp:1448
static void addColdAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Definition FunctionAttrs.cpp:2183
static bool mayHaveRecursiveCallee(Function &F, bool AnyFunctionsAddressIsTaken=true)
Definition FunctionAttrs.cpp:2077
static void addNoReturnAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Definition FunctionAttrs.cpp:2122
static cl::opt< bool > DisableNoUnwindInference("disable-nounwind-inference", cl::Hidden, cl::desc("Stop inferring nounwind attribute during function-attrs pass"))
static void addWillReturn(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Definition FunctionAttrs.cpp:2230
static void addNonNullAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Deduce nonnull attributes for the SCC.
Definition FunctionAttrs.cpp:1624
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...
Definition FunctionAttrs.cpp:172
static bool InstrBreaksNonThrowing(Instruction &I, const SCCNodeSet &SCCNodes)
Helper for NoUnwind inference predicate InstrBreaksAttribute.
Definition FunctionAttrs.cpp:1880
static void inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Infer attributes from all functions in the SCC by scanning every instruction for compliance to the at...
Definition FunctionAttrs.cpp:2001
static bool isReturnNonNull(Function *F, const SCCNodeSet &SCCNodes, bool &Speculative)
Tests whether this function is known to not return null.
Definition FunctionAttrs.cpp:1553
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 bool InstrBreaksNoSync(Instruction &I, const SCCNodeSet &SCCNodes)
Definition FunctionAttrs.cpp:1935
static bool deduceFunctionAttributeInRPO(Module &M, LazyCallGraph &CG)
Definition FunctionAttrs.cpp:2410
static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes)
Helper for NoFree inference predicate InstrBreaksAttribute.
Definition FunctionAttrs.cpp:1896
static void addNoAliasAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Deduce noalias attributes for the SCC.
Definition FunctionAttrs.cpp:1511
static bool addNoRecurseAttrsTopDown(Function &F)
Definition FunctionAttrs.cpp:2378
static void addLocAccess(MemoryEffects &ME, const MemoryLocation &Loc, ModRefInfo MR, AAResults &AAR)
Definition FunctionAttrs.cpp:125
static void inferConvergent(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Attempt to remove convergent function attribute when possible.
Definition FunctionAttrs.cpp:1970
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)
Definition FunctionAttrs.cpp:2242
static bool InstrBreaksNonConvergent(Instruction &I, const SCCNodeSet &SCCNodes)
Helper for non-Convergent inference predicate InstrBreaksAttribute.
Definition FunctionAttrs.cpp:1870
static void addArgumentAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed, bool SkipInitializes)
Deduce nocapture attributes for the SCC.
Definition FunctionAttrs.cpp:1239
static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Definition FunctionAttrs.cpp:2100
static bool functionWillReturn(const Function &F)
Definition FunctionAttrs.cpp:2200
static void addNoUndefAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Deduce noundef attributes for the SCC.
Definition FunctionAttrs.cpp:1681
static void addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes, SmallPtrSet< Function *, 8 > &Changed)
Deduce returned attributes for the SCC.
Definition FunctionAttrs.cpp:1003
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
ModuleAnalysisManager MAM
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 ...
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet 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.
LLVM_ABI ModRefInfo getModRefInfoMask(const MemoryLocation &Loc, bool IgnoreLocals=false)
Returns a bitmask that should be unconditionally applied to the ModRef info of a memory location.
LLVM_ABI 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 " (e....
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.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Functions, function parameters, and return types can have attributes to indicate how they should be t...
LLVM_ABI const ConstantRange & getRange() const
Returns the value of the range attribute.
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
LLVM_ABI 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.
static LLVM_ABI Attribute getWithCaptureInfo(LLVMContext &Context, CaptureInfo CI)
bool isValid() const
Return true if the attribute is any kind of attribute.
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...
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI CaptureInfo getCaptureInfo(unsigned OpNo) const
Return which pointer components this operand may capture.
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.
Represents which components of the pointer may be captured in which location.
static CaptureInfo none()
Create CaptureInfo that does not capture any components of the pointer.
static CaptureInfo retOnly(CaptureComponents RetComponents=CaptureComponents::All)
Create CaptureInfo that may only capture via the return value.
static CaptureInfo all()
Create CaptureInfo that may capture all components of the pointer.
This class represents a list of constant ranges.
LLVM_ABI void subtract(const ConstantRange &SubRange)
LLVM_ABI 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
LLVM_ABI ConstantRangeList intersectWith(const ConstantRangeList &CRL) const
Return the range list that results from the intersection of this ConstantRangeList with another Const...
LLVM_ABI 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.
LLVM_ABI bool contains(const APInt &Val) const
Return true if the specified value is in the set.
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)
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)
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
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.
LLVM_ABI void buildRefSCCs()
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)
static MemoryEffectsBase inaccessibleMemOnly(ModRefInfo MR=ModRefInfo::ModRef)
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
static MemoryEffectsBase none()
static MemoryEffectsBase unknown()
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...
static LLVM_ABI 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.
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Definition FunctionAttrs.cpp:2449
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.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Return a value (possibly void), from a function.
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
Definition FunctionAttrs.cpp:2438
This class represents the LLVM 'select' instruction.
size_type size() const
Determine the number of elements in the SetVector.
void insert_range(Range &&R)
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.
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.
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ 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.
NodeAddr< UseNode * > Use
NodeAddr< NodeBase * > Node
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
@ Low
Lower the current thread's priority such that it does not affect foreground tasks significantly.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
Definition FunctionAttrs.cpp:267
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
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)
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
LLVM_ABI 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.
Definition FunctionAttrs.cpp:419
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.
LLVM_ABI ConstantRange computeConstantRange(const Value *V, bool ForSigned, bool UseInstrInfo=true, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Determine the possible constant range of an integer or vector of integer value.
AnalysisManager< LazyCallGraph::SCC, LazyCallGraph & > CGSCCAnalysisManager
The CGSCC analysis manager.
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)
LLVM_ABI 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)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
CaptureComponents
Components of the pointer that may be captured.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI 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.
@ Ref
The access may reference the value stored in memory.
@ ModRef
The access may reference and may modify the value stored in memory.
@ Mod
The access may modify the value stored in memory.
@ NoModRef
The access neither references nor modifies the value stored in memory.
@ ArgMem
Access to memory via argument pointers.
LLVM_ABI const Value * getUnderlyingObjectAggressive(const Value *V)
Like getUnderlyingObject(), but will try harder to find a single underlying object.
LLVM_ABI bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, unsigned MaxUsesToExplore=0)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
LLVM_ABI bool isGuaranteedToTransferExecutionToSuccessor(const Instruction *I)
Return true if this function can prove that the instruction I will always transfer execution to one o...
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
LLVM_ABI bool inferAttributesFromOthers(Function &F)
If we can infer one attribute from another on the declaration of a function, explicitly materialize t...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
bool capturesAll(CaptureComponents CC)
bool capturesNothing(CaptureComponents CC)
bool isNoModRef(const ModRefInfo MRI)
LLVM_ABI 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.
LLVM_ABI bool isIdentifiedObject(const Value *V)
Return true if this pointer refers to a distinct and identifiable object.
bool capturesAnyProvenance(CaptureComponents CC)
bool isRefSet(const ModRefInfo MRI)
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI bool canReturn(const Function &F)
Return true if there is at least a path through which F can return, false if there is no such path.
This struct is a compact representation of a valid (non-zero power of two) alignment.
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.
Flags specific to function summaries.
SmallVectorImpl< ArgumentGraphNode * >::iterator ChildIteratorType
Definition FunctionAttrs.cpp:839
static ChildIteratorType child_begin(NodeRef N)
Definition FunctionAttrs.cpp:842
static ChildIteratorType child_end(NodeRef N)
Definition FunctionAttrs.cpp:843
ArgumentGraphNode * NodeRef
Definition FunctionAttrs.cpp:838
static NodeRef getEntryNode(NodeRef A)
Definition FunctionAttrs.cpp:841
static ChildIteratorType nodes_end(ArgumentGraph *AG)
Definition FunctionAttrs.cpp:854
static NodeRef getEntryNode(ArgumentGraph *AG)
Definition FunctionAttrs.cpp:848
static ChildIteratorType nodes_begin(ArgumentGraph *AG)
Definition FunctionAttrs.cpp:850
typename ArgumentGraph *::UnknownGraphTypeError NodeRef
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
A CRTP mix-in to automatically provide informational APIs needed for passes.
LLVM_ABI PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, LazyCallGraph &CG, CGSCCUpdateResult &UR)
Definition FunctionAttrs.cpp:2300
LLVM_ABI void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)
Definition FunctionAttrs.cpp:2360
CaptureComponents UseCC
Components captured by this use.
Struct that holds a reference to a particular GUID in a global value summary.