46 using namespace llvm::objcarc;
48 #define DEBUG_TYPE "objc-arc-opts"
58 if (isa<ConstantData>(Arg))
62 if (
const BitCastInst *BC = dyn_cast<BitCastInst>(Arg))
65 if (
GEP->hasAllZeroIndices())
69 cast<CallInst>(Arg)->getArgOperand(0));
100 if (isa<AllocaInst>(P))
103 if (!Visited.
insert(P).second)
106 if (
const SelectInst *
SI = dyn_cast<const SelectInst>(P)) {
112 if (
const PHINode *PN = dyn_cast<const PHINode>(P)) {
113 for (
Value *IncValue : PN->incoming_values())
117 }
while (!Worklist.
empty());
166 STATISTIC(NumNoops,
"Number of no-op objc calls eliminated");
167 STATISTIC(NumPartialNoops,
"Number of partially no-op objc calls eliminated");
168 STATISTIC(NumAutoreleases,
"Number of autoreleases converted to releases");
169 STATISTIC(NumRets,
"Number of return value forwarding "
170 "retain+autoreleases eliminated");
171 STATISTIC(NumRRs,
"Number of retain+release paths eliminated");
172 STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
175 "Number of retains before optimization");
177 "Number of releases before optimization");
179 "Number of retains after optimization");
181 "Number of releases after optimization");
189 unsigned TopDownPathCount;
192 unsigned BottomUpPathCount;
211 static const unsigned OverflowOccurredValue;
213 BBState() : TopDownPathCount(0), BottomUpPathCount(0) { }
215 typedef decltype(PerPtrTopDown)::iterator top_down_ptr_iterator;
216 typedef decltype(PerPtrTopDown)::const_iterator const_top_down_ptr_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 typedef decltype(PerPtrBottomUp)::iterator bottom_up_ptr_iterator;
232 PerPtrBottomUp)::const_iterator const_bottom_up_ptr_iterator;
234 bottom_up_ptr_iterator bottom_up_ptr_begin() {
235 return PerPtrBottomUp.begin();
237 bottom_up_ptr_iterator bottom_up_ptr_end() {
return PerPtrBottomUp.end(); }
238 const_bottom_up_ptr_iterator bottom_up_ptr_begin()
const {
239 return PerPtrBottomUp.begin();
241 const_bottom_up_ptr_iterator bottom_up_ptr_end()
const {
242 return PerPtrBottomUp.end();
244 bool hasBottomUpPtrs()
const {
245 return !PerPtrBottomUp.empty();
250 void SetAsEntry() { TopDownPathCount = 1; }
254 void SetAsExit() { BottomUpPathCount = 1; }
260 return PerPtrTopDown[Arg];
267 return PerPtrBottomUp[Arg];
272 bottom_up_ptr_iterator findPtrBottomUpState(
const Value *Arg) {
273 return PerPtrBottomUp.find(Arg);
276 void clearBottomUpPointers() {
277 PerPtrBottomUp.clear();
280 void clearTopDownPointers() {
281 PerPtrTopDown.clear();
284 void InitFromPred(
const BBState &Other);
285 void InitFromSucc(
const BBState &Other);
286 void MergePred(
const BBState &Other);
287 void MergeSucc(
const BBState &Other);
295 bool GetAllPathCountWithOverflow(
unsigned &PathCount)
const {
296 if (TopDownPathCount == OverflowOccurredValue ||
297 BottomUpPathCount == OverflowOccurredValue)
299 unsigned long long Product =
300 (
unsigned long long)TopDownPathCount*BottomUpPathCount;
303 return (Product >> 32) ||
304 ((PathCount = Product) == OverflowOccurredValue);
309 edge_iterator
pred_begin()
const {
return Preds.begin(); }
310 edge_iterator
pred_end()
const {
return Preds.end(); }
311 edge_iterator
succ_begin()
const {
return Succs.begin(); }
312 edge_iterator
succ_end()
const {
return Succs.end(); }
314 void addSucc(
BasicBlock *Succ) { Succs.push_back(Succ); }
315 void addPred(
BasicBlock *Pred) { Preds.push_back(Pred); }
317 bool isExit()
const {
return Succs.empty(); }
320 const unsigned BBState::OverflowOccurredValue = 0xffffffff;
328 void BBState::InitFromPred(
const BBState &Other) {
329 PerPtrTopDown = Other.PerPtrTopDown;
330 TopDownPathCount = Other.TopDownPathCount;
333 void BBState::InitFromSucc(
const BBState &Other) {
334 PerPtrBottomUp = Other.PerPtrBottomUp;
335 BottomUpPathCount = Other.BottomUpPathCount;
340 void BBState::MergePred(
const BBState &Other) {
341 if (TopDownPathCount == OverflowOccurredValue)
346 TopDownPathCount += Other.TopDownPathCount;
351 if (TopDownPathCount == OverflowOccurredValue) {
352 clearTopDownPointers();
358 if (TopDownPathCount < Other.TopDownPathCount) {
359 TopDownPathCount = OverflowOccurredValue;
360 clearTopDownPointers();
367 for (
auto MI = Other.top_down_ptr_begin(), ME = Other.top_down_ptr_end();
369 auto Pair = PerPtrTopDown.insert(*
MI);
376 for (
auto MI = top_down_ptr_begin(), ME = top_down_ptr_end();
MI != ME; ++
MI)
377 if (Other.PerPtrTopDown.find(
MI->first) == Other.PerPtrTopDown.end())
383 void BBState::MergeSucc(
const BBState &Other) {
384 if (BottomUpPathCount == OverflowOccurredValue)
389 BottomUpPathCount += Other.BottomUpPathCount;
394 if (BottomUpPathCount == OverflowOccurredValue) {
395 clearBottomUpPointers();
401 if (BottomUpPathCount < Other.BottomUpPathCount) {
402 BottomUpPathCount = OverflowOccurredValue;
403 clearBottomUpPointers();
410 for (
auto MI = Other.bottom_up_ptr_begin(), ME = Other.bottom_up_ptr_end();
412 auto Pair = PerPtrBottomUp.insert(*
MI);
419 for (
auto MI = bottom_up_ptr_begin(), ME = bottom_up_ptr_end();
MI != ME;
421 if (Other.PerPtrBottomUp.find(
MI->first) == Other.PerPtrBottomUp.end())
427 OS <<
" TopDown State:\n";
428 if (!BBInfo.hasTopDownPtrs()) {
431 for (
auto I = BBInfo.top_down_ptr_begin(),
E = BBInfo.top_down_ptr_end();
434 OS <<
" Ptr: " << *
I->first
435 <<
"\n KnownSafe: " << (P.
IsKnownSafe()?
"true":
"false")
436 <<
"\n ImpreciseRelease: "
438 <<
" HasCFGHazards: "
440 <<
" KnownPositive: "
447 OS <<
" BottomUp State:\n";
448 if (!BBInfo.hasBottomUpPtrs()) {
451 for (
auto I = BBInfo.bottom_up_ptr_begin(),
E = BBInfo.bottom_up_ptr_end();
454 OS <<
" Ptr: " << *
I->first
455 <<
"\n KnownSafe: " << (P.
IsKnownSafe()?
"true":
"false")
456 <<
"\n ImpreciseRelease: "
458 <<
" HasCFGHazards: "
460 <<
" KnownPositive: "
492 unsigned UsedInThisFunction;
497 void OptimizeIndividualCalls(
Function &
F);
501 BBState &MyStates)
const;
531 Value *Arg,
bool KnownSafe,
532 bool &AnyPairsCompletelyEliminated);
545 void GatherStatistics(
Function &
F,
bool AfterOptimization =
false);
549 bool doInitialization(
Module &M)
override;
550 bool runOnFunction(
Function &
F)
override;
551 void releaseMemory()
override;
563 "objc-arc",
"ObjC ARC optimization",
false,
false)
569 return new ObjCARCOpt();
595 }
else if (
const InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
597 if (II->getNormalDest() == RetainRVParent) {
620 DEBUG(
dbgs() <<
"Erasing autoreleaseRV,retainRV pair: " << *I <<
"\n"
621 <<
"Erasing " << *RetainRV <<
"\n");
633 DEBUG(
dbgs() <<
"Transforming objc_retainAutoreleasedReturnValue => "
634 "objc_retain since the operand is not a return value.\n"
635 "Old = " << *RetainRV <<
"\n");
638 cast<CallInst>(RetainRV)->setCalledFunction(NewDecl);
640 DEBUG(
dbgs() <<
"New = " << *RetainRV <<
"\n");
647 void ObjCARCOpt::OptimizeAutoreleaseRVCall(
Function &F,
655 if (isa<ConstantData>(Ptr))
665 if (isa<BitCastInst>(U))
668 }
while (!Users.
empty());
673 DEBUG(
dbgs() <<
"Transforming objc_autoreleaseReturnValue => "
674 "objc_autorelease since its operand is not used as a return "
676 "Old = " << *AutoreleaseRV <<
"\n");
678 CallInst *AutoreleaseRVCI = cast<CallInst>(AutoreleaseRV);
684 DEBUG(
dbgs() <<
"New: " << *AutoreleaseRV <<
"\n");
690 void ObjCARCOpt::OptimizeIndividualCalls(
Function &F) {
691 DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeIndividualCalls ==\n");
693 UsedInThisFunction = 0;
701 DEBUG(
dbgs() <<
"Visiting: Class: " << Class <<
"; " << *Inst <<
"\n");
717 DEBUG(
dbgs() <<
"Erasing no-op cast: " << *Inst <<
"\n");
727 CallInst *CI = cast<CallInst>(Inst);
735 DEBUG(
dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
736 "\nOld = " << *CI <<
"\nNew = " << *NewValue <<
"\n");
745 CallInst *CI = cast<CallInst>(Inst);
755 DEBUG(
dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
756 "\nOld = " << *CI <<
"\nNew = " << *NewValue <<
"\n");
765 if (OptimizeRetainRVCall(F, Inst))
769 OptimizeAutoreleaseRVCall(F, Inst, Class);
791 DEBUG(
dbgs() <<
"Replacing autorelease{,RV}(x) with objc_release(x) "
792 "since x is otherwise unused.\nOld: " << *Call <<
"\nNew: "
793 << *NewCall <<
"\n");
805 DEBUG(
dbgs() <<
"Adding tail keyword to function since it can never be "
806 "passed stack args: " << *Inst <<
"\n");
807 cast<CallInst>(Inst)->setTailCall();
814 DEBUG(
dbgs() <<
"Removing tail keyword from function: " << *Inst <<
816 cast<CallInst>(Inst)->setTailCall(
false);
822 DEBUG(
dbgs() <<
"Found no throw class. Setting nounwind on: " << *Inst
828 UsedInThisFunction |= 1 <<
unsigned(Class);
838 DEBUG(
dbgs() <<
"ARC calls with null are no-ops. Erasing: " << *Inst
846 UsedInThisFunction |= 1 <<
unsigned(Class);
854 Worklist.
push_back(std::make_pair(Inst, Arg));
856 std::pair<Instruction *, const Value *> Pair = Worklist.
pop_back_val();
865 bool HasNull =
false;
866 bool HasCriticalEdges =
false;
873 .getNumSuccessors() != 1) {
874 HasCriticalEdges =
true;
879 if (!HasCriticalEdges && HasNull) {
895 DependingInstructions, Visited, PA);
901 DependingInstructions, Visited, PA);
915 if (DependingInstructions.size() == 1 &&
916 *DependingInstructions.begin() == PN) {
920 CallInst *CInst = cast<CallInst>(Inst);
929 if (Op->getType() != ParamTy)
936 "And inserting clone at " << *InsertPos <<
"\n");
937 Worklist.
push_back(std::make_pair(Clone, Incoming));
941 DEBUG(
dbgs() <<
"Erasing: " << *CInst <<
"\n");
946 }
while (!Worklist.
empty());
953 const bool SuccSRRIKnownSafe,
955 bool &SomeSuccHasSame,
956 bool &AllSuccsHaveSame,
957 bool &NotAllSeqEqualButKnownSafe,
958 bool &ShouldContinue) {
966 ShouldContinue =
true;
970 SomeSuccHasSame =
true;
976 AllSuccsHaveSame =
false;
978 NotAllSeqEqualButKnownSafe =
true;
991 const bool SuccSRRIKnownSafe,
993 bool &SomeSuccHasSame,
994 bool &AllSuccsHaveSame,
995 bool &NotAllSeqEqualButKnownSafe) {
998 SomeSuccHasSame =
true;
1005 AllSuccsHaveSame =
false;
1007 NotAllSeqEqualButKnownSafe =
true;
1020 ObjCARCOpt::CheckForCFGHazards(
const BasicBlock *BB,
1022 BBState &MyStates)
const {
1025 for (
auto I = MyStates.top_down_ptr_begin(),
E = MyStates.top_down_ptr_end();
1028 const Sequence Seq = I->second.GetSeq();
1037 "Unknown top down sequence state.");
1039 const Value *Arg = I->first;
1041 bool SomeSuccHasSame =
false;
1042 bool AllSuccsHaveSame =
true;
1043 bool NotAllSeqEqualButKnownSafe =
false;
1047 for (;
SI != SE; ++
SI) {
1054 const Sequence SuccSSeq = SuccS.GetSeq();
1061 if (SuccSSeq ==
S_None) {
1068 const bool SuccSRRIKnownSafe = SuccS.IsKnownSafe();
1074 bool ShouldContinue =
false;
1076 AllSuccsHaveSame, NotAllSeqEqualButKnownSafe,
1084 SomeSuccHasSame, AllSuccsHaveSame,
1085 NotAllSeqEqualButKnownSafe);
1100 if (SomeSuccHasSame && !AllSuccsHaveSame) {
1102 }
else if (NotAllSeqEqualButKnownSafe) {
1112 bool ObjCARCOpt::VisitInstructionBottomUp(
1114 BBState &MyStates) {
1115 bool NestingDetected =
false;
1117 const Value *Arg =
nullptr;
1119 DEBUG(
dbgs() <<
" Class: " << Class <<
"\n");
1152 MyStates.clearBottomUpPointers();
1153 return NestingDetected;
1157 return NestingDetected;
1171 if (
StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
1174 auto I = MyStates.findPtrBottomUpState(
1176 if (I != MyStates.bottom_up_ptr_end())
1177 MultiOwnersSet.insert(I->first);
1187 for (
auto MI = MyStates.bottom_up_ptr_begin(),
1188 ME = MyStates.bottom_up_ptr_end();
1201 return NestingDetected;
1204 bool ObjCARCOpt::VisitBottomUp(
BasicBlock *BB,
1208 DEBUG(
dbgs() <<
"\n== ObjCARCOpt::VisitBottomUp ==\n");
1210 bool NestingDetected =
false;
1211 BBState &MyStates = BBStates[BB];
1216 SE(MyStates.succ_end());
1221 MyStates.InitFromSucc(I->second);
1223 for (;
SI != SE; ++
SI) {
1225 I = BBStates.
find(Succ);
1227 MyStates.MergeSucc(I->second);
1232 <<
"Performing Dataflow:\n");
1239 if (isa<InvokeInst>(Inst))
1242 DEBUG(
dbgs() <<
" Visiting " << *Inst <<
"\n");
1244 NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates);
1251 PE(MyStates.pred_end()); PI != PE; ++PI) {
1254 NestingDetected |= VisitInstructionBottomUp(II, BB, Retains, MyStates);
1259 return NestingDetected;
1263 ObjCARCOpt::VisitInstructionTopDown(
Instruction *Inst,
1265 BBState &MyStates) {
1266 bool NestingDetected =
false;
1268 const Value *Arg =
nullptr;
1304 MyStates.clearTopDownPointers();
1316 for (
auto MI = MyStates.top_down_ptr_begin(),
1317 ME = MyStates.top_down_ptr_end();
1329 return NestingDetected;
1336 DEBUG(
dbgs() <<
"\n== ObjCARCOpt::VisitTopDown ==\n");
1337 bool NestingDetected =
false;
1338 BBState &MyStates = BBStates[BB];
1343 PE(MyStates.pred_end());
1348 MyStates.InitFromPred(I->second);
1350 for (; PI != PE; ++PI) {
1352 I = BBStates.
find(Pred);
1354 MyStates.MergePred(I->second);
1359 <<
"Performing Dataflow:\n");
1363 DEBUG(
dbgs() <<
" Visiting " << Inst <<
"\n");
1365 NestingDetected |= VisitInstructionTopDown(&Inst, Releases, MyStates);
1369 << BBStates[BB] <<
"\n\n");
1370 CheckForCFGHazards(BB, BBStates, MyStates);
1372 return NestingDetected;
1379 unsigned NoObjCARCExceptionsMDKind,
1391 BBState &MyStates = BBStates[EntryBB];
1392 MyStates.SetAsEntry();
1403 while (SuccStack.
back().second != SE) {
1405 if (Visited.
insert(SuccBB).second) {
1408 BBStates[CurrBB].addSucc(SuccBB);
1409 BBState &SuccStates = BBStates[SuccBB];
1410 SuccStates.addPred(CurrBB);
1415 if (!OnStack.
count(SuccBB)) {
1416 BBStates[CurrBB].addSucc(SuccBB);
1417 BBStates[SuccBB].addPred(CurrBB);
1420 OnStack.
erase(CurrBB);
1423 }
while (!SuccStack.
empty());
1432 BBState &MyStates = BBStates[&ExitBB];
1433 if (!MyStates.isExit())
1436 MyStates.SetAsExit();
1438 PredStack.
push_back(std::make_pair(&ExitBB, MyStates.pred_begin()));
1440 while (!PredStack.
empty()) {
1441 reverse_dfs_next_succ:
1443 while (PredStack.
back().second != PE) {
1445 if (Visited.
insert(BB).second) {
1447 goto reverse_dfs_next_succ;
1456 bool ObjCARCOpt::Visit(
Function &F,
1473 bool BottomUpNestingDetected =
false;
1475 BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains);
1478 bool TopDownNestingDetected =
false;
1480 TopDownNestingDetected |= VisitTopDown(BB, BBStates, Releases);
1482 return TopDownNestingDetected && BottomUpNestingDetected;
1486 void ObjCARCOpt::MoveCalls(
Value *Arg,
RRInfo &RetainsToMove,
1495 DEBUG(
dbgs() <<
"== ObjCARCOpt::MoveCalls ==\n");
1499 Value *MyArg = ArgTy == ParamTy ? Arg :
1506 DEBUG(
dbgs() <<
"Inserting new Retain: " << *Call <<
"\n"
1507 "At insertion point: " << *InsertPt <<
"\n");
1510 Value *MyArg = ArgTy == ParamTy ? Arg :
1521 DEBUG(
dbgs() <<
"Inserting new Release: " << *Call <<
"\n"
1522 "At insertion point: " << *InsertPt <<
"\n");
1527 Retains.
blot(OrigRetain);
1529 DEBUG(
dbgs() <<
"Deleting retain: " << *OrigRetain <<
"\n");
1532 Releases.
erase(OrigRelease);
1534 DEBUG(
dbgs() <<
"Deleting release: " << *OrigRelease <<
"\n");
1539 bool ObjCARCOpt::PairUpRetainsAndReleases(
1546 RRInfo &ReleasesToMove,
Value *Arg,
bool KnownSafe,
1547 bool &AnyPairsCompletelyEliminated) {
1551 bool KnownSafeTD =
true, KnownSafeBU =
true;
1552 bool MultipleOwners =
false;
1553 bool CFGHazardAfflicted =
false;
1559 unsigned OldDelta = 0;
1560 unsigned NewDelta = 0;
1561 unsigned OldCount = 0;
1562 unsigned NewCount = 0;
1563 bool FirstRelease =
true;
1566 auto It = Retains.
find(NewRetain);
1568 const RRInfo &NewRetainRRI = It->second;
1569 KnownSafeTD &= NewRetainRRI.KnownSafe;
1572 for (
Instruction *NewRetainRelease : NewRetainRRI.Calls) {
1573 auto Jt = Releases.
find(NewRetainRelease);
1574 if (Jt == Releases.
end())
1576 const RRInfo &NewRetainReleaseRRI = Jt->second;
1583 if (!NewRetainReleaseRRI.
Calls.count(NewRetain))
1586 if (ReleasesToMove.
Calls.insert(NewRetainRelease).second) {
1590 const BBState &NRRBBState = BBStates[NewRetainRelease->
getParent()];
1591 unsigned PathCount = BBState::OverflowOccurredValue;
1592 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1594 assert(PathCount != BBState::OverflowOccurredValue &&
1595 "PathCount at this point can not be "
1596 "OverflowOccurredValue.");
1597 OldDelta -= PathCount;
1605 FirstRelease =
false;
1621 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1622 PathCount = BBState::OverflowOccurredValue;
1623 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1625 assert(PathCount != BBState::OverflowOccurredValue &&
1626 "PathCount at this point can not be "
1627 "OverflowOccurredValue.");
1628 NewDelta -= PathCount;
1631 NewReleases.
push_back(NewRetainRelease);
1636 if (NewReleases.
empty())
break;
1640 auto It = Releases.
find(NewRelease);
1642 const RRInfo &NewReleaseRRI = It->second;
1644 CFGHazardAfflicted |= NewReleaseRRI.CFGHazardAfflicted;
1645 for (
Instruction *NewReleaseRetain : NewReleaseRRI.Calls) {
1646 auto Jt = Retains.
find(NewReleaseRetain);
1647 if (Jt == Retains.
end())
1649 const RRInfo &NewReleaseRetainRRI = Jt->second;
1656 if (!NewReleaseRetainRRI.
Calls.count(NewRelease))
1659 if (RetainsToMove.
Calls.insert(NewReleaseRetain).second) {
1662 const BBState &NRRBBState = BBStates[NewReleaseRetain->
getParent()];
1663 unsigned PathCount = BBState::OverflowOccurredValue;
1664 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1666 assert(PathCount != BBState::OverflowOccurredValue &&
1667 "PathCount at this point can not be "
1668 "OverflowOccurredValue.");
1669 OldDelta += PathCount;
1670 OldCount += PathCount;
1678 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1680 PathCount = BBState::OverflowOccurredValue;
1681 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1683 assert(PathCount != BBState::OverflowOccurredValue &&
1684 "PathCount at this point can not be "
1685 "OverflowOccurredValue.");
1686 NewDelta += PathCount;
1687 NewCount += PathCount;
1690 NewRetains.push_back(NewReleaseRetain);
1694 NewReleases.clear();
1695 if (NewRetains.empty())
break;
1699 bool UnconditionallySafe = KnownSafeTD && KnownSafeBU;
1700 if (UnconditionallySafe) {
1715 const bool WillPerformCodeMotion = RetainsToMove.
ReverseInsertPts.size() ||
1717 if (CFGHazardAfflicted && WillPerformCodeMotion)
1730 assert(OldCount != 0 &&
"Unreachable code?");
1731 NumRRs += OldCount - NewCount;
1733 AnyPairsCompletelyEliminated = NewCount == 0;
1741 bool ObjCARCOpt::PerformCodePlacement(
1745 DEBUG(
dbgs() <<
"\n== ObjCARCOpt::PerformCodePlacement ==\n");
1747 bool AnyPairsCompletelyEliminated =
false;
1758 Value *V = I->first;
1763 DEBUG(
dbgs() <<
"Visiting: " << *Retain <<
"\n");
1770 bool KnownSafe = isa<Constant>(Arg) || isa<AllocaInst>(Arg);
1774 if (
const LoadInst *LI = dyn_cast<LoadInst>(Arg))
1776 dyn_cast<GlobalVariable>(
1778 if (GV->isConstant())
1784 bool PerformMoveCalls = PairUpRetainsAndReleases(
1785 BBStates, Retains, Releases, M, NewRetains, NewReleases, DeadInsts,
1786 RetainsToMove, ReleasesToMove, Arg, KnownSafe,
1787 AnyPairsCompletelyEliminated);
1789 if (PerformMoveCalls) {
1792 MoveCalls(Arg, RetainsToMove, ReleasesToMove,
1793 Retains, Releases, DeadInsts, M);
1797 NewReleases.
clear();
1799 RetainsToMove.
clear();
1800 ReleasesToMove.
clear();
1805 while (!DeadInsts.
empty())
1808 return AnyPairsCompletelyEliminated;
1812 void ObjCARCOpt::OptimizeWeakCalls(
Function &F) {
1813 DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeWeakCalls ==\n");
1821 DEBUG(
dbgs() <<
"Visiting: " << *Inst <<
"\n");
1845 switch (EarlierClass) {
1850 CallInst *Call = cast<CallInst>(Inst);
1851 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
1853 Value *EarlierArg = EarlierCall->getArgOperand(0);
1854 switch (PA.getAA()->alias(Arg, EarlierArg)) {
1879 CallInst *Call = cast<CallInst>(Inst);
1880 CallInst *EarlierCall = cast<CallInst>(EarlierInst);
1882 Value *EarlierArg = EarlierCall->getArgOperand(0);
1883 switch (PA.getAA()->alias(Arg, EarlierArg)) {
1931 CallInst *Call = cast<CallInst>(Inst);
1933 if (
AllocaInst *Alloca = dyn_cast<AllocaInst>(Arg)) {
1935 const Instruction *UserInst = cast<Instruction>(U);
1946 for (
auto UI = Alloca->user_begin(), UE = Alloca->user_end(); UI != UE;) {
1947 CallInst *UserInst = cast<CallInst>(*UI++);
1962 Alloca->eraseFromParent();
1970 bool ObjCARCOpt::OptimizeSequences(
Function &F) {
1983 bool NestingDetected = Visit(F, BBStates, Retains, Releases);
1986 bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
1991 MultiOwnersSet.clear();
1993 return AnyPairsCompletelyEliminated && NestingDetected;
2005 DepInsts, Visited, PA);
2006 if (DepInsts.size() != 1)
2009 auto *Call = dyn_cast_or_null<CallInst>(*DepInsts.begin());
2012 if (!Call || Arg != Call)
2030 BB, Autorelease, DepInsts, Visited, PA);
2031 if (DepInsts.
size() != 1)
2034 auto *Retain = dyn_cast_or_null<CallInst>(*DepInsts.
begin());
2055 BB, Ret, DepInsts, V, PA);
2056 if (DepInsts.
size() != 1)
2079 void ObjCARCOpt::OptimizeReturns(
Function &F) {
2083 DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeReturns ==\n");
2092 DEBUG(
dbgs() <<
"Visiting: " << *Ret <<
"\n");
2100 Arg, &BB, Ret, DependingInstructions, Visited, PA);
2101 DependingInstructions.
clear();
2108 Arg, &BB, Autorelease, DependingInstructions, Visited, PA);
2109 DependingInstructions.
clear();
2118 DependingInstructions,
2120 DependingInstructions.
clear();
2123 if (!HasSafePathToCall)
2129 DEBUG(
dbgs() <<
"Erasing: " << *Retain <<
"\nErasing: "
2130 << *Autorelease <<
"\n");
2138 ObjCARCOpt::GatherStatistics(
Function &F,
bool AfterOptimization) {
2140 AfterOptimization? NumRetainsAfterOpt : NumRetainsBeforeOpt;
2142 AfterOptimization? NumReleasesAfterOpt : NumReleasesBeforeOpt;
2160 bool ObjCARCOpt::doInitialization(
Module &M) {
2172 MDKindCache.init(&M);
2180 bool ObjCARCOpt::runOnFunction(
Function &F) {
2190 DEBUG(
dbgs() <<
"<<< ObjCARCOpt: Visiting Function: " << F.
getName() <<
" >>>"
2193 PA.setAA(&getAnalysis<AAResultsWrapperPass>().getAAResults());
2197 GatherStatistics(F,
false);
2206 OptimizeIndividualCalls(F);
2216 OptimizeWeakCalls(F);
2225 while (OptimizeSequences(F)) {}
2235 GatherStatistics(F,
true);
2244 void ObjCARCOpt::releaseMemory() {
Pass interface - Implemented by all 'passes'.
The two locations precisely alias each other.
Return a value (possibly void), from a function.
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
void push_back(const T &Elt)
A parsed version of the target data layout string in and methods for querying 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.
const Instruction & back() const
This file contains a class ARCRuntimeEntryPoints for use in creating/managing references to entry poi...
STATISTIC(NumFunctions,"Total number of functions")
objc_loadWeakRetained (primitive)
could call objc_release and/or "use" pointers
A Module instance is used to store all the information related to an LLVM module. ...
Implements a dense probed hash-table based set.
The two locations alias, but only due to a partial overlap.
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.
size_type count(PtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
Value * GetArgRCIdentityRoot(Value *Inst)
Assuming the given instruction is one of the special calls such as objc_retain or objc_release...
bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release)
Return true if this set of retains can be paired with the given release.
Type * getReturnType() const
Returns the type of the ret val.
The two locations do not alias at all.
static bool AreAnyUnderlyingObjectsAnAlloca(const Value *V, const DataLayout &DL)
This is a wrapper around getUnderlyingObjCPtr along the lines of GetUnderlyingObjects except that it ...
void initializeObjCARCOptPass(PassRegistry &)
An instruction for reading from memory.
iv Induction Variable Users
SmallPtrSet< Instruction *, 2 > ReverseInsertPts
The set of optimal insert positions for moving calls in the opposite sequence.
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.
The two locations may or may not alias. This is the least precise result.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
StringRef getName() const
Return a constant reference to the value's name.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
iterator begin()
Instruction iterator methods.
AnalysisUsage & addRequired()
#define INITIALIZE_PASS_DEPENDENCY(depName)
objc_autoreleaseReturnValue
inst_iterator inst_begin(Function *F)
This class represents the LLVM 'select' instruction.
const Module * getModule() const
Return the module owning the function this basic block belongs to, or nullptr it the function does no...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This class summarizes several per-pointer runtime properties which are propagated through the flow gr...
Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following: ...
bool IsNullOrUndef(const Value *V)
LLVM_NODISCARD bool empty() const
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 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
static bool setDoesNotThrow(Function &F)
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
bool EnableARCOpts
A handy option to enable/disable all ARC Optimizations.
This class represents a no-op cast from one type to another.
void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
An instruction for storing to memory.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
const RRInfo & GetRRInfo() const
bool IsAlwaysTail(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the "tail" keyword...
BBIty & getBasicBlockIterator()
bool ModuleHasARC(const Module &M)
Test if the given module looks interesting to run ARC optimization on.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
Unidirectional information about either a retain-decrement-use-release sequence or release-use-decrem...
unsigned getNumIncomingValues() const
Return the number of incoming edges.
Interval::succ_iterator succ_end(Interval *I)
raw_ostream & operator<<(raw_ostream &OS, const ARCInstKind Class)
an instruction for type-safe pointer arithmetic to access elements of arrays and structs ...
iterator find(const KeyT &Key)
bool erase(const KeyT &Val)
Subclasses of this class are all able to terminate a basic block.
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.
bool IsCFGHazardAfflicted() const
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.
This is an important base class in LLVM.
VectorTy::const_iterator const_iterator
BIty & getInstructionIterator()
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...
like S_Release, but code motion is stopped.
Represent the analysis usage information of a pass.
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
#define LLVM_ATTRIBUTE_UNUSED
INITIALIZE_PASS_END(RegBankSelect, DEBUG_TYPE,"Assign register bank of generic virtual registers", false, false) RegBankSelect
FunctionPass class - This class is used to implement most global optimizations.
Value * getOperand(unsigned i) const
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...
self_iterator getIterator()
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...
INITIALIZE_PASS_BEGIN(ObjCARCOpt,"objc-arc","ObjC ARC optimization", false, false) INITIALIZE_PASS_END(ObjCARCOpt
void setTailCall(bool isTC=true)
bool isPointerTy() const
True if this is an instance of PointerType.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
LLVMContext & getContext() const
All values hold a context through their type.
anything that is inert from an ARC perspective.
#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.
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...
static void EraseInstruction(Instruction *CI)
Erase the given instruction.
Iterator for intrusive lists based on ilist_node.
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...
bool erase(PtrType Ptr)
erase - If the set contains the specified pointer, remove it and return true, otherwise return false...
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
static CallInst * Create(Value *Func, ArrayRef< Value * > Args, ArrayRef< OperandBundleDef > Bundles=None, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
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.
Type * getType() const
All values are typed, get the type of this value.
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)
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_NODISCARD T pop_back_val()
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...
void setPreservesCFG()
This function should be called by the pass, iff they do not:
const BasicBlock & getEntryBlock() const
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Value * getArgOperand(unsigned i) const
getArgOperand/setArgOperand - Return/set the i-th call argument.
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()
iterator_range< user_iterator > users()
TerminatorInst::SuccIterator< TerminatorInst *, BasicBlock > succ_iterator
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)
void setCalledFunction(Value *Fn)
Set the function called.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
ImmutableCallSite - establish a view to a call site for examination.
objc_storeWeak (primitive)
bool hasOneUse() const
Return true if there is exactly one user of this value.
void setArgOperand(unsigned i, Value *v)
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
iterator find(const KeyT &Val)
bool IsTrackingImpreciseReleases() const
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)
const Value * GetUnderlyingObjCPtr(const Value *V, const DataLayout &DL)
This is a wrapper around getUnderlyingObject which also knows how to look through objc_retain and obj...
raw_ostream & operator<<(raw_ostream &OS, const APInt &I)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
foo(x) – x could possibly see a ref count decrement.
Legacy wrapper pass to provide the ObjCARCAAResult object.
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)
static void ComputePostOrders(Function &F, SmallVectorImpl< BasicBlock * > &PostOrder, SmallVectorImpl< BasicBlock * > &ReverseCFGPostOrder, unsigned NoObjCARCExceptionsMDKind, DenseMap< const BasicBlock *, BBState > &BBStates)
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object...
bool InitTopDown(ARCInstKind Kind, Instruction *I)
(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases...
bool HasKnownPositiveRefCount() const
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...
static IntegerType * getInt8Ty(LLVMContext &C)
bool AreStatisticsEnabled()
Check if statistics are enabled.
const BasicBlock * getParent() const
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 ...
bool IsNoopInstruction(const Instruction *I)
an instruction to allocate memory on the stack
bool IsAutorelease(ARCInstKind Class)
Test if the given class is objc_autorelease or equivalent.