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 (Call->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 (Loc) {

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];

542 Node.Definition = 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 (F || F->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

772 for (Use &U : A.uses())

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

893 for (Use &UU : I->uses())

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)) {

917 for (Use &UU : CB.uses())

918 if (Visited.insert(&UU).second)

922

923

924

925

927

928 if (I->getType()->isVoidTy())

929 for (Use &UU : I->uses())

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 (isRefSet(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 (F->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 (Info.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 (F->hasExactDefinition())

1260 continue;

1261

1264

1265

1266

1267 if (F->onlyReadsMemory() && F->doesNotThrow() && F->willReturn() &&

1268 F->getReturnType()->isVoidTy()) {

1270 if (A.getType()->isPointerTy() && A.hasNoCaptureAttr()) {

1273 ++NumCapturesNone;

1275 }

1276 }

1277 continue;

1278 }

1279

1281 if (A.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]);

1303 if (Use != &A)

1304 HasNonLocalUses = true;

1305 }

1306 }

1307 }

1308

1309 }

1310 if (!HasNonLocalUses && A.onlyReadsMemory()) {

1311

1312

1313

1314

1315 if (DetermineAccessAttrsForSingleton(&A))

1317 }

1318 if (!SkipInitializes && A.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

1416 if (A == B)

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 (F->hasExactDefinition())

1524 return;

1525

1526

1527

1528 if (F->getReturnType()->isPointerTy())

1529 continue;

1530

1532 return;

1533 }

1534

1536 if (F->returnDoesNotAlias() ||

1537 F->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 (F->hasExactDefinition())

1641 return;

1642

1643

1644

1645 if (F->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 F->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 (F->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

1809 if (ID.SkipFunction(*F))

1810 return false;

1811

1812

1813

1814 return F->isDeclaration() ||

1815 (ID.RequiresExactDefinition && F->hasExactDefinition());

1816 });

1817

1818

1819

1822 InferInSCC, std::back_inserter(InferInThisFunc),

1823 [F](const InferenceDescriptor &ID) { return ID.SkipFunction(*F); });

1824

1825 if (InferInThisFunc.empty())

1826 continue;

1827

1828

1830 llvm::erase_if(InferInThisFunc, [&](const InferenceDescriptor &ID) {

1831 if (ID.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) {

1856 if (ID.SkipFunction(*F))

1857 continue;

1859 ID.SetAttribute(*F);

1860 }

1861}

1862

1863struct SCCNodesResult {

1864 SCCNodeSet SCCNodes;

1865};

1866

1867}

1868

1869

1871 const SCCNodeSet &SCCNodes) {

1873

1874

1877}

1878

1879

1881 if (I.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 (I->isAtomic())

1919 return false;

1920

1922

1925 return true;

1927 return SI->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 (MI->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 F.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 (F || F->hasExactDefinition() || F->doesNotRecurse())

2110 return;

2112

2113

2114

2115 F->setDoesNotRecurse();

2116 ++NumNoRecurse;

2118 }

2119}

2120

2121

2125 if (F || F->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 (F || F->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 (F.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 || 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 (N->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(F.isDeclaration() && "Cannot deduce norecurse without a definition!");

2383 assert(F.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 (I)

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 (F.isDeclaration() && F.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 (F.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 (F.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.