LLVM: lib/Transforms/ObjCARC/ObjCARCOpts.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

67#include

68#include

69#include

70

71using namespace llvm;

73

74#define DEBUG_TYPE "objc-arc-opts"

75

78 cl::desc("Maximum number of ptr states the optimizer keeps track of"),

80

81

82

83

84

85

87

88

90 return nullptr;

91

96 if (GEP->hasAllZeroIndices())

102 return nullptr;

103 return Arg;

104 }

105

106

107

109 for (const User *U : Arg->users())

111 return nullptr;

112

113 return Arg;

114 }

115

116 return nullptr;

117}

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159STATISTIC(NumNoops, "Number of no-op objc calls eliminated");

160STATISTIC(NumPartialNoops, "Number of partially no-op objc calls eliminated");

161STATISTIC(NumAutoreleases,"Number of autoreleases converted to releases");

163 "retain+autoreleases eliminated");

164STATISTIC(NumRRs, "Number of retain+release paths eliminated");

165STATISTIC(NumPeeps, "Number of calls peephole-optimized");

166#ifndef NDEBUG

168 "Number of retains before optimization");

170 "Number of releases before optimization");

172 "Number of retains after optimization");

174 "Number of releases after optimization");

175#endif

176

177namespace {

178

179

180 class BBState {

181

182

183 unsigned TopDownPathCount = 0;

184

185

186 unsigned BottomUpPathCount = 0;

187

188

189

191

192

193

195

196

197

199

200

201

203

204 public:

206

207 BBState() = default;

208

209 using top_down_ptr_iterator = decltype(PerPtrTopDown)::iterator;

210 using const_top_down_ptr_iterator = decltype(PerPtrTopDown)::const_iterator;

211

212 top_down_ptr_iterator top_down_ptr_begin() { return PerPtrTopDown.begin(); }

213 top_down_ptr_iterator top_down_ptr_end() { return PerPtrTopDown.end(); }

214 const_top_down_ptr_iterator top_down_ptr_begin() const {

215 return PerPtrTopDown.begin();

216 }

217 const_top_down_ptr_iterator top_down_ptr_end() const {

218 return PerPtrTopDown.end();

219 }

220 bool hasTopDownPtrs() const {

221 return !PerPtrTopDown.empty();

222 }

223

224 unsigned top_down_ptr_list_size() const {

225 return std::distance(top_down_ptr_begin(), top_down_ptr_end());

226 }

227

228 using bottom_up_ptr_iterator = decltype(PerPtrBottomUp)::iterator;

229 using const_bottom_up_ptr_iterator =

230 decltype(PerPtrBottomUp)::const_iterator;

231

232 bottom_up_ptr_iterator bottom_up_ptr_begin() {

233 return PerPtrBottomUp.begin();

234 }

235 bottom_up_ptr_iterator bottom_up_ptr_end() { return PerPtrBottomUp.end(); }

236 const_bottom_up_ptr_iterator bottom_up_ptr_begin() const {

237 return PerPtrBottomUp.begin();

238 }

239 const_bottom_up_ptr_iterator bottom_up_ptr_end() const {

240 return PerPtrBottomUp.end();

241 }

242 bool hasBottomUpPtrs() const {

243 return !PerPtrBottomUp.empty();

244 }

245

246 unsigned bottom_up_ptr_list_size() const {

247 return std::distance(bottom_up_ptr_begin(), bottom_up_ptr_end());

248 }

249

250

251

252 void SetAsEntry() { TopDownPathCount = 1; }

253

254

255

256 void SetAsExit() { BottomUpPathCount = 1; }

257

258

259

260

261 TopDownPtrState &getPtrTopDownState(const Value *Arg) {

262 return PerPtrTopDown[Arg];

263 }

264

265

266

267

268 BottomUpPtrState &getPtrBottomUpState(const Value *Arg) {

269 return PerPtrBottomUp[Arg];

270 }

271

272

273

274 bottom_up_ptr_iterator findPtrBottomUpState(const Value *Arg) {

275 return PerPtrBottomUp.find(Arg);

276 }

277

278 void clearBottomUpPointers() {

279 PerPtrBottomUp.clear();

280 }

281

282 void clearTopDownPointers() {

283 PerPtrTopDown.clear();

284 }

285

286 void InitFromPred(const BBState &Other);

287 void InitFromSucc(const BBState &Other);

288 void MergePred(const BBState &Other);

289 void MergeSucc(const BBState &Other);

290

291

292

293

294

295

296

297 bool GetAllPathCountWithOverflow(unsigned &PathCount) const {

300 return true;

301 unsigned long long Product =

302 (unsigned long long)TopDownPathCount*BottomUpPathCount;

303

304

305 return (Product >> 32) ||

307 }

308

309

311

312 edge_iterator pred_begin() const { return Preds.begin(); }

313 edge_iterator pred_end() const { return Preds.end(); }

314 edge_iterator succ_begin() const { return Succs.begin(); }

315 edge_iterator succ_end() const { return Succs.end(); }

316

317 void addSucc(BasicBlock *Succ) { Succs.push_back(Succ); }

318 void addPred(BasicBlock *Pred) { Preds.push_back(Pred); }

319

320 bool isExit() const { return Succs.empty(); }

321 };

322

323}

324

326

327namespace llvm {

328

330

331}

332

333void BBState::InitFromPred(const BBState &Other) {

334 PerPtrTopDown = Other.PerPtrTopDown;

335 TopDownPathCount = Other.TopDownPathCount;

336}

337

338void BBState::InitFromSucc(const BBState &Other) {

339 PerPtrBottomUp = Other.PerPtrBottomUp;

340 BottomUpPathCount = Other.BottomUpPathCount;

341}

342

343

344

345void BBState::MergePred(const BBState &Other) {

346 if (TopDownPathCount == OverflowOccurredValue)

347 return;

348

349

350

351 TopDownPathCount += Other.TopDownPathCount;

352

353

354

355

356 if (TopDownPathCount == OverflowOccurredValue) {

357 clearTopDownPointers();

358 return;

359 }

360

361

362

363 if (TopDownPathCount < Other.TopDownPathCount) {

364 TopDownPathCount = OverflowOccurredValue;

365 clearTopDownPointers();

366 return;

367 }

368

369

370

371

372 for (auto MI = Other.top_down_ptr_begin(), ME = Other.top_down_ptr_end();

373 MI != ME; ++MI) {

374 auto Pair = PerPtrTopDown.insert(*MI);

375 Pair.first->second.Merge(Pair.second ? TopDownPtrState() : MI->second,

376 true);

377 }

378

379

380

381 for (auto MI = top_down_ptr_begin(), ME = top_down_ptr_end(); MI != ME; ++MI)

382 if (Other.PerPtrTopDown.find(MI->first) == Other.PerPtrTopDown.end())

383 MI->second.Merge(TopDownPtrState(), true);

384}

385

386

387

388void BBState::MergeSucc(const BBState &Other) {

389 if (BottomUpPathCount == OverflowOccurredValue)

390 return;

391

392

393

394 BottomUpPathCount += Other.BottomUpPathCount;

395

396

397

398

399 if (BottomUpPathCount == OverflowOccurredValue) {

400 clearBottomUpPointers();

401 return;

402 }

403

404

405

406 if (BottomUpPathCount < Other.BottomUpPathCount) {

407 BottomUpPathCount = OverflowOccurredValue;

408 clearBottomUpPointers();

409 return;

410 }

411

412

413

414

415 for (auto MI = Other.bottom_up_ptr_begin(), ME = Other.bottom_up_ptr_end();

416 MI != ME; ++MI) {

417 auto Pair = PerPtrBottomUp.insert(*MI);

418 Pair.first->second.Merge(Pair.second ? BottomUpPtrState() : MI->second,

419 false);

420 }

421

422

423

424 for (auto MI = bottom_up_ptr_begin(), ME = bottom_up_ptr_end(); MI != ME;

425 ++MI)

426 if (Other.PerPtrBottomUp.find(MI->first) == Other.PerPtrBottomUp.end())

427 MI->second.Merge(BottomUpPtrState(), false);

428}

429

431

432 OS << " TopDown State:\n";

433 if (!BBInfo.hasTopDownPtrs()) {

435 } else {

436 for (auto I = BBInfo.top_down_ptr_begin(), E = BBInfo.top_down_ptr_end();

437 I != E; ++I) {

439 OS << " Ptr: " << *I->first

440 << "\n KnownSafe: " << (P.IsKnownSafe()?"true":"false")

441 << "\n ImpreciseRelease: "

442 << (P.IsTrackingImpreciseReleases()?"true":"false") << "\n"

443 << " HasCFGHazards: "

444 << (P.IsCFGHazardAfflicted()?"true":"false") << "\n"

445 << " KnownPositive: "

446 << (P.HasKnownPositiveRefCount()?"true":"false") << "\n"

447 << " Seq: "

448 << P.GetSeq() << "\n";

449 }

450 }

451

452 OS << " BottomUp State:\n";

