77 #define DEBUG_TYPE "objc-arc-opts"
81 cl::desc(
"Maximum number of ptr states the optimizer keeps track of"),
92 if (isa<ConstantData>(
Arg))
95 if (
Arg->hasOneUse()) {
99 if (
GEP->hasAllZeroIndices())
103 cast<CallInst>(
Arg)->getArgOperand(0));
112 for (
const User *U :
Arg->users())
165 STATISTIC(NumNoops,
"Number of no-op objc calls eliminated");
166 STATISTIC(NumPartialNoops,
"Number of partially no-op objc calls eliminated");
167 STATISTIC(NumAutoreleases,
"Number of autoreleases converted to releases");
168 STATISTIC(NumRets,
"Number of return value forwarding "
169 "retain+autoreleases eliminated");
170 STATISTIC(NumRRs,
"Number of retain+release paths eliminated");
171 STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
174 "Number of retains before optimization");
176 "Number of releases before optimization");
178 "Number of retains after optimization");
180 "Number of releases after optimization");
189 unsigned TopDownPathCount = 0;
192 unsigned BottomUpPathCount = 0;
215 using top_down_ptr_iterator = decltype(PerPtrTopDown)::iterator;
216 using const_top_down_ptr_iterator = decltype(PerPtrTopDown)::const_iterator;
218 top_down_ptr_iterator top_down_ptr_begin() {
return PerPtrTopDown.
begin(); }
219 top_down_ptr_iterator top_down_ptr_end() {
return PerPtrTopDown.
end(); }
220 const_top_down_ptr_iterator top_down_ptr_begin()
const {
221 return PerPtrTopDown.
begin();
223 const_top_down_ptr_iterator top_down_ptr_end()
const {
224 return PerPtrTopDown.
end();
226 bool hasTopDownPtrs()
const {
227 return !PerPtrTopDown.
empty();
230 unsigned top_down_ptr_list_size()
const {
231 return std::distance(top_down_ptr_begin(), top_down_ptr_end());
234 using bottom_up_ptr_iterator = decltype(PerPtrBottomUp)::iterator;
235 using const_bottom_up_ptr_iterator =
236 decltype(PerPtrBottomUp)::const_iterator;
238 bottom_up_ptr_iterator bottom_up_ptr_begin() {
239 return PerPtrBottomUp.
begin();
241 bottom_up_ptr_iterator bottom_up_ptr_end() {
return PerPtrBottomUp.
end(); }
242 const_bottom_up_ptr_iterator bottom_up_ptr_begin()
const {
243 return PerPtrBottomUp.
begin();
245 const_bottom_up_ptr_iterator bottom_up_ptr_end()
const {
246 return PerPtrBottomUp.
end();
248 bool hasBottomUpPtrs()
const {
249 return !PerPtrBottomUp.
empty();
252 unsigned bottom_up_ptr_list_size()
const {
253 return std::distance(bottom_up_ptr_begin(), bottom_up_ptr_end());
258 void SetAsEntry() { TopDownPathCount = 1; }
262 void SetAsExit() { BottomUpPathCount = 1; }
268 return PerPtrTopDown[
Arg];
275 return PerPtrBottomUp[
Arg];
280 bottom_up_ptr_iterator findPtrBottomUpState(
const Value *
Arg) {
281 return PerPtrBottomUp.
find(
Arg);
284 void clearBottomUpPointers() {
285 PerPtrBottomUp.
clear();
288 void clearTopDownPointers() {
289 PerPtrTopDown.
clear();
292 void InitFromPred(
const BBState &Other);
293 void InitFromSucc(
const BBState &Other);
294 void MergePred(
const BBState &Other);
295 void MergeSucc(
const BBState &Other);
303 bool GetAllPathCountWithOverflow(
unsigned &PathCount)
const {
304 if (TopDownPathCount == OverflowOccurredValue ||
305 BottomUpPathCount == OverflowOccurredValue)
307 unsigned long long Product =
308 (
unsigned long long)TopDownPathCount*BottomUpPathCount;
311 return (Product >> 32) ||
312 ((PathCount = Product) == OverflowOccurredValue);
318 edge_iterator
pred_begin()
const {
return Preds.begin(); }
319 edge_iterator
pred_end()
const {
return Preds.end(); }
320 edge_iterator
succ_begin()
const {
return Succs.begin(); }
321 edge_iterator
succ_end()
const {
return Succs.end(); }
323 void addSucc(
BasicBlock *Succ) { Succs.push_back(Succ); }
324 void addPred(
BasicBlock *Pred) { Preds.push_back(Pred); }
326 bool isExit()
const {
return Succs.empty(); }
331 const unsigned BBState::OverflowOccurredValue = 0xffffffff;
340 void BBState::InitFromPred(
const BBState &Other) {
341 PerPtrTopDown =
Other.PerPtrTopDown;
342 TopDownPathCount =
Other.TopDownPathCount;
345 void BBState::InitFromSucc(
const BBState &Other) {
346 PerPtrBottomUp =
Other.PerPtrBottomUp;
347 BottomUpPathCount =
Other.BottomUpPathCount;
352 void BBState::MergePred(
const BBState &Other) {
353 if (TopDownPathCount == OverflowOccurredValue)
358 TopDownPathCount +=
Other.TopDownPathCount;
363 if (TopDownPathCount == OverflowOccurredValue) {
364 clearTopDownPointers();
370 if (TopDownPathCount <
Other.TopDownPathCount) {
371 TopDownPathCount = OverflowOccurredValue;
372 clearTopDownPointers();
379 for (
auto MI =
Other.top_down_ptr_begin(), ME =
Other.top_down_ptr_end();
381 auto Pair = PerPtrTopDown.
insert(*
MI);
388 for (
auto MI = top_down_ptr_begin(), ME = top_down_ptr_end();
MI != ME; ++
MI)
389 if (
Other.PerPtrTopDown.find(
MI->first) ==
Other.PerPtrTopDown.end())
395 void BBState::MergeSucc(
const BBState &Other) {
396 if (BottomUpPathCount == OverflowOccurredValue)
401 BottomUpPathCount +=
Other.BottomUpPathCount;
406 if (BottomUpPathCount == OverflowOccurredValue) {
407 clearBottomUpPointers();
413 if (BottomUpPathCount <
Other.BottomUpPathCount) {
414 BottomUpPathCount = OverflowOccurredValue;
415 clearBottomUpPointers();
422 for (
auto MI =
Other.bottom_up_ptr_begin(), ME =
Other.bottom_up_ptr_end();
424 auto Pair = PerPtrBottomUp.
insert(*
MI);
431 for (
auto MI = bottom_up_ptr_begin(), ME = bottom_up_ptr_end();
MI != ME;
433 if (
Other.PerPtrBottomUp.find(
MI->first) ==
Other.PerPtrBottomUp.end())
439 OS <<
" TopDown State:\n";
440 if (!BBInfo.hasTopDownPtrs()) {
443 for (
auto I = BBInfo.top_down_ptr_begin(),
E = BBInfo.top_down_ptr_end();
446 OS <<
" Ptr: " << *
I->first
447 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
448 <<
"\n ImpreciseRelease: "
449 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n"
450 <<
" HasCFGHazards: "
451 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n"
452 <<
" KnownPositive: "
453 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n"
455 <<
P.GetSeq() <<
"\n";
459 OS <<
" BottomUp State:\n";
460 if (!BBInfo.hasBottomUpPtrs()) {
463 for (
auto I = BBInfo.bottom_up_ptr_begin(),
E = BBInfo.bottom_up_ptr_end();
466 OS <<
" Ptr: " << *
I->first
467 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
468 <<
"\n ImpreciseRelease: "
469 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n"
470 <<
" HasCFGHazards: "
471 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n"
472 <<
" KnownPositive: "
473 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n"
475 <<
P.GetSeq() <<
"\n";
501 bool DisableRetainReleasePairing =
false;
505 unsigned UsedInThisFunction;
510 void OptimizeIndividualCalls(
Function &
F);
514 void OptimizeIndividualCallImpl(
521 bool OptimizeInlinedAutoreleaseRVCall(
528 BBState &MyStates)
const;
535 bool VisitInstructionTopDown(
538 &ReleaseInsertPtToRCIdentityRoots);
543 &ReleaseInsertPtToRCIdentityRoots);
560 bool &AnyPairsCompletelyEliminated);
573 void GatherStatistics(
Function &
F,
bool AfterOptimization =
false);
579 void releaseMemory();
580 bool hasCFGChanged()
const {
return CFGChanged; }
590 bool doInitialization(
Module &M)
override {
595 return OCAO.run(
F, getAnalysis<AAResultsWrapperPass>().getAAResults());
597 void releaseMemory()
override { OCAO.releaseMemory(); }
615 void ObjCARCOptLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
634 }
else if (
const InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
636 if (II->getNormalDest() == RetainRVParent) {
646 assert(!BundledInsts->contains(RetainRV) &&
647 "a bundled retainRV's argument should be a call");
653 LLVM_DEBUG(
dbgs() <<
"Transforming objc_retainAutoreleasedReturnValue => "
654 "objc_retain since the operand is not a return value.\n"
656 << *RetainRV <<
"\n");
659 cast<CallInst>(RetainRV)->setCalledFunction(NewDecl);
666 bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
670 if (BundledInsts->contains(Inst))
679 if (
Arg != AutoreleaseRVArg) {
693 LLVM_DEBUG(
dbgs() <<
"Found inlined objc_autoreleaseReturnValue '"
694 << *AutoreleaseRV <<
"' paired with '" << *Inst <<
"'\n");
698 cast<CallInst>(AutoreleaseRV)->getArgOperand(0));
711 Value *
CallArg = cast<CallInst>(Inst)->getArgOperand(0);
715 "Expected UnsafeClaimRV to be safe to tail call");
728 void ObjCARCOpt::OptimizeAutoreleaseRVCall(
Function &
F,
736 if (isa<ConstantData>(Ptr))
740 Users.push_back(Ptr);
743 if (
const PHINode *PN = dyn_cast<PHINode>(Ptr))
747 Ptr =
Users.pop_back_val();
751 if (isa<BitCastInst>(U))
754 }
while (!
Users.empty());
760 dbgs() <<
"Transforming objc_autoreleaseReturnValue => "
761 "objc_autorelease since its operand is not used as a return "
764 << *AutoreleaseRV <<
"\n");
766 CallInst *AutoreleaseRVCI = cast<CallInst>(AutoreleaseRV);
788 if (!BlockColors.
empty()) {
790 assert(CV.
size() == 1 &&
"non-unique color for block!");
802 void ObjCARCOpt::OptimizeIndividualCalls(
Function &
F) {
803 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeIndividualCalls ==\n");
805 UsedInThisFunction = 0;
808 if (
F.hasPersonalityFn() &&
815 const Value *DelayedAutoreleaseRVArg =
nullptr;
817 assert(!DelayedAutoreleaseRV || !AutoreleaseRV);
819 DelayedAutoreleaseRVArg =
nullptr;
821 auto optimizeDelayedAutoreleaseRV = [&]() {
822 if (!DelayedAutoreleaseRV)
824 OptimizeIndividualCallImpl(
F, BlockColors, DelayedAutoreleaseRV,
826 DelayedAutoreleaseRVArg);
827 setDelayedAutoreleaseRV(
nullptr);
829 auto shouldDelayAutoreleaseRV = [&](
Instruction *NonARCInst) {
831 if (!DelayedAutoreleaseRV)
836 if (NonARCInst->isTerminator())
846 auto *CB = dyn_cast<CallBase>(NonARCInst);
856 if (
auto *CI = dyn_cast<CallInst>(Inst))
858 BundledInsts->insertRVCall(&*
I, CI);
868 optimizeDelayedAutoreleaseRV();
876 if (!shouldDelayAutoreleaseRV(Inst))
877 optimizeDelayedAutoreleaseRV();
880 optimizeDelayedAutoreleaseRV();
881 setDelayedAutoreleaseRV(Inst);
885 if (DelayedAutoreleaseRV) {
887 if (OptimizeInlinedAutoreleaseRVCall(
F, BlockColors, Inst,
Arg, Class,
888 DelayedAutoreleaseRV,
889 DelayedAutoreleaseRVArg)) {
890 setDelayedAutoreleaseRV(
nullptr);
893 optimizeDelayedAutoreleaseRV();
898 OptimizeIndividualCallImpl(
F, BlockColors, Inst, Class,
Arg);
902 optimizeDelayedAutoreleaseRV();
914 if (
auto *GV = dyn_cast<GlobalVariable>(V))
915 if (GV->hasAttribute(
"objc_arc_inert"))
918 if (
auto PN = dyn_cast<PHINode>(V)) {
920 if (!VisitedPhis.
insert(PN).second)
932 void ObjCARCOpt::OptimizeIndividualCallImpl(
935 LLVM_DEBUG(
dbgs() <<
"Visiting: Class: " << Class <<
"; " << *Inst <<
"\n");
940 if (BundledInsts->contains(Inst)) {
941 UsedInThisFunction |= 1 << unsigned(Class);
979 CallInst *CI = cast<CallInst>(Inst);
986 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
988 << *CI <<
"\nNew = " << *NewValue <<
"\n");
997 CallInst *CI = cast<CallInst>(Inst);
1006 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
1008 << *CI <<
"\nNew = " << *NewValue <<
"\n");
1017 if (OptimizeRetainRVCall(
F, Inst))
1021 OptimizeAutoreleaseRVCall(
F, Inst, Class);
1043 LLVM_DEBUG(
dbgs() <<
"Replacing autorelease{,RV}(x) with objc_release(x) "
1044 "since x is otherwise unused.\nOld: "
1045 << *Call <<
"\nNew: " << *NewCall <<
"\n");
1055 if (
IsAlwaysTail(Class) && !cast<CallInst>(Inst)->isNoTailCall()) {
1058 dbgs() <<
"Adding tail keyword to function since it can never be "
1059 "passed stack args: "
1061 cast<CallInst>(Inst)->setTailCall();
1068 LLVM_DEBUG(
dbgs() <<
"Removing tail keyword from function: " << *Inst
1070 cast<CallInst>(Inst)->setTailCall(
false);
1076 LLVM_DEBUG(
dbgs() <<
"Found no throw class. Setting nounwind on: " << *Inst
1078 cast<CallInst>(Inst)->setDoesNotThrow();
1083 UsedInThisFunction |= 1 << unsigned(Class);
1095 LLVM_DEBUG(
dbgs() <<
"ARC calls with null are no-ops. Erasing: " << *Inst
1103 UsedInThisFunction |= 1 << unsigned(Class);
1116 Worklist.push_back(std::make_pair(Inst,
Arg));
1118 std::pair<Instruction *, const Value *> Pair = Worklist.
pop_back_val();
1128 bool HasNull =
false;
1129 bool HasCriticalEdges =
false;
1136 HasCriticalEdges =
true;
1141 if (HasCriticalEdges)
1184 CallInst *CInst = cast<CallInst>(Inst);
1193 CloneCallInstForBB(*CInst, *InsertPos->
getParent(), BlockColors));
1194 if (
Op->getType() != ParamTy)
1200 "And inserting clone at "
1201 << *InsertPos <<
"\n");
1202 Worklist.push_back(std::make_pair(Clone, Incoming));
1207 }
while (!Worklist.empty());
1213 const bool SuccSRRIKnownSafe,
1215 bool &SomeSuccHasSame,
1216 bool &AllSuccsHaveSame,
1217 bool &NotAllSeqEqualButKnownSafe,
1218 bool &ShouldContinue) {
1221 if (!
S.IsKnownSafe() && !SuccSRRIKnownSafe) {
1222 S.ClearSequenceProgress();
1225 S.SetCFGHazardAfflicted(
true);
1226 ShouldContinue =
true;
1230 SomeSuccHasSame =
true;
1234 if (!
S.IsKnownSafe() && !SuccSRRIKnownSafe)
1235 AllSuccsHaveSame =
false;
1237 NotAllSeqEqualButKnownSafe =
true;
1250 const bool SuccSRRIKnownSafe,
1252 bool &SomeSuccHasSame,
1253 bool &AllSuccsHaveSame,
1254 bool &NotAllSeqEqualButKnownSafe) {
1257 SomeSuccHasSame =
true;
1262 if (!
S.IsKnownSafe() && !SuccSRRIKnownSafe)
1263 AllSuccsHaveSame =
false;
1265 NotAllSeqEqualButKnownSafe =
true;
1280 BBState &MyStates)
const {
1283 for (
auto I = MyStates.top_down_ptr_begin(),
E = MyStates.top_down_ptr_end();
1286 const Sequence Seq =
I->second.GetSeq();
1295 "Unknown top down sequence state.");
1298 bool SomeSuccHasSame =
false;
1299 bool AllSuccsHaveSame =
true;
1300 bool NotAllSeqEqualButKnownSafe =
false;
1306 BBStates.
find(Succ);
1316 if (SuccSSeq ==
S_None) {
1317 S.ClearSequenceProgress();
1323 const bool SuccSRRIKnownSafe = SuccS.
IsKnownSafe();
1327 switch(
S.GetSeq()) {
1329 bool ShouldContinue =
false;
1331 AllSuccsHaveSame, NotAllSeqEqualButKnownSafe,
1339 SomeSuccHasSame, AllSuccsHaveSame,
1340 NotAllSeqEqualButKnownSafe);
1353 if (SomeSuccHasSame && !AllSuccsHaveSame) {
1354 S.ClearSequenceProgress();
1355 }
else if (NotAllSeqEqualButKnownSafe) {
1360 S.SetCFGHazardAfflicted(
true);
1365 bool ObjCARCOpt::VisitInstructionBottomUp(
1367 BBState &MyStates) {
1368 bool NestingDetected =
false;
1379 NestingDetected |=
S.InitBottomUp(MDKindCache, Inst);
1391 if (
S.MatchWithRetain()) {
1396 Retains[Inst] =
S.GetRRInfo();
1398 S.ClearSequenceProgress();
1405 MyStates.clearBottomUpPointers();
1406 return NestingDetected;
1410 return NestingDetected;
1417 for (
auto MI = MyStates.bottom_up_ptr_begin(),
1418 ME = MyStates.bottom_up_ptr_end();
1425 if (
S.HandlePotentialAlterRefCount(Inst, Ptr, PA, Class))
1428 S.HandlePotentialUse(
BB, Inst, Ptr, PA, Class);
1431 return NestingDetected;
1439 bool NestingDetected =
false;
1440 BBState &MyStates = BBStates[
BB];
1444 BBState::edge_iterator
SI(MyStates.succ_begin()),
1445 SE(MyStates.succ_end());
1450 MyStates.InitFromSucc(
I->second);
1452 for (;
SI != SE; ++
SI) {
1454 I = BBStates.
find(Succ);
1456 MyStates.MergeSucc(
I->second);
1461 << BBStates[
BB] <<
"\n"
1462 <<
"Performing Dataflow:\n");
1469 if (isa<InvokeInst>(Inst))
1474 NestingDetected |= VisitInstructionBottomUp(Inst,
BB, Retains, MyStates);
1478 if (MyStates.bottom_up_ptr_list_size() >
MaxPtrStates) {
1479 DisableRetainReleasePairing =
true;
1487 for (BBState::edge_iterator PI(MyStates.pred_begin()),
1488 PE(MyStates.pred_end()); PI != PE; ++PI) {
1491 NestingDetected |= VisitInstructionBottomUp(II,
BB, Retains, MyStates);
1496 return NestingDetected;
1505 &ReleaseInsertPtToRCIdentityRoots) {
1506 for (
auto &
P : Retains) {
1513 for (
const Instruction *InsertPt :
P.second.ReverseInsertPts)
1514 ReleaseInsertPtToRCIdentityRoots[InsertPt].insert(Root);
1524 &ReleaseInsertPtToRCIdentityRoots) {
1525 auto I = ReleaseInsertPtToRCIdentityRoots.find(InsertPt);
1526 if (
I == ReleaseInsertPtToRCIdentityRoots.end())
1531 bool ObjCARCOpt::VisitInstructionTopDown(
1534 &ReleaseInsertPtToRCIdentityRoots) {
1535 bool NestingDetected =
false;
1543 Inst, ReleaseInsertPtToRCIdentityRoots))
1544 for (
auto *Root : *Roots) {
1552 S.SetCFGHazardAfflicted(
true);
1568 NestingDetected |=
S.InitTopDown(Class, Inst);
1578 if (
S.MatchWithRelease(MDKindCache, Inst)) {
1582 Releases[Inst] =
S.GetRRInfo();
1583 S.ClearSequenceProgress();
1589 MyStates.clearTopDownPointers();
1601 for (
auto MI = MyStates.top_down_ptr_begin(),
1602 ME = MyStates.top_down_ptr_end();
1608 if (
S.HandlePotentialAlterRefCount(Inst, Ptr, PA, Class, *BundledInsts))
1611 S.HandlePotentialUse(Inst, Ptr, PA, Class);
1614 return NestingDetected;
1617 bool ObjCARCOpt::VisitTopDown(
1621 &ReleaseInsertPtToRCIdentityRoots) {
1623 bool NestingDetected =
false;
1624 BBState &MyStates = BBStates[
BB];
1628 BBState::edge_iterator PI(MyStates.pred_begin()),
1629 PE(MyStates.pred_end());
1634 MyStates.InitFromPred(
I->second);
1636 for (; PI != PE; ++PI) {
1638 I = BBStates.
find(Pred);
1640 MyStates.MergePred(
I->second);
1647 if (!
BB->hasNPredecessors(MyStates.pred_end() - MyStates.pred_begin()))
1648 for (
auto I = MyStates.top_down_ptr_begin(),
1649 E = MyStates.top_down_ptr_end();
1651 I->second.SetCFGHazardAfflicted(
true);
1654 << BBStates[
BB] <<
"\n"
1655 <<
"Performing Dataflow:\n");
1661 NestingDetected |= VisitInstructionTopDown(
1662 &Inst, Releases, MyStates, ReleaseInsertPtToRCIdentityRoots);
1666 if (MyStates.top_down_ptr_list_size() >
MaxPtrStates) {
1667 DisableRetainReleasePairing =
true;
1672 LLVM_DEBUG(
dbgs() <<
"\nState Before Checking for CFG Hazards:\n"
1673 << BBStates[
BB] <<
"\n\n");
1674 CheckForCFGHazards(
BB, BBStates, MyStates);
1676 return NestingDetected;
1683 unsigned NoObjCARCExceptionsMDKind,
1695 BBState &MyStates = BBStates[EntryBB];
1696 MyStates.SetAsEntry();
1698 SuccStack.push_back(std::make_pair(EntryBB,
succ_iterator(EntryTI)));
1706 while (SuccStack.back().second != SE) {
1707 BasicBlock *SuccBB = *SuccStack.back().second++;
1708 if (Visited.
insert(SuccBB).second) {
1709 SuccStack.push_back(
1711 BBStates[CurrBB].addSucc(SuccBB);
1712 BBState &SuccStates = BBStates[SuccBB];
1713 SuccStates.addPred(CurrBB);
1718 if (!OnStack.
count(SuccBB)) {
1719 BBStates[CurrBB].addSucc(SuccBB);
1720 BBStates[SuccBB].addPred(CurrBB);
1723 OnStack.
erase(CurrBB);
1724 PostOrder.push_back(CurrBB);
1725 SuccStack.pop_back();
1726 }
while (!SuccStack.empty());
1735 BBState &MyStates = BBStates[&ExitBB];
1736 if (!MyStates.isExit())
1739 MyStates.SetAsExit();
1741 PredStack.push_back(std::make_pair(&ExitBB, MyStates.pred_begin()));
1743 while (!PredStack.empty()) {
1744 reverse_dfs_next_succ:
1745 BBState::edge_iterator PE = BBStates[PredStack.back().first].pred_end();
1746 while (PredStack.back().second != PE) {
1749 PredStack.push_back(std::make_pair(
BB, BBStates[
BB].
pred_begin()));
1750 goto reverse_dfs_next_succ;
1753 ReverseCFGPostOrder.push_back(PredStack.
pop_back_val().first);
1775 bool BottomUpNestingDetected =
false;
1777 BottomUpNestingDetected |= VisitBottomUp(
BB, BBStates, Retains);
1778 if (DisableRetainReleasePairing)
1783 ReleaseInsertPtToRCIdentityRoots;
1787 bool TopDownNestingDetected =
false;
1789 TopDownNestingDetected |=
1790 VisitTopDown(
BB, BBStates, Releases, ReleaseInsertPtToRCIdentityRoots);
1791 if (DisableRetainReleasePairing)
1795 return TopDownNestingDetected && BottomUpNestingDetected;
1812 Value *MyArg = ArgTy == ParamTy ?
Arg :
1816 Call->setDoesNotThrow();
1817 Call->setTailCall();
1821 "At insertion point: "
1822 << *InsertPt <<
"\n");
1825 Value *MyArg = ArgTy == ParamTy ?
Arg :
1832 Call->setDoesNotThrow();
1834 Call->setTailCall();
1838 "At insertion point: "
1839 << *InsertPt <<
"\n");
1844 Retains.
blot(OrigRetain);
1845 DeadInsts.push_back(OrigRetain);
1846 LLVM_DEBUG(
dbgs() <<
"Deleting retain: " << *OrigRetain <<
"\n");
1849 Releases.
erase(OrigRelease);
1850 DeadInsts.push_back(OrigRelease);
1851 LLVM_DEBUG(
dbgs() <<
"Deleting release: " << *OrigRelease <<
"\n");
1855 bool ObjCARCOpt::PairUpRetainsAndReleases(
1862 bool &AnyPairsCompletelyEliminated) {
1866 bool KnownSafeTD =
true, KnownSafeBU =
true;
1867 bool CFGHazardAfflicted =
false;
1873 unsigned OldDelta = 0;
1874 unsigned NewDelta = 0;
1875 unsigned OldCount = 0;
1876 unsigned NewCount = 0;
1877 bool FirstRelease =
true;
1881 auto It = Retains.
find(NewRetain);
1883 const RRInfo &NewRetainRRI = It->second;
1887 auto Jt = Releases.
find(NewRetainRelease);
1888 if (Jt == Releases.
end())
1890 const RRInfo &NewRetainReleaseRRI = Jt->second;
1897 if (!NewRetainReleaseRRI.
Calls.count(NewRetain))
1900 if (ReleasesToMove.
Calls.insert(NewRetainRelease).second) {
1903 const BBState &NRRBBState = BBStates[NewRetainRelease->
getParent()];
1904 unsigned PathCount = BBState::OverflowOccurredValue;
1905 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1907 assert(PathCount != BBState::OverflowOccurredValue &&
1908 "PathCount at this point can not be "
1909 "OverflowOccurredValue.");
1910 OldDelta -= PathCount;
1918 FirstRelease =
false;
1934 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1935 PathCount = BBState::OverflowOccurredValue;
1936 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1938 assert(PathCount != BBState::OverflowOccurredValue &&
1939 "PathCount at this point can not be "
1940 "OverflowOccurredValue.");
1941 NewDelta -= PathCount;
1944 NewReleases.push_back(NewRetainRelease);
1949 if (NewReleases.empty())
break;
1953 auto It = Releases.
find(NewRelease);
1955 const RRInfo &NewReleaseRRI = It->second;
1959 auto Jt = Retains.
find(NewReleaseRetain);
1960 if (Jt == Retains.
end())
1962 const RRInfo &NewReleaseRetainRRI = Jt->second;
1969 if (!NewReleaseRetainRRI.
Calls.count(NewRelease))
1972 if (RetainsToMove.
Calls.insert(NewReleaseRetain).second) {
1975 const BBState &NRRBBState = BBStates[NewReleaseRetain->
getParent()];
1976 unsigned PathCount = BBState::OverflowOccurredValue;
1977 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1979 assert(PathCount != BBState::OverflowOccurredValue &&
1980 "PathCount at this point can not be "
1981 "OverflowOccurredValue.");
1982 OldDelta += PathCount;
1983 OldCount += PathCount;
1991 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1993 PathCount = BBState::OverflowOccurredValue;
1994 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1996 assert(PathCount != BBState::OverflowOccurredValue &&
1997 "PathCount at this point can not be "
1998 "OverflowOccurredValue.");
1999 NewDelta += PathCount;
2000 NewCount += PathCount;
2003 NewRetains.push_back(NewReleaseRetain);
2007 if (NewRetains.empty())
break;
2011 bool UnconditionallySafe = KnownSafeTD && KnownSafeBU;
2012 if (UnconditionallySafe) {
2027 const bool WillPerformCodeMotion =
2030 if (CFGHazardAfflicted && WillPerformCodeMotion)
2043 assert(OldCount != 0 &&
"Unreachable code?");
2044 NumRRs += OldCount - NewCount;
2046 AnyPairsCompletelyEliminated = NewCount == 0;
2054 bool ObjCARCOpt::PerformCodePlacement(
2058 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::PerformCodePlacement ==\n");
2060 bool AnyPairsCompletelyEliminated =
false;
2079 bool KnownSafe = isa<Constant>(
Arg) || isa<AllocaInst>(
Arg);
2085 dyn_cast<GlobalVariable>(
2087 if (GV->isConstant())
2092 RRInfo RetainsToMove, ReleasesToMove;
2094 bool PerformMoveCalls = PairUpRetainsAndReleases(
2095 BBStates, Retains, Releases, M, Retain, DeadInsts,
2096 RetainsToMove, ReleasesToMove,
Arg, KnownSafe,
2097 AnyPairsCompletelyEliminated);
2099 if (PerformMoveCalls) {
2102 MoveCalls(
Arg, RetainsToMove, ReleasesToMove,
2103 Retains, Releases, DeadInsts, M);
2109 while (!DeadInsts.empty())
2112 return AnyPairsCompletelyEliminated;
2116 void ObjCARCOpt::OptimizeWeakCalls(
Function &
F) {
2150 switch (EarlierClass) {
2156 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
2159 switch (PA.getAA()->alias(
Arg, EarlierArg)) {
2169 Call->replaceAllUsesWith(EarlierCall);
2170 Call->eraseFromParent();
2185 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
2188 switch (PA.getAA()->alias(
Arg, EarlierArg)) {
2199 Call->eraseFromParent();
2239 const Instruction *UserInst = cast<Instruction>(U);
2251 CallInst *UserInst = cast<CallInst>(U);
2266 Alloca->eraseFromParent();
2274 bool ObjCARCOpt::OptimizeSequences(
Function &
F) {
2287 bool NestingDetected = Visit(
F, BBStates, Retains, Releases);
2289 if (DisableRetainReleasePairing)
2293 bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
2297 return AnyPairsCompletelyEliminated && NestingDetected;
2310 if (!Call ||
Arg != Call)
2327 auto *
Retain = dyn_cast_or_null<CallInst>(
2369 void ObjCARCOpt::OptimizeReturns(
Function &
F) {
2370 if (!
F.getReturnType()->isPointerTy())
2405 (!
Call->isTailCall() &&
2413 LLVM_DEBUG(
dbgs() <<
"Erasing: " << *Retain <<
"\nErasing: " << *Autorelease
2415 BundledInsts->eraseInst(Retain);
2422 ObjCARCOpt::GatherStatistics(
Function &
F,
bool AfterOptimization) {
2424 AfterOptimization ? NumRetainsAfterOpt : NumRetainsBeforeOpt;
2426 AfterOptimization ? NumReleasesAfterOpt : NumReleasesBeforeOpt;
2451 MDKindCache.init(&M);
2461 Changed = CFGChanged =
false;
2463 BundledInsts = &BRV;
2465 LLVM_DEBUG(
dbgs() <<
"<<< ObjCARCOpt: Visiting Function: " <<
F.getName()
2469 std::pair<bool, bool>
R = BundledInsts->insertAfterInvokes(
F,
nullptr);
2471 CFGChanged |=
R.second;
2477 GatherStatistics(
F,
false);
2486 OptimizeIndividualCalls(
F);
2496 OptimizeWeakCalls(
F);
2505 while (OptimizeSequences(
F)) {}
2515 GatherStatistics(
F,
true);
2524 void ObjCARCOpt::releaseMemory() {
2534 OCAO.init(*
F.getParent());
2537 bool CFGChanged = OCAO.hasCFGChanged();