76 #define DEBUG_TYPE "objc-arc-opts" 80 cl::desc(
"Maximum number of ptr states the optimizer keeps track of"),
91 if (isa<ConstantData>(
Arg))
94 if (
Arg->hasOneUse()) {
98 if (
GEP->hasAllZeroIndices())
102 cast<CallInst>(
Arg)->getArgOperand(0));
111 for (
const User *U :
Arg->users())
164 STATISTIC(NumNoops,
"Number of no-op objc calls eliminated");
165 STATISTIC(NumPartialNoops,
"Number of partially no-op objc calls eliminated");
166 STATISTIC(NumAutoreleases,
"Number of autoreleases converted to releases");
167 STATISTIC(NumRets,
"Number of return value forwarding " 168 "retain+autoreleases eliminated");
169 STATISTIC(NumRRs,
"Number of retain+release paths eliminated");
170 STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
173 "Number of retains before optimization");
175 "Number of releases before optimization");
177 "Number of retains after optimization");
179 "Number of releases after optimization");
188 unsigned TopDownPathCount = 0;
191 unsigned BottomUpPathCount = 0;
214 using top_down_ptr_iterator = decltype(PerPtrTopDown)::iterator;
215 using const_top_down_ptr_iterator = decltype(PerPtrTopDown)::const_iterator;
217 top_down_ptr_iterator top_down_ptr_begin() {
return PerPtrTopDown.
begin(); }
218 top_down_ptr_iterator top_down_ptr_end() {
return PerPtrTopDown.
end(); }
219 const_top_down_ptr_iterator top_down_ptr_begin()
const {
220 return PerPtrTopDown.
begin();
222 const_top_down_ptr_iterator top_down_ptr_end()
const {
223 return PerPtrTopDown.
end();
225 bool hasTopDownPtrs()
const {
226 return !PerPtrTopDown.
empty();
229 unsigned top_down_ptr_list_size()
const {
230 return std::distance(top_down_ptr_begin(), top_down_ptr_end());
233 using bottom_up_ptr_iterator = decltype(PerPtrBottomUp)::iterator;
234 using const_bottom_up_ptr_iterator =
235 decltype(PerPtrBottomUp)::const_iterator;
237 bottom_up_ptr_iterator bottom_up_ptr_begin() {
238 return PerPtrBottomUp.
begin();
240 bottom_up_ptr_iterator bottom_up_ptr_end() {
return PerPtrBottomUp.
end(); }
241 const_bottom_up_ptr_iterator bottom_up_ptr_begin()
const {
242 return PerPtrBottomUp.
begin();
244 const_bottom_up_ptr_iterator bottom_up_ptr_end()
const {
245 return PerPtrBottomUp.
end();
247 bool hasBottomUpPtrs()
const {
248 return !PerPtrBottomUp.
empty();
251 unsigned bottom_up_ptr_list_size()
const {
252 return std::distance(bottom_up_ptr_begin(), bottom_up_ptr_end());
257 void SetAsEntry() { TopDownPathCount = 1; }
261 void SetAsExit() { BottomUpPathCount = 1; }
267 return PerPtrTopDown[
Arg];
274 return PerPtrBottomUp[
Arg];
279 bottom_up_ptr_iterator findPtrBottomUpState(
const Value *
Arg) {
280 return PerPtrBottomUp.
find(
Arg);
283 void clearBottomUpPointers() {
284 PerPtrBottomUp.
clear();
287 void clearTopDownPointers() {
288 PerPtrTopDown.
clear();
291 void InitFromPred(
const BBState &Other);
292 void InitFromSucc(
const BBState &Other);
293 void MergePred(
const BBState &Other);
294 void MergeSucc(
const BBState &Other);
302 bool GetAllPathCountWithOverflow(
unsigned &PathCount)
const {
303 if (TopDownPathCount == OverflowOccurredValue ||
304 BottomUpPathCount == OverflowOccurredValue)
306 unsigned long long Product =
307 (
unsigned long long)TopDownPathCount*BottomUpPathCount;
310 return (Product >> 32) ||
311 ((PathCount = Product) == OverflowOccurredValue);
318 edge_iterator
pred_end()
const {
return Preds.
end(); }
320 edge_iterator
succ_end()
const {
return Succs.
end(); }
325 bool isExit()
const {
return Succs.
empty(); }
330 const unsigned BBState::OverflowOccurredValue = 0xffffffff;
339 void BBState::InitFromPred(
const BBState &Other) {
340 PerPtrTopDown =
Other.PerPtrTopDown;
341 TopDownPathCount =
Other.TopDownPathCount;
344 void BBState::InitFromSucc(
const BBState &Other) {
345 PerPtrBottomUp =
Other.PerPtrBottomUp;
346 BottomUpPathCount =
Other.BottomUpPathCount;
351 void BBState::MergePred(
const BBState &Other) {
352 if (TopDownPathCount == OverflowOccurredValue)
357 TopDownPathCount +=
Other.TopDownPathCount;
362 if (TopDownPathCount == OverflowOccurredValue) {
363 clearTopDownPointers();
369 if (TopDownPathCount <
Other.TopDownPathCount) {
370 TopDownPathCount = OverflowOccurredValue;
371 clearTopDownPointers();
378 for (
auto MI =
Other.top_down_ptr_begin(), ME =
Other.top_down_ptr_end();
380 auto Pair = PerPtrTopDown.
insert(*
MI);
387 for (
auto MI = top_down_ptr_begin(), ME = top_down_ptr_end();
MI != ME; ++
MI)
388 if (
Other.PerPtrTopDown.find(
MI->first) ==
Other.PerPtrTopDown.end())
394 void BBState::MergeSucc(
const BBState &Other) {
395 if (BottomUpPathCount == OverflowOccurredValue)
400 BottomUpPathCount +=
Other.BottomUpPathCount;
405 if (BottomUpPathCount == OverflowOccurredValue) {
406 clearBottomUpPointers();
412 if (BottomUpPathCount <
Other.BottomUpPathCount) {
413 BottomUpPathCount = OverflowOccurredValue;
414 clearBottomUpPointers();
421 for (
auto MI =
Other.bottom_up_ptr_begin(), ME =
Other.bottom_up_ptr_end();
423 auto Pair = PerPtrBottomUp.
insert(*
MI);
430 for (
auto MI = bottom_up_ptr_begin(), ME = bottom_up_ptr_end();
MI != ME;
432 if (
Other.PerPtrBottomUp.find(
MI->first) ==
Other.PerPtrBottomUp.end())
438 OS <<
" TopDown State:\n";
439 if (!BBInfo.hasTopDownPtrs()) {
442 for (
auto I = BBInfo.top_down_ptr_begin(),
E = BBInfo.top_down_ptr_end();
445 OS <<
" Ptr: " << *
I->first
446 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
447 <<
"\n ImpreciseRelease: " 448 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n" 449 <<
" HasCFGHazards: " 450 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n" 451 <<
" KnownPositive: " 452 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n" 454 <<
P.GetSeq() <<
"\n";
458 OS <<
" BottomUp State:\n";
459 if (!BBInfo.hasBottomUpPtrs()) {
462 for (
auto I = BBInfo.bottom_up_ptr_begin(),
E = BBInfo.bottom_up_ptr_end();
465 OS <<
" Ptr: " << *
I->first
466 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
467 <<
"\n ImpreciseRelease: " 468 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n" 469 <<
" HasCFGHazards: " 470 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n" 471 <<
" KnownPositive: " 472 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n" 474 <<
P.GetSeq() <<
"\n";
500 bool DisableRetainReleasePairing =
false;
504 unsigned UsedInThisFunction;
509 void OptimizeIndividualCalls(
Function &
F);
513 void OptimizeIndividualCallImpl(
520 bool OptimizeInlinedAutoreleaseRVCall(
527 BBState &MyStates)
const;
556 bool &AnyPairsCompletelyEliminated);
569 void GatherStatistics(
Function &
F,
bool AfterOptimization =
false);
575 void releaseMemory();
585 bool doInitialization(
Module &M)
override {
590 return OCAO.run(
F, getAnalysis<AAResultsWrapperPass>().getAAResults());
592 void releaseMemory()
override { OCAO.releaseMemory(); }
610 void ObjCARCOptLegacyPass::getAnalysisUsage(
AnalysisUsage &AU)
const {
631 }
else if (
const InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
633 if (II->getNormalDest() == RetainRVParent) {
647 LLVM_DEBUG(
dbgs() <<
"Transforming objc_retainAutoreleasedReturnValue => " 648 "objc_retain since the operand is not a return value.\n" 650 << *RetainRV <<
"\n");
653 cast<CallInst>(RetainRV)->setCalledFunction(NewDecl);
660 bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
670 if (
Arg != AutoreleaseRVArg) {
684 LLVM_DEBUG(
dbgs() <<
"Found inlined objc_autoreleaseReturnValue '" 685 << *AutoreleaseRV <<
"' paired with '" << *Inst <<
"'\n");
689 cast<CallInst>(AutoreleaseRV)->getArgOperand(0));
702 Value *
CallArg = cast<CallInst>(Inst)->getArgOperand(0);
706 "Expected ClaimRV to be safe to tail call");
719 void ObjCARCOpt::OptimizeAutoreleaseRVCall(
Function &
F,
727 if (isa<ConstantData>(Ptr))
731 Users.push_back(Ptr);
734 if (
const PHINode *PN = dyn_cast<PHINode>(Ptr))
738 Ptr =
Users.pop_back_val();
742 if (isa<BitCastInst>(U))
745 }
while (!
Users.empty());
751 dbgs() <<
"Transforming objc_autoreleaseReturnValue => " 752 "objc_autorelease since its operand is not used as a return " 755 << *AutoreleaseRV <<
"\n");
757 CallInst *AutoreleaseRVCI = cast<CallInst>(AutoreleaseRV);
779 if (!BlockColors.
empty()) {
781 assert(CV.
size() == 1 &&
"non-unique color for block!");
783 if (EHPad->isEHPad())
793 void ObjCARCOpt::OptimizeIndividualCalls(
Function &
F) {
794 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeIndividualCalls ==\n");
796 UsedInThisFunction = 0;
799 if (
F.hasPersonalityFn() &&
806 const Value *DelayedAutoreleaseRVArg =
nullptr;
808 assert(!DelayedAutoreleaseRV || !AutoreleaseRV);
810 DelayedAutoreleaseRVArg =
nullptr;
812 auto optimizeDelayedAutoreleaseRV = [&]() {
813 if (!DelayedAutoreleaseRV)
815 OptimizeIndividualCallImpl(
F, BlockColors, DelayedAutoreleaseRV,
817 DelayedAutoreleaseRVArg);
818 setDelayedAutoreleaseRV(
nullptr);
820 auto shouldDelayAutoreleaseRV = [&](
Instruction *NonARCInst) {
822 if (!DelayedAutoreleaseRV)
827 if (NonARCInst->isTerminator())
837 auto *CB = dyn_cast<CallBase>(NonARCInst);
853 optimizeDelayedAutoreleaseRV();
861 if (!shouldDelayAutoreleaseRV(Inst))
862 optimizeDelayedAutoreleaseRV();
865 optimizeDelayedAutoreleaseRV();
866 setDelayedAutoreleaseRV(Inst);
870 if (DelayedAutoreleaseRV) {
872 if (OptimizeInlinedAutoreleaseRVCall(
F, BlockColors, Inst,
Arg, Class,
873 DelayedAutoreleaseRV,
874 DelayedAutoreleaseRVArg)) {
875 setDelayedAutoreleaseRV(
nullptr);
878 optimizeDelayedAutoreleaseRV();
883 OptimizeIndividualCallImpl(
F, BlockColors, Inst, Class,
Arg);
887 optimizeDelayedAutoreleaseRV();
899 if (
auto *GV = dyn_cast<GlobalVariable>(V))
900 if (GV->hasAttribute(
"objc_arc_inert"))
903 if (
auto PN = dyn_cast<PHINode>(V)) {
905 if (!VisitedPhis.
insert(PN).second)
917 void ObjCARCOpt::OptimizeIndividualCallImpl(
920 LLVM_DEBUG(
dbgs() <<
"Visiting: Class: " << Class <<
"; " << *Inst <<
"\n");
959 CallInst *CI = cast<CallInst>(Inst);
967 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior." 969 << *CI <<
"\nNew = " << *NewValue <<
"\n");
978 CallInst *CI = cast<CallInst>(Inst);
988 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior." 990 << *CI <<
"\nNew = " << *NewValue <<
"\n");
999 if (OptimizeRetainRVCall(
F, Inst))
1003 OptimizeAutoreleaseRVCall(
F, Inst, Class);
1025 LLVM_DEBUG(
dbgs() <<
"Replacing autorelease{,RV}(x) with objc_release(x) " 1026 "since x is otherwise unused.\nOld: " 1027 << *Call <<
"\nNew: " << *NewCall <<
"\n");
1037 if (
IsAlwaysTail(Class) && !cast<CallInst>(Inst)->isNoTailCall()) {
1040 dbgs() <<
"Adding tail keyword to function since it can never be " 1041 "passed stack args: " 1043 cast<CallInst>(Inst)->setTailCall();
1050 LLVM_DEBUG(
dbgs() <<
"Removing tail keyword from function: " << *Inst
1052 cast<CallInst>(Inst)->setTailCall(
false);
1058 LLVM_DEBUG(
dbgs() <<
"Found no throw class. Setting nounwind on: " << *Inst
1060 cast<CallInst>(Inst)->setDoesNotThrow();
1065 UsedInThisFunction |= 1 <<
unsigned(Class);
1077 LLVM_DEBUG(
dbgs() <<
"ARC calls with null are no-ops. Erasing: " << *Inst
1085 UsedInThisFunction |= 1 <<
unsigned(Class);
1100 std::pair<Instruction *, const Value *> Pair = Worklist.
pop_back_val();
1110 bool HasNull =
false;
1111 bool HasCriticalEdges =
false;
1118 HasCriticalEdges =
true;
1123 if (HasCriticalEdges)
1166 CallInst *CInst = cast<CallInst>(Inst);
1175 CloneCallInstForBB(*CInst, *InsertPos->
getParent(), BlockColors));
1176 if (
Op->getType() != ParamTy)
1182 "And inserting clone at " 1183 << *InsertPos <<
"\n");
1184 Worklist.
push_back(std::make_pair(Clone, Incoming));
1189 }
while (!Worklist.
empty());
1195 const bool SuccSRRIKnownSafe,
1197 bool &SomeSuccHasSame,
1198 bool &AllSuccsHaveSame,
1199 bool &NotAllSeqEqualButKnownSafe,
1200 bool &ShouldContinue) {
1208 ShouldContinue =
true;
1212 SomeSuccHasSame =
true;
1218 AllSuccsHaveSame =
false;
1220 NotAllSeqEqualButKnownSafe =
true;
1233 const bool SuccSRRIKnownSafe,
1235 bool &SomeSuccHasSame,
1236 bool &AllSuccsHaveSame,
1237 bool &NotAllSeqEqualButKnownSafe) {
1240 SomeSuccHasSame =
true;
1247 AllSuccsHaveSame =
false;
1249 NotAllSeqEqualButKnownSafe =
true;
1262 ObjCARCOpt::CheckForCFGHazards(
const BasicBlock *BB,
1264 BBState &MyStates)
const {
1267 for (
auto I = MyStates.top_down_ptr_begin(),
E = MyStates.top_down_ptr_end();
1270 const Sequence Seq =
I->second.GetSeq();
1279 "Unknown top down sequence state.");
1282 bool SomeSuccHasSame =
false;
1283 bool AllSuccsHaveSame =
true;
1284 bool NotAllSeqEqualButKnownSafe =
false;
1290 BBStates.
find(Succ);
1293 const Sequence SuccSSeq = SuccS.GetSeq();
1300 if (SuccSSeq ==
S_None) {
1307 const bool SuccSRRIKnownSafe = SuccS.IsKnownSafe();
1313 bool ShouldContinue =
false;
1315 AllSuccsHaveSame, NotAllSeqEqualButKnownSafe,
1323 SomeSuccHasSame, AllSuccsHaveSame,
1324 NotAllSeqEqualButKnownSafe);
1338 if (SomeSuccHasSame && !AllSuccsHaveSame) {
1340 }
else if (NotAllSeqEqualButKnownSafe) {
1350 bool ObjCARCOpt::VisitInstructionBottomUp(
1352 BBState &MyStates) {
1353 bool NestingDetected =
false;
1390 MyStates.clearBottomUpPointers();
1391 return NestingDetected;
1395 return NestingDetected;
1402 for (
auto MI = MyStates.bottom_up_ptr_begin(),
1403 ME = MyStates.bottom_up_ptr_end();
1416 return NestingDetected;
1419 bool ObjCARCOpt::VisitBottomUp(
BasicBlock *BB,
1424 bool NestingDetected =
false;
1425 BBState &MyStates = BBStates[BB];
1429 BBState::edge_iterator
SI(MyStates.succ_begin()),
1430 SE(MyStates.succ_end());
1435 MyStates.InitFromSucc(
I->second);
1437 for (;
SI != SE; ++
SI) {
1439 I = BBStates.
find(Succ);
1441 MyStates.MergeSucc(
I->second);
1446 << BBStates[BB] <<
"\n" 1447 <<
"Performing Dataflow:\n");
1454 if (isa<InvokeInst>(Inst))
1459 NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates);
1463 if (MyStates.bottom_up_ptr_list_size() >
MaxPtrStates) {
1464 DisableRetainReleasePairing =
true;
1472 for (BBState::edge_iterator PI(MyStates.pred_begin()),
1473 PE(MyStates.pred_end()); PI != PE; ++PI) {
1476 NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates);
1479 LLVM_DEBUG(
dbgs() <<
"\nFinal State:\n" << BBStates[BB] <<
"\n");
1481 return NestingDetected;
1485 ObjCARCOpt::VisitInstructionTopDown(
Instruction *Inst,
1487 BBState &MyStates) {
1488 bool NestingDetected =
false;
1526 MyStates.clearTopDownPointers();
1538 for (
auto MI = MyStates.top_down_ptr_begin(),
1539 ME = MyStates.top_down_ptr_end();
1551 return NestingDetected;
1559 bool NestingDetected =
false;
1560 BBState &MyStates = BBStates[BB];
1564 BBState::edge_iterator PI(MyStates.pred_begin()),
1565 PE(MyStates.pred_end());
1570 MyStates.InitFromPred(
I->second);
1572 for (; PI != PE; ++PI) {
1574 I = BBStates.
find(Pred);
1576 MyStates.MergePred(
I->second);
1584 for (
auto I = MyStates.top_down_ptr_begin(),
1585 E = MyStates.top_down_ptr_end();
1587 I->second.SetCFGHazardAfflicted(
true);
1590 << BBStates[BB] <<
"\n" 1591 <<
"Performing Dataflow:\n");
1597 NestingDetected |= VisitInstructionTopDown(&Inst, Releases, MyStates);
1601 if (MyStates.top_down_ptr_list_size() >
MaxPtrStates) {
1602 DisableRetainReleasePairing =
true;
1607 LLVM_DEBUG(
dbgs() <<
"\nState Before Checking for CFG Hazards:\n" 1608 << BBStates[BB] <<
"\n\n");
1609 CheckForCFGHazards(BB, BBStates, MyStates);
1611 return NestingDetected;
1618 unsigned NoObjCARCExceptionsMDKind,
1630 BBState &MyStates = BBStates[EntryBB];
1631 MyStates.SetAsEntry();
1641 while (SuccStack.
back().second != SE) {
1643 if (Visited.
insert(SuccBB).second) {
1646 BBStates[CurrBB].addSucc(SuccBB);
1647 BBState &SuccStates = BBStates[SuccBB];
1648 SuccStates.addPred(CurrBB);
1653 if (!OnStack.
count(SuccBB)) {
1654 BBStates[CurrBB].addSucc(SuccBB);
1655 BBStates[SuccBB].addPred(CurrBB);
1658 OnStack.
erase(CurrBB);
1661 }
while (!SuccStack.
empty());
1670 BBState &MyStates = BBStates[&ExitBB];
1671 if (!MyStates.isExit())
1674 MyStates.SetAsExit();
1676 PredStack.
push_back(std::make_pair(&ExitBB, MyStates.pred_begin()));
1678 while (!PredStack.
empty()) {
1679 reverse_dfs_next_succ:
1680 BBState::edge_iterator PE = BBStates[PredStack.
back().first].pred_end();
1681 while (PredStack.
back().second != PE) {
1683 if (Visited.
insert(BB).second) {
1685 goto reverse_dfs_next_succ;
1710 bool BottomUpNestingDetected =
false;
1712 BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains);
1713 if (DisableRetainReleasePairing)
1718 bool TopDownNestingDetected =
false;
1720 TopDownNestingDetected |= VisitTopDown(BB, BBStates, Releases);
1721 if (DisableRetainReleasePairing)
1725 return TopDownNestingDetected && BottomUpNestingDetected;
1742 Value *MyArg = ArgTy == ParamTy ?
Arg :
1746 Call->setDoesNotThrow();
1747 Call->setTailCall();
1751 "At insertion point: " 1752 << *InsertPt <<
"\n");
1755 Value *MyArg = ArgTy == ParamTy ?
Arg :
1762 Call->setDoesNotThrow();
1764 Call->setTailCall();
1768 "At insertion point: " 1769 << *InsertPt <<
"\n");
1774 Retains.
blot(OrigRetain);
1776 LLVM_DEBUG(
dbgs() <<
"Deleting retain: " << *OrigRetain <<
"\n");
1779 Releases.
erase(OrigRelease);
1781 LLVM_DEBUG(
dbgs() <<
"Deleting release: " << *OrigRelease <<
"\n");
1785 bool ObjCARCOpt::PairUpRetainsAndReleases(
1792 bool &AnyPairsCompletelyEliminated) {
1796 bool KnownSafeTD =
true, KnownSafeBU =
true;
1797 bool CFGHazardAfflicted =
false;
1803 unsigned OldDelta = 0;
1804 unsigned NewDelta = 0;
1805 unsigned OldCount = 0;
1806 unsigned NewCount = 0;
1807 bool FirstRelease =
true;
1811 auto It = Retains.
find(NewRetain);
1813 const RRInfo &NewRetainRRI = It->second;
1814 KnownSafeTD &= NewRetainRRI.KnownSafe;
1815 CFGHazardAfflicted |= NewRetainRRI.CFGHazardAfflicted;
1816 for (
Instruction *NewRetainRelease : NewRetainRRI.Calls) {
1817 auto Jt = Releases.
find(NewRetainRelease);
1818 if (Jt == Releases.
end())
1820 const RRInfo &NewRetainReleaseRRI = Jt->second;
1827 if (!NewRetainReleaseRRI.
Calls.count(NewRetain))
1830 if (ReleasesToMove.
Calls.insert(NewRetainRelease).second) {
1833 const BBState &NRRBBState = BBStates[NewRetainRelease->
getParent()];
1834 unsigned PathCount = BBState::OverflowOccurredValue;
1835 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1837 assert(PathCount != BBState::OverflowOccurredValue &&
1838 "PathCount at this point can not be " 1839 "OverflowOccurredValue.");
1840 OldDelta -= PathCount;
1848 FirstRelease =
false;
1864 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1865 PathCount = BBState::OverflowOccurredValue;
1866 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1868 assert(PathCount != BBState::OverflowOccurredValue &&
1869 "PathCount at this point can not be " 1870 "OverflowOccurredValue.");
1871 NewDelta -= PathCount;
1874 NewReleases.
push_back(NewRetainRelease);
1879 if (NewReleases.
empty())
break;
1883 auto It = Releases.
find(NewRelease);
1885 const RRInfo &NewReleaseRRI = It->second;
1887 CFGHazardAfflicted |= NewReleaseRRI.CFGHazardAfflicted;
1888 for (
Instruction *NewReleaseRetain : NewReleaseRRI.Calls) {
1889 auto Jt = Retains.
find(NewReleaseRetain);
1890 if (Jt == Retains.
end())
1892 const RRInfo &NewReleaseRetainRRI = Jt->second;
1899 if (!NewReleaseRetainRRI.
Calls.count(NewRelease))
1902 if (RetainsToMove.
Calls.insert(NewReleaseRetain).second) {
1905 const BBState &NRRBBState = BBStates[NewReleaseRetain->
getParent()];
1906 unsigned PathCount = BBState::OverflowOccurredValue;
1907 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1909 assert(PathCount != BBState::OverflowOccurredValue &&
1910 "PathCount at this point can not be " 1911 "OverflowOccurredValue.");
1912 OldDelta += PathCount;
1913 OldCount += PathCount;
1921 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1923 PathCount = BBState::OverflowOccurredValue;
1924 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1926 assert(PathCount != BBState::OverflowOccurredValue &&
1927 "PathCount at this point can not be " 1928 "OverflowOccurredValue.");
1929 NewDelta += PathCount;
1930 NewCount += PathCount;
1933 NewRetains.push_back(NewReleaseRetain);
1937 if (NewRetains.empty())
break;
1941 bool UnconditionallySafe = KnownSafeTD && KnownSafeBU;
1942 if (UnconditionallySafe) {
1957 const bool WillPerformCodeMotion =
1960 if (CFGHazardAfflicted && WillPerformCodeMotion)
1973 assert(OldCount != 0 &&
"Unreachable code?");
1974 NumRRs += OldCount - NewCount;
1976 AnyPairsCompletelyEliminated = NewCount == 0;
1984 bool ObjCARCOpt::PerformCodePlacement(
1988 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::PerformCodePlacement ==\n");
1990 bool AnyPairsCompletelyEliminated =
false;
2009 bool KnownSafe = isa<Constant>(
Arg) || isa<AllocaInst>(
Arg);
2015 dyn_cast<GlobalVariable>(
2017 if (GV->isConstant())
2022 RRInfo RetainsToMove, ReleasesToMove;
2024 bool PerformMoveCalls = PairUpRetainsAndReleases(
2025 BBStates, Retains, Releases, M, Retain, DeadInsts,
2026 RetainsToMove, ReleasesToMove,
Arg, KnownSafe,
2027 AnyPairsCompletelyEliminated);
2029 if (PerformMoveCalls) {
2032 MoveCalls(
Arg, RetainsToMove, ReleasesToMove,
2033 Retains, Releases, DeadInsts, M);
2039 while (!DeadInsts.
empty())
2042 return AnyPairsCompletelyEliminated;
2046 void ObjCARCOpt::OptimizeWeakCalls(
Function &
F) {
2080 switch (EarlierClass) {
2086 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
2089 switch (PA.getAA()->alias(
Arg, EarlierArg)) {
2099 Call->replaceAllUsesWith(EarlierCall);
2100 Call->eraseFromParent();
2115 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
2118 switch (PA.getAA()->alias(
Arg, EarlierArg)) {
2129 Call->eraseFromParent();
2170 const Instruction *UserInst = cast<Instruction>(U);
2181 for (
auto UI = Alloca->user_begin(), UE = Alloca->user_end(); UI != UE;) {
2182 CallInst *UserInst = cast<CallInst>(*UI++);
2197 Alloca->eraseFromParent();
2205 bool ObjCARCOpt::OptimizeSequences(
Function &
F) {
2218 bool NestingDetected = Visit(
F, BBStates, Retains, Releases);
2220 if (DisableRetainReleasePairing)
2224 bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
2228 return AnyPairsCompletelyEliminated && NestingDetected;
2241 if (!Call ||
Arg != Call)
2258 auto *
Retain = dyn_cast_or_null<CallInst>(
2300 void ObjCARCOpt::OptimizeReturns(
Function &
F) {
2301 if (!
F.getReturnType()->isPointerTy())
2336 (!
Call->isTailCall() &&
2344 LLVM_DEBUG(
dbgs() <<
"Erasing: " << *Retain <<
"\nErasing: " << *Autorelease
2353 ObjCARCOpt::GatherStatistics(
Function &
F,
bool AfterOptimization) {
2355 AfterOptimization ? NumRetainsAfterOpt : NumRetainsBeforeOpt;
2357 AfterOptimization ? NumReleasesAfterOpt : NumReleasesBeforeOpt;
2387 MDKindCache.init(&M);
2403 LLVM_DEBUG(
dbgs() <<
"<<< ObjCARCOpt: Visiting Function: " <<
F.getName()
2411 GatherStatistics(
F,
false);
2420 OptimizeIndividualCalls(
F);
2430 OptimizeWeakCalls(
F);
2439 while (OptimizeSequences(
F)) {}
2449 GatherStatistics(
F,
true);
2458 void ObjCARCOpt::releaseMemory() {
2468 OCAO.init(*
F.getParent());
Pass interface - Implemented by all 'passes'.
Return a value (possibly void), from a function.
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
reference emplace_back(ArgTypes &&... Args)
This file declares special dependency analysis routines used in Objective C ARC Optimizations.
llvm::Instruction * findSingleDependency(DependenceKind Flavor, const Value *Arg, BasicBlock *StartBB, Instruction *StartInst, ProvenanceAnalysis &PA)
Find dependent instructions.
ARCInstKind GetARCInstKind(const Value *V)
Map V to its ARCInstKind equivalence class.
objc_destroyWeak (derived)
bool hasNPredecessors(unsigned N) const
Return true if this block has exactly N predecessors.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
SmallPtrSet< Instruction *, 2 > Calls
For a top-down sequence, the set of objc_retains or objc_retainBlocks.
typename SuperClass::const_iterator const_iterator
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...
This file contains a class ARCRuntimeEntryPoints for use in creating/managing references to entry poi...
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
This class represents lattice values for constants.
objc_loadWeakRetained (primitive)
typename VectorTy::const_iterator const_iterator
could call objc_release and/or "use" pointers
A Module instance is used to store all the information related to an LLVM module.
LLVM_NODISCARD bool empty() const
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
void push_back(const T &Elt)
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
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 ...
This class represents a function call, abstracting a target machine's calling convention.
objc_retainedObject, etc.
Value * GetArgRCIdentityRoot(Value *Inst)
Assuming the given instruction is one of the special calls such as objc_retain or objc_release,...
Optional< std::vector< StOtherPiece > > Other
The two locations do not alias at all.
static bool isInertARCValue(Value *V, SmallPtrSet< Value *, 1 > &VisitedPhis)
This function returns true if the value is inert.
LLVMContext & getContext() const
All values hold a context through their type.
bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release)
Return true if this set of retains can be paired with the given release.
STATISTIC(NumFunctions, "Total number of functions")
void setArgOperand(unsigned i, Value *v)
An instruction for reading from memory.
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...
iv Induction Variable Users
OperandBundleUse getOperandBundleAt(unsigned Index) const
Return the operand bundle at a specific index.
SmallPtrSet< Instruction *, 2 > ReverseInsertPts
The set of optimal insert positions for moving calls in the opposite sequence.
TinyPtrVector - This class is specialized for cases where there are normally 0 or 1 element in a vect...
bool IsNoopOnNull(ARCInstKind Class)
Test if the given class represents instructions which do nothing if passed a null pointer.
bool IsForwarding(ARCInstKind Class)
Test if the given class represents instructions which return their argument verbatim.
bool IsObjCIdentifiedObject(const Value *V)
Return true if this value refers to a distinct and identifiable object.
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))
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
iterator begin()
Instruction iterator methods.
Value * getArgOperand(unsigned i) const
AnalysisUsage & addRequired()
objc_autoreleaseReturnValue
inst_iterator inst_begin(Function *F)
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
bool IsNoopOnGlobal(ARCInstKind Class)
Test if the given class represents instructions which do nothing if passed a global variable.
This class summarizes several per-pointer runtime properties which are propagated through the flow gr...
bool IsNullOrUndef(const Value *V)
Interval::succ_iterator succ_begin(Interval *I)
succ_begin/succ_end - define methods so that Intervals may be used just like BasicBlocks can with the...
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
bool IsTailCallRelease
True of the objc_release calls are all marked with the "tail" keyword.
bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I)
(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases.
objc_retainAutoreleasedReturnValue
Type * getType() const
All values are typed, get the type of this value.
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
bool EnableARCOpts
A handy option to enable/disable all ARC Optimizations.
This class represents a no-op cast from one type to another.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
An instruction for storing to memory.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
bool IsAlwaysTail(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the "tail" keyword...
unsigned getNumOperandBundles() const
Return the number of operand bundles associated with this User.
BBIty & getBasicBlockIterator()
bool ModuleHasARC(const Module &M)
Test if the given module looks interesting to run ARC optimization on.
unsigned getNumSuccessors() const
Return the number of successors that this instruction has.
Value * getOperand(unsigned i) const
Unidirectional information about either a retain-decrement-use-release sequence or release-use-decrem...
Interval::succ_iterator succ_end(Interval *I)
raw_ostream & operator<<(raw_ostream &OS, const ARCInstKind Class)
iterator find(const_arg_type_t< KeyT > Val)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
bool isVoidTy() const
Return true if this is 'void'.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
iterator find(const KeyT &Key)
static bool runOnFunction(Function &F, bool PostInlining)
initializer< Ty > init(const Ty &Val)
bool erase(const KeyT &Val)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
A set of analyses that are preserved following a run of a transformation pass.
void HandlePotentialUse(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction.
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed.
This is an important class for using LLVM in a threaded context.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
BIty & getInstructionIterator()
A manager for alias analyses.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Interval::pred_iterator pred_begin(Interval *I)
pred_begin/pred_end - define methods so that Intervals may be used just like BasicBlocks can with the...
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &InsertPair)
like S_Release, but code motion is stopped.
EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
Represent the analysis usage information of a pass.
const Instruction & back() const
#define LLVM_ATTRIBUTE_UNUSED
FunctionPass class - This class is used to implement most global optimizations.
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
Interval::pred_iterator pred_end(Interval *I)
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.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
A cache of MDKinds used by various ARC optimizations.
bool MatchWithRetain()
Return true if this set of releases can be paired with a release.
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...
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
INITIALIZE_PASS_BEGIN(ObjCARCOptLegacyPass, "objc-arc", "ObjC ARC optimization", false, false) INITIALIZE_PASS_END(ObjCARCOptLegacyPass
This file defines common analysis utilities used by the ObjC ARC Optimizer.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
anything that is inert from an ARC perspective.
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE, "Assign register bank of generic virtual registers", false, false) RegBankSelect
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This file declares a simple ARC-aware AliasAnalysis using special knowledge of Objective C to enhance...
void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
ARCInstKind GetBasicARCInstKind(const Value *V)
Determine which objc runtime call instruction class V belongs to.
objc_release(x), !clang.imprecise_release.
The two locations may or may not alias. This is the least precise result.
The two locations precisely alias each other.
static void EraseInstruction(Instruction *CI)
Erase the given instruction.
Iterator for intrusive lists based on ilist_node.
static CallInst * FindPredecessorAutoreleaseWithSafePath(const Value *Arg, BasicBlock *BB, ReturnInst *Ret, ProvenanceAnalysis &PA)
Look for an `‘autorelease’' instruction dependent on Arg such that there are no instructions dependen...
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the generic address space (address sp...
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
void setTailCall(bool IsTc=true)
bool erase(PtrType Ptr)
erase - If the set contains the specified pointer, remove it and return true, otherwise return false.
This file declares a special form of Alias Analysis called Provenance Analysis''.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
ARCInstKind
Equivalence classes of instructions in the ARC Model.
An associative container with fast insertion-order (deterministic) iteration over its elements.
bool IsNoThrow(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the nounwind attri...
objc_unsafeClaimAutoreleasedReturnValue
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
LLVM_NODISCARD T pop_back_val()
void setPreservesCFG()
This function should be called by the pass, iff they do not:
unsigned getNumIncomingValues() const
Return the number of incoming edges.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
MDNode * ReleaseMetadata
If the Calls are objc_release calls and they all have a clang.imprecise_release tag,...
Pass * createObjCARCOptPass()
iterator_range< user_iterator > users()
Represents analyses that only rely on functions' control flow.
void ClearSequenceProgress()
objc ObjC ARC optimization
bool IsRetain(ARCInstKind Class)
Test if the given class is objc_retain or equivalent.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
SuccIterator< Instruction, BasicBlock > succ_iterator
const RRInfo & GetRRInfo() const
void preserveSet()
Mark an analysis set as preserved.
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
objc_storeWeak (primitive)
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
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...
Declarations for ObjC runtime functions and constants.
void SetCFGHazardAfflicted(const bool NewValue)
LLVM_NODISCARD bool empty() const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
foo(x) – x could possibly see a ref count decrement.
Legacy wrapper pass to provide the ObjCARCAAResult object.
succ_range successors(Instruction *I)
static const unsigned OverflowOccurredValue
bool KnownSafe
After an objc_retain, the reference count of the referenced object is known to be positive.
This class implements an extremely fast bulk output stream that can only output to a stream.
This is similar to BasicAliasAnalysis, and it uses many of the same techniques, except it uses specia...
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...
inst_iterator inst_end(Function *F)
A container for analyses that lazily runs them and caches their results.
static void ComputePostOrders(Function &F, SmallVectorImpl< BasicBlock * > &PostOrder, SmallVectorImpl< BasicBlock * > &ReverseCFGPostOrder, unsigned NoObjCARCExceptionsMDKind, DenseMap< const BasicBlock *, BBState > &BBStates)
void initializeObjCARCOptLegacyPassPass(PassRegistry &)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
auto reverse(ContainerTy &&C, std::enable_if_t< has_rbegin< ContainerTy >::value > *=nullptr)
The two locations alias, but only due to a partial overlap.
bool InitTopDown(ARCInstKind Kind, Instruction *I)
(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases.
DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)
If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...
op_range incoming_values()
static IntegerType * getInt8Ty(LLVMContext &C)
bool AreStatisticsEnabled()
Check if statistics are enabled.
bool IsNeverTail(ARCInstKind Class)
Test if the given class represents instructions which are never safe to mark with the "tail" keyword.
void blot(const KeyT &Key)
This is similar to erase, but instead of removing the element from the vector, it just zeros out the ...
void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList)
Return the list of PHI nodes that are equivalent to PN.
bool IsNoopInstruction(const Instruction *I)
const BasicBlock * getParent() const
an instruction to allocate memory on the stack
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
bool IsAutorelease(ARCInstKind Class)
Test if the given class is objc_autorelease or equivalent.