453 if (!BBInfo.hasBottomUpPtrs()) {

455 } else {

456 for (auto I = BBInfo.bottom_up_ptr_begin(), E = BBInfo.bottom_up_ptr_end();

457 I != E; ++I) {

459 OS << " Ptr: " << *I->first

460 << "\n KnownSafe: " << (P.IsKnownSafe()?"true":"false")

461 << "\n ImpreciseRelease: "

462 << (P.IsTrackingImpreciseReleases()?"true":"false") << "\n"

463 << " HasCFGHazards: "

464 << (P.IsCFGHazardAfflicted()?"true":"false") << "\n"

465 << " KnownPositive: "

466 << (P.HasKnownPositiveRefCount()?"true":"false") << "\n"

467 << " Seq: "

468 << P.GetSeq() << "\n";

469 }

470 }

471

472 return OS;

473}

474

475namespace {

476

477

478class ObjCARCOpt {

480 bool CFGChanged = false;

482

483

485

486

487

489

491

492

493

494 bool DisableRetainReleasePairing = false;

495

496

497

498 unsigned UsedInThisFunction;

499

501

505 void OptimizeIndividualCalls(Function &F);

506

507

508

511

512

513

514

518 const Value *&AutoreleaseRVArg);

519

520 void CheckForCFGHazards(const BasicBlock *BB,

522 BBState &MyStates) const;

525 BBState &MyStates);

529 bool VisitInstructionTopDown(

532 &ReleaseInsertPtToRCIdentityRoots);

533 bool VisitTopDown(

537 &ReleaseInsertPtToRCIdentityRoots);

541

542 void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove,

546

552 RRInfo &RetainsToMove, RRInfo &ReleasesToMove,

553 Value *Arg, bool KnownSafe,

554 bool &AnyPairsCompletelyEliminated);

555

559

560 void OptimizeWeakCalls(Function &F);

561

562 bool OptimizeSequences(Function &F);

563

564 void OptimizeReturns(Function &F);

565

566 void OptimizeAutoreleasePools(Function &F);

567

568 template

569 static void cloneOpBundlesIf(CallBase *CI,

576 }

577 }

578

579 void addOpBundleForFunclet(BasicBlock *BB,

580 SmallVectorImpl &OpBundles) {

581 if (!BlockEHColors.empty()) {

583 assert(CV.size() > 0 && "Uncolored block");

584 for (BasicBlock *EHPadBB : CV)

585 if (auto *EHPad =

588 return;

589 }

590 }

591 }

592

593#ifndef NDEBUG

594 void GatherStatistics(Function &F, bool AfterOptimization = false);

595#endif

596

597 public:

598 void init(Function &F);

599 bool run(Function &F, AAResults &AA);

600 bool hasCFGChanged() const { return CFGChanged; }

601};

602}

603

604

605

606bool

607ObjCARCOpt::OptimizeRetainRVCall(Function &F, Instruction *RetainRV) {

608

613 ++I;

615 ++I;

617 return false;

620 if (II->getNormalDest() == RetainRVParent) {

623 ++I;

625 return false;

626 }

627 }

628 }

629

631 "a bundled retainRV's argument should be a call");

632

633

635 ++NumPeeps;

636

637 LLVM_DEBUG(dbgs() << "Transforming objc_retainAutoreleasedReturnValue => "

638 "objc_retain since the operand is not a return value.\n"

639 "Old = "

641

642 Function *NewDecl = EP.get(ARCRuntimeEntryPointKind::Retain);

644

646

647 return false;

648}

649

650bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(

651 Function &F, Instruction *Inst, const Value *&Arg, ARCInstKind Class,

653 if (BundledInsts->contains(Inst))

654 return false;

655

656

658

659

662 if (Arg != AutoreleaseRVArg) {

663

665 if (!PN)

666 return false;

667

671 return false;

672 }

673

674

675 ++NumPeeps;

676 LLVM_DEBUG(dbgs() << "Found inlined objc_autoreleaseReturnValue '"

677 << *AutoreleaseRV << "' paired with '" << *Inst << "'\n");

678

679

684 if (Class == ARCInstKind::RetainRV) {

685

688 return true;

689 }

690

691

692

693 assert(Class == ARCInstKind::UnsafeClaimRV);

699 "Expected UnsafeClaimRV to be safe to tail call");

703

704

705 OptimizeIndividualCallImpl(F, Release, ARCInstKind::Release, Arg);

706 return true;

707}

708

709

710

711void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F,

714

716

717

718

720 return;

721

722 SmallVector<const Value *, 2> Users;

723 Users.push_back(Ptr);

724

725

728

729 do {

730 Ptr = Users.pop_back_val();

731 for (const User *U : Ptr->users()) {

733 return;

735 Users.push_back(U);

736 }

737 } while (Users.empty());

738

740 ++NumPeeps;

741

743 dbgs() << "Transforming objc_autoreleaseReturnValue => "

744 "objc_autorelease since its operand is not used as a return "

745 "value.\n"

746 "Old = "

748

750 Function *NewDecl = EP.get(ARCRuntimeEntryPointKind::Autorelease);

752 AutoreleaseRVCI->setTailCall(false);

753 Class = ARCInstKind::Autorelease;

754

756}

757

758

759

760void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {

761 LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeIndividualCalls ==\n");

762

763 UsedInThisFunction = 0;

764

765

766

767 Instruction *DelayedAutoreleaseRV = nullptr;

768 const Value *DelayedAutoreleaseRVArg = nullptr;

772 DelayedAutoreleaseRVArg = nullptr;

773 };

774 auto optimizeDelayedAutoreleaseRV = [&]() {

775 if (!DelayedAutoreleaseRV)

776 return;

777 OptimizeIndividualCallImpl(F, DelayedAutoreleaseRV,

778 ARCInstKind::AutoreleaseRV,

779 DelayedAutoreleaseRVArg);

780 setDelayedAutoreleaseRV(nullptr);

781 };

782 auto shouldDelayAutoreleaseRV = [&](Instruction *NonARCInst) {

783

784 if (!DelayedAutoreleaseRV)

785 return true;

786

787

788

789 if (NonARCInst->isTerminator())

790 return false;

791

792

793

794

795

796

797

798

800 if (!CB)

801 return true;

803 };

804

805

808

811 BundledInsts->insertRVCall(I->getIterator(), CI);

813 }

814

816

817

818 const Value *Arg = nullptr;

819 switch (Class) {

820 default:

821 optimizeDelayedAutoreleaseRV();

822 break;

823 case ARCInstKind::CallOrUser:

824 case ARCInstKind::User:

825 case ARCInstKind::None:

826

827

828

829 if (!shouldDelayAutoreleaseRV(Inst))

830 optimizeDelayedAutoreleaseRV();

831 continue;

832 case ARCInstKind::AutoreleaseRV:

833 optimizeDelayedAutoreleaseRV();

834 setDelayedAutoreleaseRV(Inst);

835 continue;

836 case ARCInstKind::RetainRV:

837 case ARCInstKind::UnsafeClaimRV:

838 if (DelayedAutoreleaseRV) {

839

840 if (OptimizeInlinedAutoreleaseRVCall(F, Inst, Arg, Class,

841 DelayedAutoreleaseRV,

842 DelayedAutoreleaseRVArg)) {

843 setDelayedAutoreleaseRV(nullptr);

844 continue;

845 }

846 optimizeDelayedAutoreleaseRV();

847 }

848 break;

849 }

850

851 OptimizeIndividualCallImpl(F, Inst, Class, Arg);

852 }

853

854

855 optimizeDelayedAutoreleaseRV();

856}

857

858

859

861 V = V->stripPointerCasts();

862

864 return true;

865

866

868 if (GV->hasAttribute("objc_arc_inert"))

869 return true;

870

872

873 if (!VisitedPhis.insert(PN).second)

874 return true;

875

878 return false;

879 return true;

880 }

881

882 return false;

883}

884

885void ObjCARCOpt::OptimizeIndividualCallImpl(Function &F, Instruction *Inst,

887 const Value *Arg) {

888 LLVM_DEBUG(dbgs() << "Visiting: Class: " << Class << "; " << *Inst << "\n");

889

890

891 SmallPtrSet<Value *, 1> VisitedPhis;

892

893 if (BundledInsts->contains(Inst)) {

894 UsedInThisFunction |= 1 << unsigned(Class);

895 return;

896 }

897

904 return;

905 }

906

907 switch (Class) {

908 default:

909 break;

910

911

912

913

914

915

916

917

918

919 case ARCInstKind::NoopCast:

921 ++NumNoops;

922 LLVM_DEBUG(dbgs() << "Erasing no-op cast: " << *Inst << "\n");

924 return;

925

926

927 case ARCInstKind::StoreWeak:

928 case ARCInstKind::LoadWeak:

929 case ARCInstKind::LoadWeakRetained:

930 case ARCInstKind::InitWeak:

931 case ARCInstKind::DestroyWeak: {

940 dbgs() << "A null pointer-to-weak-pointer is undefined behavior."

941 "\nOld = "

942 << *CI << "\nNew = " << *NewValue << "\n");

945 return;

946 }

947 break;

948 }

949 case ARCInstKind::CopyWeak:

950 case ARCInstKind::MoveWeak: {

958

961 dbgs() << "A null pointer-to-weak-pointer is undefined behavior."

962 "\nOld = "

963 << *CI << "\nNew = " << *NewValue << "\n");

964

967 return;

968 }

969 break;

970 }

971 case ARCInstKind::RetainRV:

972 if (OptimizeRetainRVCall(F, Inst))

973 return;

974 break;

975 case ARCInstKind::AutoreleaseRV:

