75 #define DEBUG_TYPE "objc-arc-opts" 85 if (isa<ConstantData>(Arg))
89 if (
const BitCastInst *BC = dyn_cast<BitCastInst>(Arg))
92 if (
GEP->hasAllZeroIndices())
96 cast<CallInst>(Arg)->getArgOperand(0));
158 STATISTIC(NumNoops,
"Number of no-op objc calls eliminated");
159 STATISTIC(NumPartialNoops,
"Number of partially no-op objc calls eliminated");
160 STATISTIC(NumAutoreleases,
"Number of autoreleases converted to releases");
161 STATISTIC(NumRets,
"Number of return value forwarding " 162 "retain+autoreleases eliminated");
163 STATISTIC(NumRRs,
"Number of retain+release paths eliminated");
164 STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
167 "Number of retains before optimization");
169 "Number of releases before optimization");
171 "Number of retains after optimization");
173 "Number of releases after optimization");
182 unsigned TopDownPathCount = 0;
185 unsigned BottomUpPathCount = 0;
208 using top_down_ptr_iterator = decltype(PerPtrTopDown)::iterator;
209 using const_top_down_ptr_iterator = decltype(PerPtrTopDown)::const_iterator;
211 top_down_ptr_iterator top_down_ptr_begin() {
return PerPtrTopDown.
begin(); }
212 top_down_ptr_iterator top_down_ptr_end() {
return PerPtrTopDown.
end(); }
213 const_top_down_ptr_iterator top_down_ptr_begin()
const {
214 return PerPtrTopDown.
begin();
216 const_top_down_ptr_iterator top_down_ptr_end()
const {
217 return PerPtrTopDown.
end();
219 bool hasTopDownPtrs()
const {
220 return !PerPtrTopDown.
empty();
223 using bottom_up_ptr_iterator = decltype(PerPtrBottomUp)::iterator;
224 using const_bottom_up_ptr_iterator =
225 decltype(PerPtrBottomUp)::const_iterator;
227 bottom_up_ptr_iterator bottom_up_ptr_begin() {
228 return PerPtrBottomUp.
begin();
230 bottom_up_ptr_iterator bottom_up_ptr_end() {
return PerPtrBottomUp.
end(); }
231 const_bottom_up_ptr_iterator bottom_up_ptr_begin()
const {
232 return PerPtrBottomUp.
begin();
234 const_bottom_up_ptr_iterator bottom_up_ptr_end()
const {
235 return PerPtrBottomUp.
end();
237 bool hasBottomUpPtrs()
const {
238 return !PerPtrBottomUp.
empty();
243 void SetAsEntry() { TopDownPathCount = 1; }
247 void SetAsExit() { BottomUpPathCount = 1; }
253 return PerPtrTopDown[
Arg];
260 return PerPtrBottomUp[
Arg];
265 bottom_up_ptr_iterator findPtrBottomUpState(
const Value *Arg) {
266 return PerPtrBottomUp.
find(Arg);
269 void clearBottomUpPointers() {
270 PerPtrBottomUp.
clear();
273 void clearTopDownPointers() {
274 PerPtrTopDown.
clear();
277 void InitFromPred(
const BBState &
Other);
278 void InitFromSucc(
const BBState &Other);
279 void MergePred(
const BBState &Other);
280 void MergeSucc(
const BBState &Other);
288 bool GetAllPathCountWithOverflow(
unsigned &PathCount)
const {
289 if (TopDownPathCount == OverflowOccurredValue ||
290 BottomUpPathCount == OverflowOccurredValue)
292 unsigned long long Product =
293 (
unsigned long long)TopDownPathCount*BottomUpPathCount;
296 return (Product >> 32) ||
297 ((PathCount = Product) == OverflowOccurredValue);
304 edge_iterator
pred_end()
const {
return Preds.
end(); }
306 edge_iterator
succ_end()
const {
return Succs.
end(); }
311 bool isExit()
const {
return Succs.
empty(); }
316 const unsigned BBState::OverflowOccurredValue = 0xffffffff;
325 void BBState::InitFromPred(
const BBState &
Other) {
326 PerPtrTopDown = Other.PerPtrTopDown;
327 TopDownPathCount = Other.TopDownPathCount;
330 void BBState::InitFromSucc(
const BBState &Other) {
331 PerPtrBottomUp = Other.PerPtrBottomUp;
332 BottomUpPathCount = Other.BottomUpPathCount;
337 void BBState::MergePred(
const BBState &Other) {
338 if (TopDownPathCount == OverflowOccurredValue)
343 TopDownPathCount += Other.TopDownPathCount;
348 if (TopDownPathCount == OverflowOccurredValue) {
349 clearTopDownPointers();
355 if (TopDownPathCount < Other.TopDownPathCount) {
356 TopDownPathCount = OverflowOccurredValue;
357 clearTopDownPointers();
364 for (
auto MI = Other.top_down_ptr_begin(), ME = Other.top_down_ptr_end();
366 auto Pair = PerPtrTopDown.
insert(*
MI);
373 for (
auto MI = top_down_ptr_begin(), ME = top_down_ptr_end();
MI != ME; ++
MI)
374 if (Other.PerPtrTopDown.find(
MI->first) == Other.PerPtrTopDown.end())
380 void BBState::MergeSucc(
const BBState &Other) {
381 if (BottomUpPathCount == OverflowOccurredValue)
386 BottomUpPathCount += Other.BottomUpPathCount;
391 if (BottomUpPathCount == OverflowOccurredValue) {
392 clearBottomUpPointers();
398 if (BottomUpPathCount < Other.BottomUpPathCount) {
399 BottomUpPathCount = OverflowOccurredValue;
400 clearBottomUpPointers();
407 for (
auto MI = Other.bottom_up_ptr_begin(), ME = Other.bottom_up_ptr_end();
409 auto Pair = PerPtrBottomUp.
insert(*
MI);
416 for (
auto MI = bottom_up_ptr_begin(), ME = bottom_up_ptr_end();
MI != ME;
418 if (Other.PerPtrBottomUp.find(
MI->first) == Other.PerPtrBottomUp.end())
424 OS <<
" TopDown State:\n";
425 if (!BBInfo.hasTopDownPtrs()) {
428 for (
auto I = BBInfo.top_down_ptr_begin(),
E = BBInfo.top_down_ptr_end();
431 OS <<
" Ptr: " << *
I->first
432 <<
"\n KnownSafe: " << (P.
IsKnownSafe()?
"true":
"false")
433 <<
"\n ImpreciseRelease: " 435 <<
" HasCFGHazards: " 437 <<
" KnownPositive: " 444 OS <<
" BottomUp State:\n";
445 if (!BBInfo.hasBottomUpPtrs()) {
448 for (
auto I = BBInfo.bottom_up_ptr_begin(),
E = BBInfo.bottom_up_ptr_end();
451 OS <<
" Ptr: " << *
I->first
452 <<
"\n KnownSafe: " << (P.
IsKnownSafe()?
"true":
"false")
453 <<
"\n ImpreciseRelease: " 455 <<
" HasCFGHazards: " 457 <<
" KnownPositive: " 486 unsigned UsedInThisFunction;
491 void OptimizeIndividualCalls(
Function &F);
495 BBState &MyStates)
const;
524 Value *Arg,
bool KnownSafe,
525 bool &AnyPairsCompletelyEliminated);
531 void OptimizeWeakCalls(
Function &F);
533 bool OptimizeSequences(
Function &F);
538 void GatherStatistics(
Function &F,
bool AfterOptimization =
false);
542 bool doInitialization(
Module &M)
override;
544 void releaseMemory()
override;
559 "objc-arc",
"ObjC ARC optimization",
false,
false)
562 "objc-arc",
"ObjC ARC optimization",
false,
false)
565 return new ObjCARCOpt();
593 if (II->getNormalDest() == RetainRVParent) {
605 EquivalentArgs.
insert(Arg);
608 if (
const PHINode *PN = dyn_cast<PHINode>(Arg)) {
627 LLVM_DEBUG(
dbgs() <<
"Erasing autoreleaseRV,retainRV pair: " << *I <<
"\n" 628 <<
"Erasing " << *RetainRV <<
"\n");
640 LLVM_DEBUG(
dbgs() <<
"Transforming objc_retainAutoreleasedReturnValue => " 641 "objc_retain since the operand is not a return value.\n" 643 << *RetainRV <<
"\n");
646 cast<CallInst>(
RetainRV)->setCalledFunction(NewDecl);
655 void ObjCARCOpt::OptimizeAutoreleaseRVCall(
Function &F,
663 if (isa<ConstantData>(Ptr))
670 if (
const PHINode *PN = dyn_cast<PHINode>(Ptr))
678 if (isa<BitCastInst>(U))
681 }
while (!Users.
empty());
687 dbgs() <<
"Transforming objc_autoreleaseReturnValue => " 688 "objc_autorelease since its operand is not used as a return " 691 << *AutoreleaseRV <<
"\n");
715 if (!BlockColors.
empty()) {
717 assert(CV.
size() == 1 &&
"non-unique color for block!");
719 if (EHPad->isEHPad())
729 void ObjCARCOpt::OptimizeIndividualCalls(
Function &F) {
730 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeIndividualCalls ==\n");
732 UsedInThisFunction = 0;
745 LLVM_DEBUG(
dbgs() <<
"Visiting: Class: " << Class <<
"; " << *Inst <<
"\n");
771 CallInst *CI = cast<CallInst>(Inst);
780 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior." 782 << *CI <<
"\nNew = " << *NewValue <<
"\n");
791 CallInst *CI = cast<CallInst>(Inst);
802 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior." 804 << *CI <<
"\nNew = " << *NewValue <<
"\n");
813 if (OptimizeRetainRVCall(F, Inst))
817 OptimizeAutoreleaseRVCall(F, Inst, Class);
840 dbgs() <<
"Replacing autorelease{,RV}(x) with objc_release(x) " 841 "since x is otherwise unused.\nOld: " 842 << *Call <<
"\nNew: " << *NewCall <<
"\n");
855 dbgs() <<
"Adding tail keyword to function since it can never be " 856 "passed stack args: " 858 cast<CallInst>(Inst)->setTailCall();
865 LLVM_DEBUG(
dbgs() <<
"Removing tail keyword from function: " << *Inst
867 cast<CallInst>(Inst)->setTailCall(
false);
873 LLVM_DEBUG(
dbgs() <<
"Found no throw class. Setting nounwind on: " 879 UsedInThisFunction |= 1 <<
unsigned(Class);
889 LLVM_DEBUG(
dbgs() <<
"ARC calls with null are no-ops. Erasing: " << *Inst
897 UsedInThisFunction |= 1 <<
unsigned(Class);
910 Worklist.
push_back(std::make_pair(Inst, Arg));
912 std::pair<Instruction *, const Value *> Pair = Worklist.
pop_back_val();
921 bool HasNull =
false;
922 bool HasCriticalEdges =
false;
930 HasCriticalEdges =
true;
935 if (!HasCriticalEdges && HasNull) {
951 DependingInstructions, Visited, PA);
957 DependingInstructions, Visited, PA);
971 if (DependingInstructions.
size() == 1 &&
972 *DependingInstructions.
begin() == PN) {
976 CallInst *CInst = cast<CallInst>(Inst);
984 CallInst *Clone = cast<CallInst>(CloneCallInstForBB(
985 *CInst, *InsertPos->
getParent(), BlockColors));
993 "And inserting clone at " 994 << *InsertPos <<
"\n");
995 Worklist.
push_back(std::make_pair(Clone, Incoming));
1004 }
while (!Worklist.
empty());
1011 const bool SuccSRRIKnownSafe,
1013 bool &SomeSuccHasSame,
1014 bool &AllSuccsHaveSame,
1015 bool &NotAllSeqEqualButKnownSafe,
1016 bool &ShouldContinue) {
1024 ShouldContinue =
true;
1028 SomeSuccHasSame =
true;
1034 AllSuccsHaveSame =
false;
1036 NotAllSeqEqualButKnownSafe =
true;
1049 const bool SuccSRRIKnownSafe,
1051 bool &SomeSuccHasSame,
1052 bool &AllSuccsHaveSame,
1053 bool &NotAllSeqEqualButKnownSafe) {
1056 SomeSuccHasSame =
true;
1063 AllSuccsHaveSame =
false;
1065 NotAllSeqEqualButKnownSafe =
true;
1078 ObjCARCOpt::CheckForCFGHazards(
const BasicBlock *BB,
1080 BBState &MyStates)
const {
1083 for (
auto I = MyStates.top_down_ptr_begin(),
E = MyStates.top_down_ptr_end();
1086 const Sequence Seq =
I->second.GetSeq();
1095 "Unknown top down sequence state.");
1098 bool SomeSuccHasSame =
false;
1099 bool AllSuccsHaveSame =
true;
1100 bool NotAllSeqEqualButKnownSafe =
false;
1106 BBStates.
find(Succ);
1109 const Sequence SuccSSeq = SuccS.GetSeq();
1116 if (SuccSSeq ==
S_None) {
1123 const bool SuccSRRIKnownSafe = SuccS.IsKnownSafe();
1129 bool ShouldContinue =
false;
1131 AllSuccsHaveSame, NotAllSeqEqualButKnownSafe,
1139 SomeSuccHasSame, AllSuccsHaveSame,
1140 NotAllSeqEqualButKnownSafe);
1154 if (SomeSuccHasSame && !AllSuccsHaveSame) {
1156 }
else if (NotAllSeqEqualButKnownSafe) {
1166 bool ObjCARCOpt::VisitInstructionBottomUp(
1168 BBState &MyStates) {
1169 bool NestingDetected =
false;
1206 MyStates.clearBottomUpPointers();
1207 return NestingDetected;
1211 return NestingDetected;
1218 for (
auto MI = MyStates.bottom_up_ptr_begin(),
1219 ME = MyStates.bottom_up_ptr_end();
1232 return NestingDetected;
1235 bool ObjCARCOpt::VisitBottomUp(
BasicBlock *BB,
1240 bool NestingDetected =
false;
1241 BBState &MyStates = BBStates[BB];
1245 BBState::edge_iterator
SI(MyStates.succ_begin()),
1246 SE(MyStates.succ_end());
1251 MyStates.InitFromSucc(I->second);
1253 for (;
SI != SE; ++
SI) {
1255 I = BBStates.
find(Succ);
1257 MyStates.MergeSucc(I->second);
1262 << BBStates[BB] <<
"\n" 1263 <<
"Performing Dataflow:\n");
1270 if (isa<InvokeInst>(Inst))
1275 NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates);
1281 for (BBState::edge_iterator PI(MyStates.pred_begin()),
1282 PE(MyStates.pred_end()); PI != PE; ++PI) {
1285 NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates);
1288 LLVM_DEBUG(
dbgs() <<
"\nFinal State:\n" << BBStates[BB] <<
"\n");
1290 return NestingDetected;
1294 ObjCARCOpt::VisitInstructionTopDown(
Instruction *Inst,
1296 BBState &MyStates) {
1297 bool NestingDetected =
false;
1335 MyStates.clearTopDownPointers();
1347 for (
auto MI = MyStates.top_down_ptr_begin(),
1348 ME = MyStates.top_down_ptr_end();
1360 return NestingDetected;
1368 bool NestingDetected =
false;
1369 BBState &MyStates = BBStates[BB];
1373 BBState::edge_iterator PI(MyStates.pred_begin()),
1374 PE(MyStates.pred_end());
1379 MyStates.InitFromPred(I->second);
1381 for (; PI != PE; ++PI) {
1383 I = BBStates.
find(Pred);
1385 MyStates.MergePred(I->second);
1390 << BBStates[BB] <<
"\n" 1391 <<
"Performing Dataflow:\n");
1397 NestingDetected |= VisitInstructionTopDown(&Inst, Releases, MyStates);
1400 LLVM_DEBUG(
dbgs() <<
"\nState Before Checking for CFG Hazards:\n" 1401 << BBStates[BB] <<
"\n\n");
1402 CheckForCFGHazards(BB, BBStates, MyStates);
1404 return NestingDetected;
1411 unsigned NoObjCARCExceptionsMDKind,
1423 BBState &MyStates = BBStates[EntryBB];
1424 MyStates.SetAsEntry();
1434 while (SuccStack.
back().second != SE) {
1436 if (Visited.
insert(SuccBB).second) {
1439 BBStates[CurrBB].addSucc(SuccBB);
1440 BBState &SuccStates = BBStates[SuccBB];
1441 SuccStates.addPred(CurrBB);
1446 if (!OnStack.
count(SuccBB)) {
1447 BBStates[CurrBB].addSucc(SuccBB);
1448 BBStates[SuccBB].addPred(CurrBB);
1451 OnStack.
erase(CurrBB);
1454 }
while (!SuccStack.
empty());
1463 BBState &MyStates = BBStates[&ExitBB];
1464 if (!MyStates.isExit())
1467 MyStates.SetAsExit();
1469 PredStack.
push_back(std::make_pair(&ExitBB, MyStates.pred_begin()));
1471 while (!PredStack.
empty()) {
1472 reverse_dfs_next_succ:
1473 BBState::edge_iterator PE = BBStates[PredStack.
back().first].pred_end();
1474 while (PredStack.
back().second != PE) {
1476 if (Visited.
insert(BB).second) {
1478 goto reverse_dfs_next_succ;
1487 bool ObjCARCOpt::Visit(
Function &F,
1503 bool BottomUpNestingDetected =
false;
1505 BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains);
1508 bool TopDownNestingDetected =
false;
1510 TopDownNestingDetected |= VisitTopDown(BB, BBStates, Releases);
1512 return TopDownNestingDetected && BottomUpNestingDetected;
1529 Value *MyArg = ArgTy == ParamTy ?
Arg :
1538 "At insertion point: " 1539 << *InsertPt <<
"\n");
1542 Value *MyArg = ArgTy == ParamTy ?
Arg :
1555 "At insertion point: " 1556 << *InsertPt <<
"\n");
1561 Retains.
blot(OrigRetain);
1563 LLVM_DEBUG(
dbgs() <<
"Deleting retain: " << *OrigRetain <<
"\n");
1566 Releases.
erase(OrigRelease);
1568 LLVM_DEBUG(
dbgs() <<
"Deleting release: " << *OrigRelease <<
"\n");
1572 bool ObjCARCOpt::PairUpRetainsAndReleases(
1578 RRInfo &ReleasesToMove,
Value *Arg,
bool KnownSafe,
1579 bool &AnyPairsCompletelyEliminated) {
1583 bool KnownSafeTD =
true, KnownSafeBU =
true;
1584 bool CFGHazardAfflicted =
false;
1590 unsigned OldDelta = 0;
1591 unsigned NewDelta = 0;
1592 unsigned OldCount = 0;
1593 unsigned NewCount = 0;
1594 bool FirstRelease =
true;
1598 auto It = Retains.
find(NewRetain);
1600 const RRInfo &NewRetainRRI = It->second;
1601 KnownSafeTD &= NewRetainRRI.KnownSafe;
1602 CFGHazardAfflicted |= NewRetainRRI.CFGHazardAfflicted;
1603 for (
Instruction *NewRetainRelease : NewRetainRRI.Calls) {
1604 auto Jt = Releases.
find(NewRetainRelease);
1605 if (Jt == Releases.
end())
1607 const RRInfo &NewRetainReleaseRRI = Jt->second;
1614 if (!NewRetainReleaseRRI.
Calls.count(NewRetain))
1617 if (ReleasesToMove.
Calls.insert(NewRetainRelease).second) {
1620 const BBState &NRRBBState = BBStates[NewRetainRelease->
getParent()];
1621 unsigned PathCount = BBState::OverflowOccurredValue;
1622 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1624 assert(PathCount != BBState::OverflowOccurredValue &&
1625 "PathCount at this point can not be " 1626 "OverflowOccurredValue.");
1627 OldDelta -= PathCount;
1635 FirstRelease =
false;
1651 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1652 PathCount = BBState::OverflowOccurredValue;
1653 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1655 assert(PathCount != BBState::OverflowOccurredValue &&
1656 "PathCount at this point can not be " 1657 "OverflowOccurredValue.");
1658 NewDelta -= PathCount;
1661 NewReleases.
push_back(NewRetainRelease);
1666 if (NewReleases.
empty())
break;
1670 auto It = Releases.
find(NewRelease);
1672 const RRInfo &NewReleaseRRI = It->second;
1674 CFGHazardAfflicted |= NewReleaseRRI.CFGHazardAfflicted;
1675 for (
Instruction *NewReleaseRetain : NewReleaseRRI.Calls) {
1676 auto Jt = Retains.
find(NewReleaseRetain);
1677 if (Jt == Retains.
end())
1679 const RRInfo &NewReleaseRetainRRI = Jt->second;
1686 if (!NewReleaseRetainRRI.
Calls.count(NewRelease))
1689 if (RetainsToMove.
Calls.insert(NewReleaseRetain).second) {
1692 const BBState &NRRBBState = BBStates[NewReleaseRetain->
getParent()];
1693 unsigned PathCount = BBState::OverflowOccurredValue;
1694 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1696 assert(PathCount != BBState::OverflowOccurredValue &&
1697 "PathCount at this point can not be " 1698 "OverflowOccurredValue.");
1699 OldDelta += PathCount;
1700 OldCount += PathCount;
1708 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1710 PathCount = BBState::OverflowOccurredValue;
1711 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1713 assert(PathCount != BBState::OverflowOccurredValue &&
1714 "PathCount at this point can not be " 1715 "OverflowOccurredValue.");
1716 NewDelta += PathCount;
1717 NewCount += PathCount;
1720 NewRetains.push_back(NewReleaseRetain);
1724 if (NewRetains.empty())
break;
1728 bool UnconditionallySafe = KnownSafeTD && KnownSafeBU;
1729 if (UnconditionallySafe) {
1744 const bool WillPerformCodeMotion =
1747 if (CFGHazardAfflicted && WillPerformCodeMotion)
1760 assert(OldCount != 0 &&
"Unreachable code?");
1761 NumRRs += OldCount - NewCount;
1763 AnyPairsCompletelyEliminated = NewCount == 0;
1771 bool ObjCARCOpt::PerformCodePlacement(
1775 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::PerformCodePlacement ==\n");
1777 bool AnyPairsCompletelyEliminated =
false;
1796 bool KnownSafe = isa<Constant>(
Arg) || isa<AllocaInst>(Arg);
1800 if (
const LoadInst *LI = dyn_cast<LoadInst>(Arg))
1802 dyn_cast<GlobalVariable>(
1804 if (GV->isConstant())
1809 RRInfo RetainsToMove, ReleasesToMove;
1811 bool PerformMoveCalls = PairUpRetainsAndReleases(
1812 BBStates, Retains, Releases, M, Retain, DeadInsts,
1813 RetainsToMove, ReleasesToMove, Arg, KnownSafe,
1814 AnyPairsCompletelyEliminated);
1816 if (PerformMoveCalls) {
1819 MoveCalls(Arg, RetainsToMove, ReleasesToMove,
1820 Retains, Releases, DeadInsts, M);
1826 while (!DeadInsts.
empty())
1829 return AnyPairsCompletelyEliminated;
1833 void ObjCARCOpt::OptimizeWeakCalls(
Function &F) {
1866 switch (EarlierClass) {
1872 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
1874 Value *EarlierArg = EarlierCall->getArgOperand(0);
1875 switch (PA.getAA()->alias(Arg, EarlierArg)) {
1901 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
1903 Value *EarlierArg = EarlierCall->getArgOperand(0);
1904 switch (PA.getAA()->alias(Arg, EarlierArg)) {
1954 if (
AllocaInst *Alloca = dyn_cast<AllocaInst>(Arg)) {
1956 const Instruction *UserInst = cast<Instruction>(U);
1967 for (
auto UI = Alloca->user_begin(), UE = Alloca->user_end(); UI != UE;) {
1968 CallInst *UserInst = cast<CallInst>(*UI++);
1983 Alloca->eraseFromParent();
1991 bool ObjCARCOpt::OptimizeSequences(
Function &F) {
2004 bool NestingDetected = Visit(F, BBStates, Retains, Releases);
2007 bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
2011 return AnyPairsCompletelyEliminated && NestingDetected;
2023 DepInsts, Visited, PA);
2024 if (DepInsts.size() != 1)
2027 auto *
Call = dyn_cast_or_null<CallInst>(*DepInsts.begin());
2048 BB, Autorelease, DepInsts, Visited, PA);
2049 if (DepInsts.
size() != 1)
2052 auto *Retain = dyn_cast_or_null<CallInst>(*DepInsts.
begin());
2073 BB, Ret, DepInsts, V, PA);
2074 if (DepInsts.
size() != 1)
2097 void ObjCARCOpt::OptimizeReturns(
Function &F) {
2118 Arg, &BB, Ret, DependingInstructions, Visited, PA);
2119 DependingInstructions.
clear();
2126 Arg, Autorelease->getParent(),
Autorelease, DependingInstructions,
2128 DependingInstructions.clear();
2137 DependingInstructions,
2139 DependingInstructions.clear();
2142 if (!HasSafePathToCall)
2148 LLVM_DEBUG(
dbgs() <<
"Erasing: " << *Retain <<
"\nErasing: " << *Autorelease
2157 ObjCARCOpt::GatherStatistics(
Function &F,
bool AfterOptimization) {
2159 AfterOptimization ? NumRetainsAfterOpt : NumRetainsBeforeOpt;
2161 AfterOptimization ? NumReleasesAfterOpt : NumReleasesBeforeOpt;
2179 bool ObjCARCOpt::doInitialization(
Module &M) {
2191 MDKindCache.init(&M);
2213 PA.setAA(&getAnalysis<AAResultsWrapperPass>().getAAResults());
2217 GatherStatistics(F,
false);
2226 OptimizeIndividualCalls(F);
2236 OptimizeWeakCalls(F);
2245 while (OptimizeSequences(F)) {}
2255 GatherStatistics(F,
true);
2264 void ObjCARCOpt::releaseMemory() {
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.
This file declares special dependency analysis routines used in Objective C ARC Optimizations.
ARCInstKind GetARCInstKind(const Value *V)
Map V to its ARCInstKind equivalence class.
objc_destroyWeak (derived)
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.
This file contains a class ARCRuntimeEntryPoints for use in creating/managing references to entry poi...
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. ...
bool IsTrackingImpreciseReleases() 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)
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...
The two locations do not alias at all.
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)
void initializeObjCARCOptPass(PassRegistry &)
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.
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()
#define INITIALIZE_PASS_DEPENDENCY(depName)
bool HasKnownPositiveRefCount() const
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...
void setCalledFunction(Value *Fn)
Sets the function called, including updating the function type.
InstrTy * getInstruction() const
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, catchpad/ret, and cleanuppad/ret.
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...
auto reverse(ContainerTy &&C, typename std::enable_if< has_rbegin< ContainerTy >::value >::type *=nullptr) -> decltype(make_range(C.rbegin(), C.rend()))
objc_retainAutoreleasedReturnValue
Type * getType() const
All values are typed, get the type of this value.
static bool setDoesNotThrow(Function &F)
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.
bool hasPersonalityFn() const
Check whether this function has a personality function.
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)
const BasicBlock & getEntryBlock() const
an instruction for type-safe pointer arithmetic to access elements of arrays and structs ...
iterator find(const KeyT &Key)
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata *> MDs)
static bool runOnFunction(Function &F, bool PostInlining)
bool erase(const KeyT &Val)
Type * getReturnType() const
Returns the type of the ret val.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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 is an important base class in LLVM.
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator begin()
This file contains the declarations for the subclasses of Constant, which represent the different fla...
bool isPointerTy() const
True if this is an instance of PointerType.
BIty & getInstructionIterator()
std::pair< iterator, bool > insert(const ValueT &V)
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
FunctionPass class - This class is used to implement most global optimizations.
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.
self_iterator getIterator()
A cache of MDKinds used by various ARC optimizations.
static CallInst * FindPredecessorAutoreleaseWithSafePath(const Value *Arg, BasicBlock *BB, ReturnInst *Ret, SmallPtrSetImpl< Instruction *> &DepInsts, SmallPtrSetImpl< const BasicBlock *> &V, ProvenanceAnalysis &PA)
Look for an ``autorelease'' instruction dependent on Arg such that there are no instructions dependen...
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...
void setTailCall(bool isTC=true)
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
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.
bool IsCFGHazardAfflicted() const
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 PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the generic address space (address sp...
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.
Implements a dense probed hash-table based set with some number of buckets stored inline...
MDNode * ReleaseMetadata
If the Calls are objc_release calls and they all have a clang.imprecise_release tag, this is the metadata tag.
Pass * createObjCARCOptPass()
void FindDependencies(DependenceKind Flavor, const Value *Arg, BasicBlock *StartBB, Instruction *StartInst, SmallPtrSetImpl< Instruction *> &DependingInstructions, SmallPtrSetImpl< const BasicBlock *> &Visited, ProvenanceAnalysis &PA)
Walk up the CFG from StartPos (which is in StartBB) and find local and non-local dependencies on Arg...
iterator_range< user_iterator > users()
amdgpu Simplify well known AMD library false Value Value * Arg
void ClearSequenceProgress()
bool IsRetain(ARCInstKind Class)
Test if the given class is objc_retain or equivalent.
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
static bool HasSafePathToPredecessorCall(const Value *Arg, Instruction *Retain, SmallPtrSetImpl< Instruction *> &DepInsts, SmallPtrSetImpl< const BasicBlock *> &Visited, ProvenanceAnalysis &PA)
Check if there is a dependent call earlier that does not have anything in between the Retain and the ...
LLVM_ATTRIBUTE_ALWAYS_INLINE iterator end()
SuccIterator< Instruction, BasicBlock > succ_iterator
const RRInfo & GetRRInfo() const
void emplace_back(ArgTypes &&... Args)
LLVM_NODISCARD bool empty() const
StringRef getName() const
Return a constant reference to the value's name.
Establish a view to a call site for examination.
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...
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
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)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
raw_ostream & operator<<(raw_ostream &OS, const APInt &I)
LLVM_NODISCARD bool empty() const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
INITIALIZE_PASS_BEGIN(ObjCARCOpt, "objc-arc", "ObjC ARC optimization", false, false) INITIALIZE_PASS_END(ObjCARCOpt
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
Constant * getPersonalityFn() const
Get the personality function associated with this function.
foo(x) – x could possibly see a ref count decrement.
Legacy wrapper pass to provide the ObjCARCAAResult object.
succ_range successors(Instruction *I)
static void ComputePostOrders(Function &F, SmallVectorImpl< BasicBlock *> &PostOrder, SmallVectorImpl< BasicBlock *> &ReverseCFGPostOrder, unsigned NoObjCARCExceptionsMDKind, DenseMap< const BasicBlock *, BBState > &BBStates)
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...
bool hasOneUse() const
Return true if there is exactly one user of this value.
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)
static CallInst * FindPredecessorRetainWithSafePath(const Value *Arg, BasicBlock *BB, Instruction *Autorelease, SmallPtrSetImpl< Instruction *> &DepInsts, SmallPtrSetImpl< const BasicBlock *> &Visited, ProvenanceAnalysis &PA)
Find a dependent retain that precedes the given autorelease for which there is nothing in between the...
#define LLVM_ATTRIBUTE_UNUSED
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object...
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...
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
bool IsAutorelease(ARCInstKind Class)
Test if the given class is objc_autorelease or equivalent.