976 OptimizeAutoreleaseRVCall(F, Inst, Class);

977 break;

978 }

979

980

985 if (Arg) {

987 ++NumAutoreleases;

988

989

991

992 Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release);

995 NewCall->setMetadata(MDKindCache.get(ARCMDKindID::ImpreciseRelease),

997

998 LLVM_DEBUG(dbgs() << "Replacing autorelease{,RV}(x) with objc_release(x) "

999 "since x is otherwise unused.\nOld: "

1000 << *Call << "\nNew: " << *NewCall << "\n");

1001

1003 Inst = NewCall;

1004 Class = ARCInstKind::Release;

1005 }

1006 }

1007

1008

1009

1013 dbgs() << "Adding tail keyword to function since it can never be "

1014 "passed stack args: "

1015 << *Inst << "\n");

1017 }

1018

1019

1020

1023 LLVM_DEBUG(dbgs() << "Removing tail keyword from function: " << *Inst

1024 << "\n");

1026 }

1027

1028

1031 LLVM_DEBUG(dbgs() << "Found no throw class. Setting nounwind on: " << *Inst

1032 << "\n");

1034 }

1035

1036

1038 UsedInThisFunction |= 1 << unsigned(Class);

1039 return;

1040 }

1041

1042

1043 if (!Arg)

1045

1046

1049 ++NumNoops;

1050 LLVM_DEBUG(dbgs() << "ARC calls with null are no-ops. Erasing: " << *Inst

1051 << "\n");

1053 return;

1054 }

1055

1056

1057

1058 UsedInThisFunction |= 1 << unsigned(Class);

1059

1060

1061

1062

1063

1064

1065

1066 if (Class == ARCInstKind::Release &&

1067 !Inst->getMetadata(MDKindCache.get(ARCMDKindID::ImpreciseRelease)))

1068 return;

1069

1071 Worklist.push_back(std::make_pair(Inst, Arg));

1072 do {

1073 std::pair<Instruction *, const Value *> Pair = Worklist.pop_back_val();

1074 Inst = Pair.first;

1075 Arg = Pair.second;

1076

1078 if (!PN)

1079 continue;

1080

1081

1082

1083 bool HasNull = false;

1084 bool HasCriticalEdges = false;

1088 HasNull = true;

1090 1) {

1091 HasCriticalEdges = true;

1092 break;

1093 }

1094 }

1095

1096 if (HasCriticalEdges)

1097 continue;

1098 if (!HasNull)

1099 continue;

1100

1102

1103

1104

1105 switch (Class) {

1106 case ARCInstKind::Retain:

1107 case ARCInstKind::RetainBlock:

1108

1109 break;

1110 case ARCInstKind::Release:

1111

1112

1115 break;

1116 case ARCInstKind::Autorelease:

1117

1120 break;

1121 case ARCInstKind::UnsafeClaimRV:

1122 case ARCInstKind::RetainRV:

1123 case ARCInstKind::AutoreleaseRV:

1124

1125

1126

1127

1128 continue;

1129 default:

1131 }

1132

1133 if (DepInst != PN)

1134 continue;

1135

1137 ++NumPartialNoops;

1138

1144 continue;

1149 cloneOpBundlesIf(CInst, OpBundles, [](const OperandBundleUse &B) {

1151 });

1152 addOpBundleForFunclet(InsertPos->getParent(), OpBundles);

1154 if (Op->getType() != ParamTy)

1155 Op = new BitCastInst(Op, ParamTy, "", InsertPos);

1157 Clone->insertBefore(*InsertPos->getParent(), InsertPos);

1158

1160 "And inserting clone at "

1161 << *InsertPos << "\n");

1162 Worklist.push_back(std::make_pair(Clone, Incoming));

1163 }

1164

1165 LLVM_DEBUG(dbgs() << "Erasing: " << *CInst << "\n");

1167 } while (!Worklist.empty());

1168}

1169

1170

1171

1173 const bool SuccSRRIKnownSafe,

1175 bool &SomeSuccHasSame,

1176 bool &AllSuccsHaveSame,

1177 bool &NotAllSeqEqualButKnownSafe,

1178 bool &ShouldContinue) {

1179 switch (SuccSSeq) {

1181 if (!S.IsKnownSafe() && !SuccSRRIKnownSafe) {

1183 break;

1184 }

1186 ShouldContinue = true;

1187 break;

1188 }

1190 SomeSuccHasSame = true;

1191 break;

1194 if (!S.IsKnownSafe() && !SuccSRRIKnownSafe)

1195 AllSuccsHaveSame = false;

1196 else

1197 NotAllSeqEqualButKnownSafe = true;

1198 break;

1203 }

1204}

1205

1206

1207

1208

1210 const bool SuccSRRIKnownSafe,

1212 bool &SomeSuccHasSame,

1213 bool &AllSuccsHaveSame,

1214 bool &NotAllSeqEqualButKnownSafe) {

1215 switch (SuccSSeq) {

1217 SomeSuccHasSame = true;

1218 break;

1222 if (!S.IsKnownSafe() && !SuccSRRIKnownSafe)

1223 AllSuccsHaveSame = false;

1224 else

1225 NotAllSeqEqualButKnownSafe = true;

1226 break;

1231 }

1232}

1233

1234

1235

1236

1237void

1238ObjCARCOpt::CheckForCFGHazards(const BasicBlock *BB,

1239 DenseMap<const BasicBlock *, BBState> &BBStates,

1240 BBState &MyStates) const {

1241

1242

1243 for (auto I = MyStates.top_down_ptr_begin(), E = MyStates.top_down_ptr_end();

1244 I != E; ++I) {

1245 TopDownPtrState &S = I->second;

1246 const Sequence Seq = I->second.GetSeq();

1247

1248

1250 continue;

1251

1252

1253

1255 "Unknown top down sequence state.");

1256

1257 const Value *Arg = I->first;

1258 bool SomeSuccHasSame = false;

1259 bool AllSuccsHaveSame = true;

1260 bool NotAllSeqEqualButKnownSafe = false;

1261

1262 for (const BasicBlock *Succ : successors(BB)) {

1263

1264

1265 const DenseMap<const BasicBlock *, BBState>::iterator BBI =

1266 BBStates.find(Succ);

1268 const BottomUpPtrState &SuccS = BBI->second.getPtrBottomUpState(Arg);

1270

1271

1272

1273

1274

1275

1276 if (SuccSSeq == S_None) {

1278 continue;

1279 }

1280

1281

1282

1283 const bool SuccSRRIKnownSafe = SuccS.IsKnownSafe();

1284

1285

1286

1287 switch(S.GetSeq()) {

1289 bool ShouldContinue = false;

1291 AllSuccsHaveSame, NotAllSeqEqualButKnownSafe,

1292 ShouldContinue);

1293 if (ShouldContinue)

1294 continue;

1295 break;

1296 }

1299 SomeSuccHasSame, AllSuccsHaveSame,

1300 NotAllSeqEqualButKnownSafe);

1301 break;

1306 break;

1307 }

1308 }

1309

1310

1311

1312

1313 if (SomeSuccHasSame && !AllSuccsHaveSame) {

1315 } else if (NotAllSeqEqualButKnownSafe) {

1316

1317

1318

1319

1321 }

1322 }

1323}

1324

1325bool ObjCARCOpt::VisitInstructionBottomUp(

1326 Instruction *Inst, BasicBlock *BB, BlotMapVector<Value *, RRInfo> &Retains,

1327 BBState &MyStates) {

1328 bool NestingDetected = false;

1330 const Value *Arg = nullptr;

1331

1333

1334 switch (Class) {

1335 case ARCInstKind::Release: {

1337

1338 BottomUpPtrState &S = MyStates.getPtrBottomUpState(Arg);

1339 NestingDetected |= S.InitBottomUp(MDKindCache, Inst);

1340 break;

1341 }

1342 case ARCInstKind::RetainBlock:

1343

1344

1345

1346 break;

1347 case ARCInstKind::Retain:

1348 case ARCInstKind::RetainRV: {

1350 BottomUpPtrState &S = MyStates.getPtrBottomUpState(Arg);

1352

1353

1354 if (Class != ARCInstKind::RetainRV) {

1355 LLVM_DEBUG(dbgs() << " Matching with: " << *Inst << "\n");

1357 }

1359 }

1360

1361 break;

1362 }

1363 case ARCInstKind::AutoreleasepoolPop:

1364

1365 MyStates.clearBottomUpPointers();

1366 return NestingDetected;

1367 case ARCInstKind::AutoreleasepoolPush:

1368 case ARCInstKind::None:

1369

1370 return NestingDetected;

1371 default:

1372 break;

1373 }

1374

1375

1376

1377 for (auto MI = MyStates.bottom_up_ptr_begin(),

1378 ME = MyStates.bottom_up_ptr_end();

1379 MI != ME; ++MI) {

1380 const Value *Ptr = MI->first;

1381 if (Ptr == Arg)

1382 continue;

1383 BottomUpPtrState &S = MI->second;

1384

1386 continue;

1387

1389 }

1390

1391 return NestingDetected;

1392}

1393

1394bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB,

1395 DenseMap<const BasicBlock *, BBState> &BBStates,

1396 BlotMapVector<Value *, RRInfo> &Retains) {

1397 LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::VisitBottomUp ==\n");

1398

1399 bool NestingDetected = false;

1400 BBState &MyStates = BBStates[BB];

1401

1402

1403

1404 BBState::edge_iterator SI(MyStates.succ_begin()),

1405 SE(MyStates.succ_end());

1406 if (SI != SE) {

1408 DenseMap<const BasicBlock *, BBState>::iterator I = BBStates.find(Succ);

1410 MyStates.InitFromSucc(I->second);

1411 ++SI;

1412 for (; SI != SE; ++SI) {

1413 Succ = *SI;

1414 I = BBStates.find(Succ);

1416 MyStates.MergeSucc(I->second);

1417 }

1418 }

1419

1421 << BBStates[BB] << "\n"

1422 << "Performing Dataflow:\n");

1423

1424

1427

1428

1430 continue;

1431

1432 LLVM_DEBUG(dbgs() << " Visiting " << *Inst << "\n");

1433

1434 NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates);

1435

1436

1437

1438 if (MyStates.bottom_up_ptr_list_size() > MaxPtrStates) {

1439 DisableRetainReleasePairing = true;

1440 return false;

1441 }

1442 }

1443

1444

1445

1446

1447 for (BBState::edge_iterator PI(MyStates.pred_begin()),

1448 PE(MyStates.pred_end()); PI != PE; ++PI) {

1451 NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates);

1452 }

1453

1454 LLVM_DEBUG(dbgs() << "\nFinal State:\n" << BBStates[BB] << "\n");

1455

1456 return NestingDetected;

1457}

1458

1459

1460

1461

1465 &ReleaseInsertPtToRCIdentityRoots) {

1466 for (const auto &P : Retains) {

1467

1468

1471

1472

1473 for (const Instruction *InsertPt : P.second.ReverseInsertPts)

1474 ReleaseInsertPtToRCIdentityRoots[InsertPt].insert(Root);

1475 }

1476}

1477

1478

1479

1480static const SmallPtrSet<const Value *, 2> *

1484 &ReleaseInsertPtToRCIdentityRoots) {

1485 auto I = ReleaseInsertPtToRCIdentityRoots.find(InsertPt);

1486 if (I == ReleaseInsertPtToRCIdentityRoots.end())

1487 return nullptr;

1488 return &I->second;

1489}

1490

1491bool ObjCARCOpt::VisitInstructionTopDown(

1492 Instruction *Inst, DenseMap<Value *, RRInfo> &Releases, BBState &MyStates,

1493 const DenseMap<const Instruction *, SmallPtrSet<const Value *, 2>>

1494 &ReleaseInsertPtToRCIdentityRoots) {

1495 bool NestingDetected = false;

1497 const Value *Arg = nullptr;

1498

1499

1500

1501 if (const SmallPtrSet<const Value *, 2> *Roots =

1503 Inst, ReleaseInsertPtToRCIdentityRoots))

1504 for (const auto *Root : *Roots) {

1505 TopDownPtrState &S = MyStates.getPtrTopDownState(Root);

1506

1507

1508

1509

1510

1513 }

1514

1516

1517 switch (Class) {

1518 case ARCInstKind::RetainBlock:

1519

1520

1521

1522

1523 break;

1524 case ARCInstKind::Retain:

1525 case ARCInstKind::RetainRV: {

1527 TopDownPtrState &S = MyStates.getPtrTopDownState(Arg);

1528 NestingDetected |= S.InitTopDown(Class, Inst);

1529

1530

1531 break;

1532 }

1533 case ARCInstKind::Release: {

1535 TopDownPtrState &S = MyStates.getPtrTopDownState(Arg);

1536

1537

1539

1540

1541 LLVM_DEBUG(dbgs() << " Matching with: " << *Inst << "\n");

1544 }

1545 break;

1546 }

1547 case ARCInstKind::AutoreleasepoolPop:

1548

1549 MyStates.clearTopDownPointers();

1550 return false;

1551 case ARCInstKind::AutoreleasepoolPush:

1552 case ARCInstKind::None:

1553

1554 return false;

1555 default:

1556 break;

1557 }

1558

1559

1560

1561 for (auto MI = MyStates.top_down_ptr_begin(),

1562 ME = MyStates.top_down_ptr_end();

1563 MI != ME; ++MI) {

1564 const Value *Ptr = MI->first;

1565 if (Ptr == Arg)

1566 continue;

1567 TopDownPtrState &S = MI->second;

1569 continue;

1570

1572 }

1573

1574 return NestingDetected;

1575}

1576

1577bool ObjCARCOpt::VisitTopDown(

1578 BasicBlock *BB, DenseMap<const BasicBlock *, BBState> &BBStates,

1579 DenseMap<Value *, RRInfo> &Releases,

1580 const DenseMap<const Instruction *, SmallPtrSet<const Value *, 2>>

1581 &ReleaseInsertPtToRCIdentityRoots) {

1582 LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::VisitTopDown ==\n");

1583 bool NestingDetected = false;

1584 BBState &MyStates = BBStates[BB];

1585

1586

1587

1588 BBState::edge_iterator PI(MyStates.pred_begin()),

1589 PE(MyStates.pred_end());

1590 if (PI != PE) {

1592 DenseMap<const BasicBlock *, BBState>::iterator I = BBStates.find(Pred);

1594 MyStates.InitFromPred(I->second);

1595 ++PI;

1596 for (; PI != PE; ++PI) {

1597 Pred = *PI;

1598 I = BBStates.find(Pred);

1600 MyStates.MergePred(I->second);

1601 }

1602 }

1603

1604

1605

1606

1607 if (!BB->hasNPredecessors(MyStates.pred_end() - MyStates.pred_begin()))

1608 for (auto I = MyStates.top_down_ptr_begin(),

1609 E = MyStates.top_down_ptr_end();

1610 I != E; ++I)

1611 I->second.SetCFGHazardAfflicted(true);

1612

1614 << BBStates[BB] << "\n"

1615 << "Performing Dataflow:\n");

1616

1617

1618 for (Instruction &Inst : *BB) {

1620

1621 NestingDetected |= VisitInstructionTopDown(

1622 &Inst, Releases, MyStates, ReleaseInsertPtToRCIdentityRoots);

1623

1624

1625

1626 if (MyStates.top_down_ptr_list_size() > MaxPtrStates) {

1627 DisableRetainReleasePairing = true;

1628 return false;

1629 }

1630 }

1631

1632 LLVM_DEBUG(dbgs() << "\nState Before Checking for CFG Hazards:\n"

1633 << BBStates[BB] << "\n\n");

1634 CheckForCFGHazards(BB, BBStates, MyStates);

1635 LLVM_DEBUG(dbgs() << "Final State:\n" << BBStates[BB] << "\n");

1636 return NestingDetected;

1637}

1638

1639static void

1643 unsigned NoObjCARCExceptionsMDKind,

1645

1647

1648

1651

1652

1653

1654 BasicBlock *EntryBB = &F.getEntryBlock();

1655 BBState &MyStates = BBStates[EntryBB];

1656 MyStates.SetAsEntry();

1659 Visited.insert(EntryBB);

1660 OnStack.insert(EntryBB);

1661 do {

1662 dfs_next_succ:

1665

1666 while (SuccStack.back().second != SE) {

1668 if (Visited.insert(SuccBB).second) {

1671 BBStates[CurrBB].addSucc(SuccBB);

1672 BBState &SuccStates = BBStates[SuccBB];

1673 SuccStates.addPred(CurrBB);

1674 OnStack.insert(SuccBB);

1675 goto dfs_next_succ;

1676 }

1677

1678 if (!OnStack.count(SuccBB)) {

1679 BBStates[CurrBB].addSucc(SuccBB);

1680 BBStates[SuccBB].addPred(CurrBB);

1681 }

1682 }

1683 OnStack.erase(CurrBB);

1686 } while (!SuccStack.empty());

1687

1688 Visited.clear();

1689

1690

1691

1692

1695 BBState &MyStates = BBStates[&ExitBB];

1696 if (!MyStates.isExit())

1697 continue;

1698

1699 MyStates.SetAsExit();

1700

1701 PredStack.push_back(std::make_pair(&ExitBB, MyStates.pred_begin()));

1702 Visited.insert(&ExitBB);

1703 while (!PredStack.empty()) {

1704 reverse_dfs_next_succ:

1705 BBState::edge_iterator PE = BBStates[PredStack.back().first].pred_end();

1706 while (PredStack.back().second != PE) {

1708 if (Visited.insert(BB).second) {

1710 goto reverse_dfs_next_succ;

1711 }

1712 }

1714 }

1715 }

1716}

1717

1718

1719bool ObjCARCOpt::Visit(Function &F,

1720 DenseMap<const BasicBlock *, BBState> &BBStates,

1721 BlotMapVector<Value *, RRInfo> &Retains,

1722 DenseMap<Value *, RRInfo> &Releases) {

1723

1724

1725

1726

1727

1728 SmallVector<BasicBlock *, 16> PostOrder;

1729 SmallVector<BasicBlock *, 16> ReverseCFGPostOrder;

1731 MDKindCache.get(ARCMDKindID::NoObjCARCExceptions),

1732 BBStates);

1733

1734

1735 bool BottomUpNestingDetected = false;

1736 for (BasicBlock *BB : llvm::reverse(ReverseCFGPostOrder)) {

1737 BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains);

1738 if (DisableRetainReleasePairing)

1739 return false;

1740 }

1741

1742 DenseMap<const Instruction *, SmallPtrSet<const Value *, 2>>

1743 ReleaseInsertPtToRCIdentityRoots;

1745

1746

1747 bool TopDownNestingDetected = false;

1748 for (BasicBlock *BB : llvm::reverse(PostOrder)) {

1749 TopDownNestingDetected |=

1750 VisitTopDown(BB, BBStates, Releases, ReleaseInsertPtToRCIdentityRoots);

1751 if (DisableRetainReleasePairing)

1752 return false;

1753 }

1754

1755 return TopDownNestingDetected && BottomUpNestingDetected;

1756}

1757

1758

1759void ObjCARCOpt::MoveCalls(Value *Arg, RRInfo &RetainsToMove,

1760 RRInfo &ReleasesToMove,

1761 BlotMapVector<Value *, RRInfo> &Retains,

1762 DenseMap<Value *, RRInfo> &Releases,

1763 SmallVectorImpl<Instruction *> &DeadInsts,

1765 LLVM_DEBUG(dbgs() << "== ObjCARCOpt::MoveCalls ==\n");

1766

1767

1768 for (Instruction *InsertPt : ReleasesToMove.ReverseInsertPts) {

1769 Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain);

1771 addOpBundleForFunclet(InsertPt->getParent(), BundleList);

1772 CallInst *Call =

1776

1778 << "\n"

1779 "At insertion point: "

1780 << *InsertPt << "\n");

1781 }

1782 for (Instruction *InsertPt : RetainsToMove.ReverseInsertPts) {

1783 Function *Decl = EP.get(ARCRuntimeEntryPointKind::Release);

1785 addOpBundleForFunclet(InsertPt->getParent(), BundleList);

1786 CallInst *Call =

1788

1790 Call->setMetadata(MDKindCache.get(ARCMDKindID::ImpreciseRelease), M);

1794

1796 << "\n"

1797 "At insertion point: "

1798 << *InsertPt << "\n");

1799 }

1800

1801

1802 for (Instruction *OrigRetain : RetainsToMove.Calls) {

1803 Retains.blot(OrigRetain);

1804 DeadInsts.push_back(OrigRetain);

1805 LLVM_DEBUG(dbgs() << "Deleting retain: " << *OrigRetain << "\n");

1806 }

1807 for (Instruction *OrigRelease : ReleasesToMove.Calls) {

1808 Releases.erase(OrigRelease);

1809 DeadInsts.push_back(OrigRelease);

1810 LLVM_DEBUG(dbgs() << "Deleting release: " << *OrigRelease << "\n");

1811 }

1812}

1813

1814bool ObjCARCOpt::PairUpRetainsAndReleases(

1815 DenseMap<const BasicBlock *, BBState> &BBStates,

1816 BlotMapVector<Value *, RRInfo> &Retains,

1817 DenseMap<Value *, RRInfo> &Releases, Module *M,

1818 Instruction *Retain,

1819 SmallVectorImpl<Instruction *> &DeadInsts, RRInfo &RetainsToMove,

1820 RRInfo &ReleasesToMove, Value *Arg, bool KnownSafe,

1821 bool &AnyPairsCompletelyEliminated) {

1822

1823

1824

1825 bool KnownSafeTD = true, KnownSafeBU = true;

1826 bool CFGHazardAfflicted = false;

1827

1828

1829

1830

1831

1832 unsigned OldDelta = 0;

1833 unsigned NewDelta = 0;

1834 unsigned OldCount = 0;

1835 unsigned NewCount = 0;

1836 bool FirstRelease = true;

1837 for (SmallVector<Instruction *, 4> NewRetains{Retain};;) {

1838 SmallVector<Instruction *, 4> NewReleases;

1839 for (Instruction *NewRetain : NewRetains) {

1840 auto It = Retains.find(NewRetain);

1842 const RRInfo &NewRetainRRI = It->second;

1843 KnownSafeTD &= NewRetainRRI.KnownSafe;

1845 for (Instruction *NewRetainRelease : NewRetainRRI.Calls) {

1846 auto Jt = Releases.find(NewRetainRelease);

1847 if (Jt == Releases.end())

1848 return false;

1849 const RRInfo &NewRetainReleaseRRI = Jt->second;

1850

1851

1852

1853

1854

1855

1856 if (!NewRetainReleaseRRI.Calls.count(NewRetain))

1857 return false;

1858

1859 if (ReleasesToMove.Calls.insert(NewRetainRelease).second) {

1860

1861

1862 const BBState &NRRBBState = BBStates[NewRetainRelease->getParent()];

1864 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))

1865 return false;

1867 "PathCount at this point can not be "

1868 "OverflowOccurredValue.");

1869 OldDelta -= PathCount;

1870

1871

1872 if (FirstRelease) {

1877 FirstRelease = false;

1878 } else {

1885 }

1886

1887

1888 if (!KnownSafe)

1889 for (Instruction *RIP : NewRetainReleaseRRI.ReverseInsertPts) {

1891

1892

1893 const BBState &RIPBBState = BBStates[RIP->getParent()];

1895 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))

1896 return false;

1898 "PathCount at this point can not be "

1899 "OverflowOccurredValue.");

1900 NewDelta -= PathCount;

1901 }

1902 }

1903 NewReleases.push_back(NewRetainRelease);

1904 }

1905 }

1906 }

1907 NewRetains.clear();

1908 if (NewReleases.empty()) break;

1909

1910

1911 for (Instruction *NewRelease : NewReleases) {

1912 auto It = Releases.find(NewRelease);

1914 const RRInfo &NewReleaseRRI = It->second;

1915 KnownSafeBU &= NewReleaseRRI.KnownSafe;

1917 for (Instruction *NewReleaseRetain : NewReleaseRRI.Calls) {

1918 auto Jt = Retains.find(NewReleaseRetain);

1919 if (Jt == Retains.end())

1920 return false;

1921 const RRInfo &NewReleaseRetainRRI = Jt->second;

1922

1923

1924

1925

1926

1927

1928 if (!NewReleaseRetainRRI.Calls.count(NewRelease))

1929 return false;

1930

1931 if (RetainsToMove.Calls.insert(NewReleaseRetain).second) {

1932

1933

1934 const BBState &NRRBBState = BBStates[NewReleaseRetain->getParent()];

1936 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))

1937 return false;

1939 "PathCount at this point can not be "

1940 "OverflowOccurredValue.");

1941 OldDelta += PathCount;

1942 OldCount += PathCount;

1943

1944

1945 if (!KnownSafe)

1946 for (Instruction *RIP : NewReleaseRetainRRI.ReverseInsertPts) {

1948

1949

1950 const BBState &RIPBBState = BBStates[RIP->getParent()];

1951

1953 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))

1954 return false;

1956 "PathCount at this point can not be "

1957 "OverflowOccurredValue.");

1958 NewDelta += PathCount;

1959 NewCount += PathCount;

1960 }

1961 }

1962 NewRetains.push_back(NewReleaseRetain);

1963 }

1964 }

1965 }

1966 if (NewRetains.empty()) break;

1967 }

1968

1969

1970 bool UnconditionallySafe = KnownSafeTD && KnownSafeBU;

1971 if (UnconditionallySafe) {

1974 NewCount = 0;

1975 } else {

1976

1977

1978

1979

1980 if (NewDelta != 0)

1981 return false;

1982

1983

1984

1985

1986 const bool WillPerformCodeMotion =

1989 if (CFGHazardAfflicted && WillPerformCodeMotion)

1990 return false;

1991 }

1992

1993

1994

1995

1996

1997

1998 if (OldDelta != 0)

1999 return false;

2000

2002 assert(OldCount != 0 && "Unreachable code?");

2003 NumRRs += OldCount - NewCount;

2004

2005 AnyPairsCompletelyEliminated = NewCount == 0;

2006

2007

2008 return true;

2009}

2010

2011

2012

2013bool ObjCARCOpt::PerformCodePlacement(

2014 DenseMap<const BasicBlock *, BBState> &BBStates,

2015 BlotMapVector<Value *, RRInfo> &Retains,

2016 DenseMap<Value *, RRInfo> &Releases, Module *M) {

2017 LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::PerformCodePlacement ==\n");

2018

2019 bool AnyPairsCompletelyEliminated = false;

2020 SmallVector<Instruction *, 8> DeadInsts;

2021

2022

2024 E = Retains.end();

2025 I != E; ++I) {

2027 if (!V) continue;

2028

2030

2032

2034

2035

2036

2037

2039

2040

2041

2043 if (const GlobalVariable *GV =

2046 if (GV->isConstant())

2047 KnownSafe = true;

2048

2049

2050

2051 RRInfo RetainsToMove, ReleasesToMove;

2052

2053 bool PerformMoveCalls = PairUpRetainsAndReleases(

2054 BBStates, Retains, Releases, M, Retain, DeadInsts,

2055 RetainsToMove, ReleasesToMove, Arg, KnownSafe,

2056 AnyPairsCompletelyEliminated);

2057

2058 if (PerformMoveCalls) {

2059

2060

2061 MoveCalls(Arg, RetainsToMove, ReleasesToMove,

2062 Retains, Releases, DeadInsts, M);

2063 }

2064 }

2065

2066

2067

2068 while (!DeadInsts.empty())

2070

2071 return AnyPairsCompletelyEliminated;

2072}

2073

2074

2075void ObjCARCOpt::OptimizeWeakCalls(Function &F) {

2076 LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeWeakCalls ==\n");

2077

2078

2079

2080

2083

2084 LLVM_DEBUG(dbgs() << "Visiting: " << *Inst << "\n");

2085

2087 if (Class != ARCInstKind::LoadWeak &&

2088 Class != ARCInstKind::LoadWeakRetained)

2089 continue;

2090

2091

2092 if (Class == ARCInstKind::LoadWeak && Inst->use_empty()) {

2095 continue;

2096 }

2097

2098

2099

2100

2101

2106 J != B; --J) {

2107 Instruction *EarlierInst = &*std::prev(J);

2109 switch (EarlierClass) {

2110 case ARCInstKind::LoadWeak:

2111 case ARCInstKind::LoadWeakRetained: {

2112

2113

2115 CallInst *EarlierCall = cast(EarlierInst);

2118 switch (PA.getAA()->alias(Arg, EarlierArg)) {

2121

2122 if (Class == ARCInstKind::LoadWeakRetained) {

2123 Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain);

2124 CallInst *CI =

2127 }

2128

2131 goto clobbered;

2134 goto clobbered;

2136 break;

2137 }

2138 break;

2139 }

2140 case ARCInstKind::StoreWeak:

2141 case ARCInstKind::InitWeak: {

2142

2143

2145 CallInst *EarlierCall = cast(EarlierInst);

2148 switch (PA.getAA()->alias(Arg, EarlierArg)) {

2151

2152 if (Class == ARCInstKind::LoadWeakRetained) {

2153 Function *Decl = EP.get(ARCRuntimeEntryPointKind::Retain);

2154 CallInst *CI =

2157 }

2158

2161 goto clobbered;

2164 goto clobbered;

2166 break;

2167 }

2168 break;

2169 }

2170 case ARCInstKind::MoveWeak:

2171 case ARCInstKind::CopyWeak:

2172

2173 goto clobbered;

2174 case ARCInstKind::AutoreleasepoolPush:

2175 case ARCInstKind::None:

2176 case ARCInstKind::IntrinsicUser:

2177 case ARCInstKind::User:

2178

2179

2180 break;

2181 default:

2182

2183 goto clobbered;

2184 }

2185 }

2186 clobbered:;

2187 }

2188

2189

2190

2193 if (Class != ARCInstKind::DestroyWeak)

2194 continue;

2195

2199 for (User *U : Alloca->users()) {

2202 case ARCInstKind::InitWeak:

2203 case ARCInstKind::StoreWeak:

2204 case ARCInstKind::DestroyWeak:

2205 continue;

2206 default:

2207 goto done;

2208 }

2209 }

2214 case ARCInstKind::InitWeak:

2215 case ARCInstKind::StoreWeak:

2216

2218 break;

2219 case ARCInstKind::DestroyWeak:

2220

2221 break;

2222 default:

2224 }

2226 }

2227 Alloca->eraseFromParent();

2228 done:;

2229 }

2230 }

2231}

2232

2233

2234

2235bool ObjCARCOpt::OptimizeSequences(Function &F) {

2236

2237

2238

2239

2240 DenseMap<Value *, RRInfo> Releases;

2241 BlotMapVector<Value *, RRInfo> Retains;

2242

2243

2244

2245 DenseMap<const BasicBlock *, BBState> BBStates;

2246

2247

2248 bool NestingDetected = Visit(F, BBStates, Retains, Releases);

2249

2250 if (DisableRetainReleasePairing)

2251 return false;

2252

2253

2254 bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,

2255 Releases,

2256 F.getParent());

2257

2258 return AnyPairsCompletelyEliminated && NestingDetected;

2259}

2260

2261

2262

2263

2269

2270

2272 return nullptr;

2273

2274

2278 : nullptr;

2279}

2280

2281

2282

2283

2284static CallInst *

2290

2291

2294 return nullptr;

2295 }

2296

2298}

2299

2300

2301

2302

2303static CallInst *FindPredecessorAutoreleaseWithSafePath(

2304 const Value *Arg, BasicBlock *BB, ReturnInst *Ret, ProvenanceAnalysis &PA) {

2307

2309 return nullptr;

2312 return nullptr;

2314 return nullptr;

2315

2317}

2318

2319

2320

2321

2322

2323

2324

2325

2326

2327void ObjCARCOpt::OptimizeReturns(Function &F) {

2328 if (F.getReturnType()->isPointerTy())

2329 return;

2330

2331 LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeReturns ==\n");

2332

2333 for (BasicBlock &BB: F) {

2335 if (!Ret)

2336 continue;

2337

2339

2341

2342

2343

2344

2346 FindPredecessorAutoreleaseWithSafePath(Arg, &BB, Ret, PA);

2347

2349 continue;

2350

2353

2355 continue;

2356

2357

2358

2360

2361

2363 (Call->isTailCall() &&

2366 continue;

2367

2368

2372 << "\n");

2375 }

2376}

2377

2378#ifndef NDEBUG

2379void

2380ObjCARCOpt::GatherStatistics(Function &F, bool AfterOptimization) {

2382 AfterOptimization ? NumRetainsAfterOpt : NumRetainsBeforeOpt;

2384 AfterOptimization ? NumReleasesAfterOpt : NumReleasesBeforeOpt;

2385

2389 default:

2390 break;

2391 case ARCInstKind::Retain:

2392 ++NumRetains;

2393 break;

2394 case ARCInstKind::Release:

2395 ++NumReleases;

2396 break;

2397 }

2398 }

2399}

2400#endif

2401

2402void ObjCARCOpt::init(Function &F) {

2404 return;

2405

2406

2407

2408

2409 MDKindCache.init(F.getParent());

2410

2411

2412 EP.init(F.getParent());

2413

2414

2415 if (F.hasPersonalityFn() &&

2418}

2419

2420bool ObjCARCOpt::run(Function &F, AAResults &AA) {

2422 return false;

2423

2424 Changed = CFGChanged = false;

2425 BundledRetainClaimRVs BRV(EP, false, false);

2426 BundledInsts = &BRV;

2427

2428 LLVM_DEBUG(dbgs() << "<<< ObjCARCOpt: Visiting Function: " << F.getName()

2429 << " >>>"

2430 "\n");

2431

2434 CFGChanged |= R.second;

2435

2437

2438#ifndef NDEBUG

2440 GatherStatistics(F, false);

2441 }

2442#endif

2443

2444

2445

2446

2447

2448

2449 OptimizeIndividualCalls(F);

2450

2451

2452 if (UsedInThisFunction & ((1 << unsigned(ARCInstKind::LoadWeak)) |

2453 (1 << unsigned(ARCInstKind::LoadWeakRetained)) |

2454 (1 << unsigned(ARCInstKind::StoreWeak)) |

2455 (1 << unsigned(ARCInstKind::InitWeak)) |

2456 (1 << unsigned(ARCInstKind::CopyWeak)) |

2457 (1 << unsigned(ARCInstKind::MoveWeak)) |

2458 (1 << unsigned(ARCInstKind::DestroyWeak))))

2459 OptimizeWeakCalls(F);

2460

2461

2462 if (UsedInThisFunction & ((1 << unsigned(ARCInstKind::Retain)) |

2463 (1 << unsigned(ARCInstKind::RetainRV)) |

2464 (1 << unsigned(ARCInstKind::RetainBlock))))

2465 if (UsedInThisFunction & (1 << unsigned(ARCInstKind::Release)))

2466

2467

2468 while (OptimizeSequences(F)) {}

2469

2470

2471 if (UsedInThisFunction & ((1 << unsigned(ARCInstKind::Autorelease)) |

2472 (1 << unsigned(ARCInstKind::AutoreleaseRV))))

2473 OptimizeReturns(F);

2474

2475

2476 if (UsedInThisFunction & ((1 << unsigned(ARCInstKind::AutoreleasepoolPush)) |

2477 (1 << unsigned(ARCInstKind::AutoreleasepoolPop))))

2478 OptimizeAutoreleasePools(F);

2479

2480

2481#ifndef NDEBUG

2483 GatherStatistics(F, true);

2484 }

2485#endif

2486

2488

2490}

2491

2492

2493

2496 return false;

2497

2498

2499

2501 return true;

2502

2504 if (!Callee->hasExactDefinition())

2505 return true;

2506 for (const BasicBlock &BB : *Callee) {

2508

2510 switch (InstKind) {

2516

2517 return true;

2518

2534

2535 break;

2536

2539

2541 return true;

2542 break;

2543

2547

2548 break;

2549 }

2550 }

2551 }

2552 return false;

2553 }

2554

2555 return true;

2556}

2557

2558

2559void ObjCARCOpt::OptimizeAutoreleasePools(Function &F) {

2560 LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeAutoreleasePools ==\n");

2561

2562 OptimizationRemarkEmitter ORE(&F);

2563

2564

2565

2566

2567 for (BasicBlock &BB : F) {

2568

2570 PoolStack;

2571

2574

2575 switch (Class) {

2576 case ARCInstKind::AutoreleasepoolPush: {

2577

2580 {Push, false});

2581 LLVM_DEBUG(dbgs() << "Found autorelease pool push: " << *Push << "\n");

2582 break;

2583 }

2584

2585 case ARCInstKind::AutoreleasepoolPop: {

2587

2588 if (PoolStack.empty())

2589 break;

2590

2591 auto &TopPool = PoolStack.back();

2592 CallInst *PendingPush = TopPool.first;

2593 bool HasAutoreleaseInScope = TopPool.second;

2594

2595

2597

2598

2599 if (Pop->getArgOperand(0)->stripPointerCasts() != PendingPush)

2600 break;

2601

2602

2603 if (HasAutoreleaseInScope)

2604 break;

2605

2606

2607 ORE.emit([&]() {

2608 return OptimizationRemark(DEBUG_TYPE, "AutoreleasePoolElimination",

2609 PendingPush)

2610 << "eliminated empty autorelease pool pair";

2611 });

2612

2613

2616

2617 Pop->eraseFromParent();

2619

2621 ++NumNoops;

2622 break;

2623 }

2624 case ARCInstKind::CallOrUser:

2625 case ARCInstKind::Call:

2627 break;

2628 [[fallthrough]];

2629 case ARCInstKind::Autorelease:

2630 case ARCInstKind::AutoreleaseRV:

2631 case ARCInstKind::FusedRetainAutorelease:

2632 case ARCInstKind::FusedRetainAutoreleaseRV:

2633 case ARCInstKind::LoadWeak: {

2634

2635 if (!PoolStack.empty()) {

2636 PoolStack.back().second = true;

2639 << "Found autorelease or potential autorelease in pool scope: "

2640 << Inst << "\n");

2641 }

2642 break;

2643 }

2644

2645

2646 case ARCInstKind::Retain:

2647 case ARCInstKind::RetainRV:

2648 case ARCInstKind::UnsafeClaimRV:

2649 case ARCInstKind::RetainBlock:

2650 case ARCInstKind::Release:

2651 case ARCInstKind::NoopCast:

2652 case ARCInstKind::LoadWeakRetained:

2653 case ARCInstKind::StoreWeak:

2654 case ARCInstKind::InitWeak:

2655 case ARCInstKind::MoveWeak:

2656 case ARCInstKind::CopyWeak:

2657 case ARCInstKind::DestroyWeak:

2658 case ARCInstKind::StoreStrong:

2659 case ARCInstKind::IntrinsicUser:

2660 case ARCInstKind::User:

2661 case ARCInstKind::None:

2662

2663 break;

2664 }

2665 }

2666 }

2667}

2668

2669

2670

2671

2674 ObjCARCOpt OCAO;

2675 OCAO.init(F);

2676

2678 bool CFGChanged = OCAO.hasCFGChanged();

2681 if (!CFGChanged)

2683 return PA;

2684 }

2686}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

This file contains a class ARCRuntimeEntryPoints for use in creating/managing references to entry poi...

Expand Atomic instructions

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

This file contains the declarations for the subclasses of Constant, which represent the different fla...

This file defines the DenseMap class.

This file declares special dependency analysis routines used in Objective C ARC Optimizations.

This file provides various utilities for inspecting and working with the control flow graph in LLVM I...

iv Induction Variable Users

Machine Check Debug Module

uint64_t IntrinsicInst * II

This file defines common analysis utilities used by the ObjC ARC Optimizer.

static cl::opt< unsigned > MaxPtrStates("arc-opt-max-ptr-states", cl::Hidden, cl::desc("Maximum number of ptr states the optimizer keeps track of"), cl::init(4095))

This file defines ARC utility functions which are used by various parts of the compiler.

This file declares a special form of Alias Analysis called Provenance / Analysis''.

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)

void setAA(AAResults *aa)

AAResults * getAA() const

A manager for alias analyses.

LLVM_ABI AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)

The main low level interface to the alias analysis implementation.

@ MayAlias

The two locations may or may not alias.

@ NoAlias

The two locations do not alias at all.

@ PartialAlias

The two locations alias, but only due to a partial overlap.

@ MustAlias

The two locations precisely alias each other.

PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)

Get the result of an analysis pass for a given IR unit.

LLVM Basic Block Representation.

iterator begin()

Instruction iterator methods.

const Instruction & back() const

InstListType::const_iterator const_iterator

LLVM_ABI bool hasNPredecessors(unsigned N) const

Return true if this block has exactly N predecessors.

InstListType::iterator iterator

Instruction iterators...

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...

This class represents a no-op cast from one type to another.

An associative container with fast insertion-order (deterministic) iteration over its elements.

void blot(const KeyT &Key)

This is similar to erase, but instead of removing the element from the vector, it just zeros out the ...

iterator find(const KeyT &Key)

typename VectorTy::const_iterator const_iterator

std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &InsertPair)

Represents analyses that only rely on functions' control flow.

Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...

OperandBundleUse getOperandBundleAt(unsigned Index) const

Return the operand bundle at a specific index.

Function * getCalledFunction() const

Returns the function called, or null if this is an indirect function invocation or the function signa...

unsigned getNumOperandBundles() const

Return the number of operand bundles associated with this User.

bool onlyReadsMemory(unsigned OpNo) const

Value * getArgOperand(unsigned i) const

void setArgOperand(unsigned i, Value *v)

void setCalledFunction(Function *Fn)

Sets the function called, including updating the function type.

This class represents a function call, abstracting a target machine's calling convention.

static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)

void setTailCall(bool IsTc=true)

static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)

iterator find(const_arg_type_t< KeyT > Val)

bool erase(const KeyT &Val)

an instruction for type-safe pointer arithmetic to access elements of arrays and structs

BIty & getInstructionIterator()

BBIty & getBasicBlockIterator()

LLVM_ABI unsigned getNumSuccessors() const LLVM_READONLY

Return the number of successors that this instruction has.

LLVM_ABI void insertBefore(InstListType::iterator InsertPos)

Insert an unlinked instruction into a basic block immediately before the specified position.

LLVM_ABI InstListType::iterator eraseFromParent()

This method unlinks 'this' from the containing basic block and deletes it.

MDNode * getMetadata(unsigned KindID) const

Get the metadata of given kind attached to this Instruction.

LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)

Set the metadata of the specified kind to the specified node.

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

A Module instance is used to store all the information related to an LLVM module.

op_range incoming_values()

BasicBlock * getIncomingBlock(unsigned i) const

Return incoming basic block number i.

Value * getIncomingValue(unsigned i) const

Return incoming value number x.

unsigned getNumIncomingValues() const

Return the number of incoming edges.

static LLVM_ABI PoisonValue * get(Type *T)

Static factory methods - Return an 'poison' object of the specified type.

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.

bool erase(PtrType Ptr)

Remove pointer from the set.

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.

reference emplace_back(ArgTypes &&... Args)

typename SuperClass::const_iterator const_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.

bool isVoidTy() const

Return true if this is 'void'.

Value * getOperand(unsigned i) const

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

bool hasOneUse() const

Return true if there is exactly one use of this value.

LLVM_ABI void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

iterator_range< user_iterator > users()

LLVM_ABI LLVMContext & getContext() const

All values hold a context through their type.

const ParentTy * getParent() const

self_iterator getIterator()

A cache of MDKinds used by various ARC optimizations.

unsigned get(ARCMDKindID ID)

Declarations for ObjC runtime functions and constants.

Function * get(ARCRuntimeEntryPointKind kind)

bool contains(const Instruction *I) const

See if an instruction is a bundled retainRV/claimRV call.

std::pair< bool, bool > insertAfterInvokes(Function &F, DominatorTree *DT)

Insert a retainRV/claimRV call to the normal destination blocks of invokes with operand bundle "clang...

CallInst * insertRVCall(BasicBlock::iterator InsertPt, CallBase *AnnotatedCall)

Insert a retainRV/claimRV call.

void eraseInst(CallInst *CI)

Remove a retainRV/claimRV call entirely.

This class summarizes several per-pointer runtime properties which are propagated through the flow gr...

void SetCFGHazardAfflicted(const bool NewValue)

const RRInfo & GetRRInfo() const

void ClearSequenceProgress()

This class implements an extremely fast bulk output stream that can only output to a stream.

static void CheckForUseCFGHazard(const Sequence SuccSSeq, const bool SuccSRRIKnownSafe, TopDownPtrState &S, bool &SomeSuccHasSame, bool &AllSuccsHaveSame, bool &NotAllSeqEqualButKnownSafe, bool &ShouldContinue)

If we have a top down pointer in the S_Use state, make sure that there are no CFG hazards by checking...

Definition ObjCARCOpts.cpp:1172

NumRets

Definition ObjCARCOpts.cpp:2370

static void CheckForCanReleaseCFGHazard(const Sequence SuccSSeq, const bool SuccSRRIKnownSafe, TopDownPtrState &S, bool &SomeSuccHasSame, bool &AllSuccsHaveSame, bool &NotAllSeqEqualButKnownSafe)

If we have a Top Down pointer in the S_CanRelease state, make sure that there are no CFG hazards by c...

Definition ObjCARCOpts.cpp:1209

static bool isInertARCValue(Value *V, SmallPtrSet< Value *, 1 > &VisitedPhis)

This function returns true if the value is inert.

Definition ObjCARCOpts.cpp:860

CallInst * Retain

Definition ObjCARCOpts.cpp:2351

CallInst * Call

Definition ObjCARCOpts.cpp:2359

static void collectReleaseInsertPts(const BlotMapVector< Value *, RRInfo > &Retains, DenseMap< const Instruction *, SmallPtrSet< const Value *, 2 > > &ReleaseInsertPtToRCIdentityRoots)

Definition ObjCARCOpts.cpp:1462

Changed

Definition ObjCARCOpts.cpp:2369

CallInst * Autorelease

Look for an `‘autorelease’' instruction dependent on Arg such that there are / no instructions depend...

Definition ObjCARCOpts.cpp:2345

static void ComputePostOrders(Function &F, SmallVectorImpl< BasicBlock * > &PostOrder, SmallVectorImpl< BasicBlock * > &ReverseCFGPostOrder, unsigned NoObjCARCExceptionsMDKind, DenseMap< const BasicBlock *, BBState > &BBStates)

Definition ObjCARCOpts.cpp:1640

static CallInst * FindPredecessorRetainWithSafePath(const Value *Arg, BasicBlock *BB, Instruction *Autorelease, ProvenanceAnalysis &PA)

Find a dependent retain that precedes the given autorelease for which there is nothing in between the...

Definition ObjCARCOpts.cpp:2285

static const SmallPtrSet< const Value *, 2 > * getRCIdentityRootsFromReleaseInsertPt(const Instruction *InsertPt, const DenseMap< const Instruction *, SmallPtrSet< const Value *, 2 > > &ReleaseInsertPtToRCIdentityRoots)

Definition ObjCARCOpts.cpp:1481

bool MayAutorelease(const CallBase &CB, unsigned Depth=0)

Interprocedurally determine if calls made by the given call site can possibly produce autoreleases.

Definition ObjCARCOpts.cpp:2494

static const unsigned OverflowOccurredValue

Definition ObjCARCOpts.cpp:205

static CallInst * HasSafePathToPredecessorCall(const Value *Arg, Instruction *Retain, ProvenanceAnalysis &PA)

Check if there is a dependent call earlier that does not have anything in between the Retain and the ...

Definition ObjCARCOpts.cpp:2264

static const Value * FindSingleUseIdentifiedObject(const Value *Arg)

This is similar to GetRCIdentityRoot but it stops as soon as it finds a value with multiple uses.

Definition ObjCARCOpts.cpp:86

This file defines common definitions/declarations used by the ObjC ARC Optimizer.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

@ C

The default llvm calling convention, compatible with C.

@ BasicBlock

Various leaf nodes.

initializer< Ty > init(const Ty &Val)

PointerTypeMap run(const Module &M)

Compute the PointerTypeMap for the module M.

bool IsRetain(ARCInstKind Class)

Test if the given class is objc_retain or equivalent.

@ AutoreleasePoolBoundary

@ NeedsPositiveRetainCount

bool IsNeverTail(ARCInstKind Class)

Test if the given class represents instructions which are never safe to mark with the "tail" keyword.

bool IsAlwaysTail(ARCInstKind Class)

Test if the given class represents instructions which are always safe to mark with the "tail" keyword...

bool IsNullOrUndef(const Value *V)

bool IsAutorelease(ARCInstKind Class)

Test if the given class is objc_autorelease or equivalent.

ARCInstKind

Equivalence classes of instructions in the ARC Model.

@ DestroyWeak

objc_destroyWeak (derived)

@ FusedRetainAutorelease

objc_retainAutorelease

@ CallOrUser

could call objc_release and/or "use" pointers

@ StoreStrong

objc_storeStrong (derived)

@ LoadWeakRetained

objc_loadWeakRetained (primitive)

@ StoreWeak

objc_storeWeak (primitive)

@ AutoreleasepoolPop

objc_autoreleasePoolPop

@ AutoreleasepoolPush

objc_autoreleasePoolPush

@ InitWeak

objc_initWeak (derived)

@ Autorelease

objc_autorelease

@ LoadWeak

objc_loadWeak (derived)

@ None

anything that is inert from an ARC perspective.

@ MoveWeak

objc_moveWeak (derived)

@ User

could "use" a pointer

@ RetainRV

objc_retainAutoreleasedReturnValue

@ RetainBlock

objc_retainBlock

@ FusedRetainAutoreleaseRV

objc_retainAutoreleaseReturnValue

@ AutoreleaseRV

objc_autoreleaseReturnValue

@ Call

could call objc_release

@ CopyWeak

objc_copyWeak (derived)

@ NoopCast

objc_retainedObject, etc.

@ UnsafeClaimRV

objc_unsafeClaimAutoreleasedReturnValue

@ IntrinsicUser

llvm.objc.clang.arc.use

bool IsObjCIdentifiedObject(const Value *V)

Return true if this value refers to a distinct and identifiable object.

bool EnableARCOpts

A handy option to enable/disable all ARC Optimizations.

void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList)

Return the list of PHI nodes that are equivalent to PN.

bool IsForwarding(ARCInstKind Class)

Test if the given class represents instructions which return their argument verbatim.

bool IsNoopInstruction(const Instruction *I)

llvm::Instruction * findSingleDependency(DependenceKind Flavor, const Value *Arg, BasicBlock *StartBB, Instruction *StartInst, ProvenanceAnalysis &PA)

Find dependent instructions.

Sequence

A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...

@ S_CanRelease

foo(x) – x could possibly see a ref count decrement.

@ S_Retain

objc_retain(x).

@ S_Stop

code motion is stopped.

@ S_MovableRelease

objc_release(x), !clang.imprecise_release.

ARCInstKind GetBasicARCInstKind(const Value *V)

Determine which objc runtime call instruction class V belongs to.

ARCInstKind GetARCInstKind(const Value *V)

Map V to its ARCInstKind equivalence class.

Value * GetArgRCIdentityRoot(Value *Inst)

Assuming the given instruction is one of the special calls such as objc_retain or objc_release,...

bool IsNoThrow(ARCInstKind Class)

Test if the given class represents instructions which are always safe to mark with the nounwind attri...

const Value * GetRCIdentityRoot(const Value *V)

The RCIdentity root of a value V is a dominating value U for which retaining or releasing U is equiva...

bool IsNoopOnGlobal(ARCInstKind Class)

Test if the given class represents instructions which do nothing if passed a global variable.

bool IsNoopOnNull(ARCInstKind Class)

Test if the given class represents instructions which do nothing if passed a null pointer.

bool hasAttachedCallOpBundle(const CallBase *CB)

static void EraseInstruction(Instruction *CI)

Erase the given instruction.

friend class Instruction

Iterator for Instructions in a `BasicBlock.

This is an optimization pass for GlobalISel generic memory operations.

FunctionAddr VTableAddr Value

InstIterator< SymbolTableList< BasicBlock >, Function::iterator, BasicBlock::iterator, Instruction > inst_iterator

auto pred_end(const MachineBasicBlock *BB)

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

auto successors(const MachineBasicBlock *BB)

LLVM_ABI DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)

If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...

inst_iterator inst_begin(Function *F)

bool isScopedEHPersonality(EHPersonality Pers)

Returns true if this personality uses scope-style EH IR instructions: catchswitch,...

auto dyn_cast_or_null(const Y &Val)

auto reverse(ContainerTy &&C)

LLVM_ABI raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

LLVM_ABI bool AreStatisticsEnabled()

Check if statistics are enabled.

LLVM_ABI EHPersonality classifyEHPersonality(const Value *Pers)

See if the given exception handling personality function is one that we understand.

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...

inst_iterator inst_end(Function *F)

RNSuccIterator< NodeRef, BlockT, RegionT > succ_begin(NodeRef Node)

RNSuccIterator< NodeRef, BlockT, RegionT > succ_end(NodeRef Node)

DWARFExpression::Operation Op

raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)

TinyPtrVector< BasicBlock * > ColorVector

auto pred_begin(const MachineBasicBlock *BB)

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

SuccIterator< Instruction, BasicBlock > succ_iterator

bool is_contained(R &&Range, const E &Element)

Returns true if Element is found in Range.

AnalysisManager< Function > FunctionAnalysisManager

Convenience typedef for the Function analysis manager.

LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)

Definition ObjCARCOpts.cpp:2672

A lightweight accessor for an operand bundle meant to be passed around by value.

bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)

bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I)

(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases.

bool MatchWithRetain()

Return true if this set of releases can be paired with a release.

void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)

Unidirectional information about either a retain-decrement-use-release sequence or release-use-decrem...

bool KnownSafe

After an objc_retain, the reference count of the referenced object is known to be positive.

SmallPtrSet< Instruction *, 2 > Calls

For a top-down sequence, the set of objc_retains or objc_retainBlocks.

MDNode * ReleaseMetadata

If the Calls are objc_release calls and they all have a clang.imprecise_release tag,...

bool CFGHazardAfflicted

If this is true, we cannot perform code motion but can still remove retain/release pairs.

bool IsTailCallRelease

True of the objc_release calls are all marked with the "tail" keyword.

SmallPtrSet< Instruction *, 2 > ReverseInsertPts

The set of optimal insert positions for moving calls in the opposite sequence.

bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release)

Return true if this set of retains can be paired with the given release.

bool InitTopDown(ARCInstKind Kind, Instruction *I)

(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases.

bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class, const BundledRetainClaimRVs &BundledRVs)

void HandlePotentialUse(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)