74#define DEBUG_TYPE "objc-arc-opts"
78 cl::desc(
"Maximum number of ptr states the optimizer keeps track of"),
96 if (
GEP->hasAllZeroIndices())
159STATISTIC(NumNoops,
"Number of no-op objc calls eliminated");
160STATISTIC(NumPartialNoops,
"Number of partially no-op objc calls eliminated");
161STATISTIC(NumAutoreleases,
"Number of autoreleases converted to releases");
163 "retain+autoreleases eliminated");
164STATISTIC(NumRRs,
"Number of retain+release paths eliminated");
165STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
168 "Number of retains before optimization");
170 "Number of releases before optimization");
172 "Number of retains after optimization");
174 "Number of releases after optimization");
183 unsigned TopDownPathCount = 0;
186 unsigned BottomUpPathCount = 0;
209 using top_down_ptr_iterator =
decltype(PerPtrTopDown)
::iterator;
210 using const_top_down_ptr_iterator =
decltype(PerPtrTopDown)
::const_iterator;
212 top_down_ptr_iterator top_down_ptr_begin() {
return PerPtrTopDown.
begin(); }
213 top_down_ptr_iterator top_down_ptr_end() {
return PerPtrTopDown.
end(); }
214 const_top_down_ptr_iterator top_down_ptr_begin()
const {
215 return PerPtrTopDown.begin();
217 const_top_down_ptr_iterator top_down_ptr_end()
const {
218 return PerPtrTopDown.end();
220 bool hasTopDownPtrs()
const {
221 return !PerPtrTopDown.empty();
224 unsigned top_down_ptr_list_size()
const {
225 return std::distance(top_down_ptr_begin(), top_down_ptr_end());
228 using bottom_up_ptr_iterator =
decltype(PerPtrBottomUp)::iterator;
229 using const_bottom_up_ptr_iterator =
230 decltype(PerPtrBottomUp)::const_iterator;
232 bottom_up_ptr_iterator bottom_up_ptr_begin() {
233 return PerPtrBottomUp.begin();
235 bottom_up_ptr_iterator bottom_up_ptr_end() {
return PerPtrBottomUp.end(); }
236 const_bottom_up_ptr_iterator bottom_up_ptr_begin()
const {
237 return PerPtrBottomUp.begin();
239 const_bottom_up_ptr_iterator bottom_up_ptr_end()
const {
240 return PerPtrBottomUp.end();
242 bool hasBottomUpPtrs()
const {
243 return !PerPtrBottomUp.empty();
246 unsigned bottom_up_ptr_list_size()
const {
247 return std::distance(bottom_up_ptr_begin(), bottom_up_ptr_end());
252 void SetAsEntry() { TopDownPathCount = 1; }
256 void SetAsExit() { BottomUpPathCount = 1; }
261 TopDownPtrState &getPtrTopDownState(
const Value *Arg) {
262 return PerPtrTopDown[Arg];
268 BottomUpPtrState &getPtrBottomUpState(
const Value *Arg) {
269 return PerPtrBottomUp[Arg];
274 bottom_up_ptr_iterator findPtrBottomUpState(
const Value *Arg) {
275 return PerPtrBottomUp.find(Arg);
278 void clearBottomUpPointers() {
279 PerPtrBottomUp.clear();
282 void clearTopDownPointers() {
283 PerPtrTopDown.clear();
286 void InitFromPred(
const BBState &
Other);
287 void InitFromSucc(
const BBState &
Other);
288 void MergePred(
const BBState &
Other);
289 void MergeSucc(
const BBState &
Other);
297 bool GetAllPathCountWithOverflow(
unsigned &PathCount)
const {
301 unsigned long long Product =
302 (
unsigned long long)TopDownPathCount*BottomUpPathCount;
305 return (Product >> 32) ||
312 edge_iterator
pred_begin()
const {
return Preds.begin(); }
313 edge_iterator
pred_end()
const {
return Preds.end(); }
314 edge_iterator
succ_begin()
const {
return Succs.begin(); }
315 edge_iterator
succ_end()
const {
return Succs.end(); }
317 void addSucc(BasicBlock *Succ) { Succs.push_back(Succ); }
318 void addPred(BasicBlock *Pred) { Preds.push_back(Pred); }
320 bool isExit()
const {
return Succs.empty(); }
333void BBState::InitFromPred(
const BBState &
Other) {
334 PerPtrTopDown =
Other.PerPtrTopDown;
335 TopDownPathCount =
Other.TopDownPathCount;
338void BBState::InitFromSucc(
const BBState &
Other) {
339 PerPtrBottomUp =
Other.PerPtrBottomUp;
340 BottomUpPathCount =
Other.BottomUpPathCount;
345void BBState::MergePred(
const BBState &
Other) {
346 if (TopDownPathCount == OverflowOccurredValue)
351 TopDownPathCount +=
Other.TopDownPathCount;
356 if (TopDownPathCount == OverflowOccurredValue) {
357 clearTopDownPointers();
363 if (TopDownPathCount <
Other.TopDownPathCount) {
364 TopDownPathCount = OverflowOccurredValue;
365 clearTopDownPointers();
372 for (
auto MI =
Other.top_down_ptr_begin(), ME =
Other.top_down_ptr_end();
374 auto Pair = PerPtrTopDown.
insert(*
MI);
375 Pair.first->second.Merge(Pair.second ? TopDownPtrState() :
MI->second,
381 for (
auto MI = top_down_ptr_begin(), ME = top_down_ptr_end();
MI != ME; ++
MI)
382 if (
Other.PerPtrTopDown.find(
MI->first) ==
Other.PerPtrTopDown.end())
383 MI->second.Merge(TopDownPtrState(),
true);
388void BBState::MergeSucc(
const BBState &
Other) {
389 if (BottomUpPathCount == OverflowOccurredValue)
394 BottomUpPathCount +=
Other.BottomUpPathCount;
399 if (BottomUpPathCount == OverflowOccurredValue) {
400 clearBottomUpPointers();
406 if (BottomUpPathCount <
Other.BottomUpPathCount) {
407 BottomUpPathCount = OverflowOccurredValue;
408 clearBottomUpPointers();
415 for (
auto MI =
Other.bottom_up_ptr_begin(), ME =
Other.bottom_up_ptr_end();
417 auto Pair = PerPtrBottomUp.
insert(*
MI);
418 Pair.first->second.Merge(Pair.second ? BottomUpPtrState() :
MI->second,
424 for (
auto MI = bottom_up_ptr_begin(), ME = bottom_up_ptr_end();
MI != ME;
426 if (
Other.PerPtrBottomUp.find(
MI->first) ==
Other.PerPtrBottomUp.end())
427 MI->second.Merge(BottomUpPtrState(),
false);
432 OS <<
" TopDown State:\n";
433 if (!BBInfo.hasTopDownPtrs()) {
436 for (
auto I = BBInfo.top_down_ptr_begin(), E = BBInfo.top_down_ptr_end();
439 OS <<
" Ptr: " << *
I->first
440 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
441 <<
"\n ImpreciseRelease: "
442 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n"
443 <<
" HasCFGHazards: "
444 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n"
445 <<
" KnownPositive: "
446 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n"
448 <<
P.GetSeq() <<
"\n";
452 OS <<
" BottomUp State:\n";
453 if (!BBInfo.hasBottomUpPtrs()) {
456 for (
auto I = BBInfo.bottom_up_ptr_begin(), E = BBInfo.bottom_up_ptr_end();
459 OS <<
" Ptr: " << *
I->first
460 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
461 <<
"\n ImpreciseRelease: "
462 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n"
463 <<
" HasCFGHazards: "
464 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n"
465 <<
" KnownPositive: "
466 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n"
468 <<
P.GetSeq() <<
"\n";
480 bool CFGChanged =
false;
494 bool DisableRetainReleasePairing =
false;
498 unsigned UsedInThisFunction;
505 void OptimizeIndividualCalls(
Function &
F);
518 const Value *&AutoreleaseRVArg);
522 BBState &MyStates)
const;
529 bool VisitInstructionTopDown(
532 &ReleaseInsertPtToRCIdentityRoots);
537 &ReleaseInsertPtToRCIdentityRoots);
553 Value *Arg,
bool KnownSafe,
554 bool &AnyPairsCompletelyEliminated);
566 void OptimizeAutoreleasePools(
Function &
F);
568 template <
typename PredicateT>
569 static void cloneOpBundlesIf(
CallBase *CI,
579 void addOpBundleForFunclet(BasicBlock *BB,
580 SmallVectorImpl<OperandBundleDef> &OpBundles) {
581 if (!BlockEHColors.
empty()) {
584 for (BasicBlock *EHPadBB : CV)
594 void GatherStatistics(Function &
F,
bool AfterOptimization =
false);
598 void init(Function &
F);
599 bool run(Function &
F, AAResults &AA);
600 bool hasCFGChanged()
const {
return CFGChanged; }
607ObjCARCOpt::OptimizeRetainRVCall(Function &
F, Instruction *
RetainRV) {
620 if (
II->getNormalDest() == RetainRVParent) {
631 "a bundled retainRV's argument should be a call");
637 LLVM_DEBUG(
dbgs() <<
"Transforming objc_retainAutoreleasedReturnValue => "
638 "objc_retain since the operand is not a return value.\n"
642 Function *NewDecl = EP.
get(ARCRuntimeEntryPointKind::Retain);
650bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
662 if (Arg != AutoreleaseRVArg) {
676 LLVM_DEBUG(
dbgs() <<
"Found inlined objc_autoreleaseReturnValue '"
684 if (Class == ARCInstKind::RetainRV) {
693 assert(Class == ARCInstKind::UnsafeClaimRV);
699 "Expected UnsafeClaimRV to be safe to tail call");
705 OptimizeIndividualCallImpl(
F,
Release, ARCInstKind::Release, Arg);
711void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &
F,
722 SmallVector<const Value *, 2>
Users;
723 Users.push_back(Ptr);
730 Ptr =
Users.pop_back_val();
737 }
while (!
Users.empty());
743 dbgs() <<
"Transforming objc_autoreleaseReturnValue => "
744 "objc_autorelease since its operand is not used as a return "
750 Function *NewDecl = EP.
get(ARCRuntimeEntryPointKind::Autorelease);
753 Class = ARCInstKind::Autorelease;
760void ObjCARCOpt::OptimizeIndividualCalls(Function &
F) {
761 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeIndividualCalls ==\n");
763 UsedInThisFunction = 0;
768 const Value *DelayedAutoreleaseRVArg =
nullptr;
772 DelayedAutoreleaseRVArg =
nullptr;
774 auto optimizeDelayedAutoreleaseRV = [&]() {
775 if (!DelayedAutoreleaseRV)
777 OptimizeIndividualCallImpl(
F, DelayedAutoreleaseRV,
778 ARCInstKind::AutoreleaseRV,
779 DelayedAutoreleaseRVArg);
780 setDelayedAutoreleaseRV(
nullptr);
782 auto shouldDelayAutoreleaseRV = [&](
Instruction *NonARCInst) {
784 if (!DelayedAutoreleaseRV)
789 if (NonARCInst->isTerminator())
818 const Value *Arg =
nullptr;
821 optimizeDelayedAutoreleaseRV();
823 case ARCInstKind::CallOrUser:
824 case ARCInstKind::User:
825 case ARCInstKind::None:
829 if (!shouldDelayAutoreleaseRV(Inst))
830 optimizeDelayedAutoreleaseRV();
832 case ARCInstKind::AutoreleaseRV:
833 optimizeDelayedAutoreleaseRV();
834 setDelayedAutoreleaseRV(Inst);
836 case ARCInstKind::RetainRV:
837 case ARCInstKind::UnsafeClaimRV:
838 if (DelayedAutoreleaseRV) {
840 if (OptimizeInlinedAutoreleaseRVCall(
F, Inst, Arg, Class,
841 DelayedAutoreleaseRV,
842 DelayedAutoreleaseRVArg)) {
843 setDelayedAutoreleaseRV(
nullptr);
846 optimizeDelayedAutoreleaseRV();
851 OptimizeIndividualCallImpl(
F, Inst, Class, Arg);
855 optimizeDelayedAutoreleaseRV();
861 V = V->stripPointerCasts();
868 if (GV->hasAttribute(
"objc_arc_inert"))
873 if (!VisitedPhis.
insert(PN).second)
885void ObjCARCOpt::OptimizeIndividualCallImpl(Function &
F, Instruction *Inst,
888 LLVM_DEBUG(
dbgs() <<
"Visiting: Class: " << Class <<
"; " << *Inst <<
"\n");
891 SmallPtrSet<Value *, 1> VisitedPhis;
894 UsedInThisFunction |= 1 << unsigned(Class);
919 case ARCInstKind::NoopCast:
927 case ARCInstKind::StoreWeak:
928 case ARCInstKind::LoadWeak:
929 case ARCInstKind::LoadWeakRetained:
930 case ARCInstKind::InitWeak:
931 case ARCInstKind::DestroyWeak: {
940 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
942 << *CI <<
"\nNew = " << *NewValue <<
"\n");
949 case ARCInstKind::CopyWeak:
950 case ARCInstKind::MoveWeak: {
961 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
963 << *CI <<
"\nNew = " << *NewValue <<
"\n");
971 case ARCInstKind::RetainRV:
972 if (OptimizeRetainRVCall(
F, Inst))
975 case ARCInstKind::AutoreleaseRV:
976 OptimizeAutoreleaseRVCall(
F, Inst, Class);
992 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Release);
995 NewCall->
setMetadata(MDKindCache.
get(ARCMDKindID::ImpreciseRelease),
998 LLVM_DEBUG(
dbgs() <<
"Replacing autorelease{,RV}(x) with objc_release(x) "
999 "since x is otherwise unused.\nOld: "
1000 << *
Call <<
"\nNew: " << *NewCall <<
"\n");
1004 Class = ARCInstKind::Release;
1013 dbgs() <<
"Adding tail keyword to function since it can never be "
1014 "passed stack args: "
1023 LLVM_DEBUG(
dbgs() <<
"Removing tail keyword from function: " << *Inst
1031 LLVM_DEBUG(
dbgs() <<
"Found no throw class. Setting nounwind on: " << *Inst
1038 UsedInThisFunction |= 1 << unsigned(Class);
1050 LLVM_DEBUG(
dbgs() <<
"ARC calls with null are no-ops. Erasing: " << *Inst
1058 UsedInThisFunction |= 1 << unsigned(Class);
1066 if (Class == ARCInstKind::Release &&
1067 !Inst->
getMetadata(MDKindCache.
get(ARCMDKindID::ImpreciseRelease)))
1071 Worklist.
push_back(std::make_pair(Inst, Arg));
1073 std::pair<Instruction *, const Value *> Pair = Worklist.
pop_back_val();
1083 bool HasNull =
false;
1084 bool HasCriticalEdges =
false;
1091 HasCriticalEdges =
true;
1096 if (HasCriticalEdges)
1106 case ARCInstKind::Retain:
1107 case ARCInstKind::RetainBlock:
1110 case ARCInstKind::Release:
1116 case ARCInstKind::Autorelease:
1121 case ARCInstKind::UnsafeClaimRV:
1122 case ARCInstKind::RetainRV:
1123 case ARCInstKind::AutoreleaseRV:
1149 cloneOpBundlesIf(CInst, OpBundles, [](
const OperandBundleUse &
B) {
1152 addOpBundleForFunclet(InsertPos->getParent(), OpBundles);
1154 if (
Op->getType() != ParamTy)
1155 Op =
new BitCastInst(
Op, ParamTy,
"", InsertPos);
1157 Clone->
insertBefore(*InsertPos->getParent(), InsertPos);
1160 "And inserting clone at "
1161 << *InsertPos <<
"\n");
1162 Worklist.
push_back(std::make_pair(Clone, Incoming));
1167 }
while (!Worklist.
empty());
1173 const bool SuccSRRIKnownSafe,
1175 bool &SomeSuccHasSame,
1176 bool &AllSuccsHaveSame,
1177 bool &NotAllSeqEqualButKnownSafe,
1178 bool &ShouldContinue) {
1186 ShouldContinue =
true;
1190 SomeSuccHasSame =
true;
1195 AllSuccsHaveSame =
false;
1197 NotAllSeqEqualButKnownSafe =
true;
1210 const bool SuccSRRIKnownSafe,
1212 bool &SomeSuccHasSame,
1213 bool &AllSuccsHaveSame,
1214 bool &NotAllSeqEqualButKnownSafe) {
1217 SomeSuccHasSame =
true;
1223 AllSuccsHaveSame =
false;
1225 NotAllSeqEqualButKnownSafe =
true;
1238ObjCARCOpt::CheckForCFGHazards(
const BasicBlock *BB,
1239 DenseMap<const BasicBlock *, BBState> &BBStates,
1240 BBState &MyStates)
const {
1243 for (
auto I = MyStates.top_down_ptr_begin(),
E = MyStates.top_down_ptr_end();
1245 TopDownPtrState &S =
I->second;
1246 const Sequence Seq =
I->second.GetSeq();
1255 "Unknown top down sequence state.");
1257 const Value *Arg =
I->first;
1258 bool SomeSuccHasSame =
false;
1259 bool AllSuccsHaveSame =
true;
1260 bool NotAllSeqEqualButKnownSafe =
false;
1262 for (
const BasicBlock *Succ :
successors(BB)) {
1265 const auto BBI = BBStates.
find(Succ);
1267 const BottomUpPtrState &SuccS = BBI->second.getPtrBottomUpState(Arg);
1275 if (SuccSSeq ==
S_None) {
1282 const bool SuccSRRIKnownSafe = SuccS.
IsKnownSafe();
1288 bool ShouldContinue =
false;
1290 AllSuccsHaveSame, NotAllSeqEqualButKnownSafe,
1298 SomeSuccHasSame, AllSuccsHaveSame,
1299 NotAllSeqEqualButKnownSafe);
1312 if (SomeSuccHasSame && !AllSuccsHaveSame) {
1314 }
else if (NotAllSeqEqualButKnownSafe) {
1324bool ObjCARCOpt::VisitInstructionBottomUp(
1325 Instruction *Inst, BasicBlock *BB, BlotMapVector<Value *, RRInfo> &Retains,
1326 BBState &MyStates) {
1327 bool NestingDetected =
false;
1329 const Value *Arg =
nullptr;
1334 case ARCInstKind::Release: {
1337 BottomUpPtrState &S = MyStates.getPtrBottomUpState(Arg);
1341 case ARCInstKind::RetainBlock:
1346 case ARCInstKind::Retain:
1347 case ARCInstKind::RetainRV: {
1349 BottomUpPtrState &S = MyStates.getPtrBottomUpState(Arg);
1353 if (Class != ARCInstKind::RetainRV) {
1362 case ARCInstKind::AutoreleasepoolPop:
1364 MyStates.clearBottomUpPointers();
1365 return NestingDetected;
1366 case ARCInstKind::AutoreleasepoolPush:
1367 case ARCInstKind::None:
1369 return NestingDetected;
1376 for (
auto MI = MyStates.bottom_up_ptr_begin(),
1377 ME = MyStates.bottom_up_ptr_end();
1382 BottomUpPtrState &S =
MI->second;
1390 return NestingDetected;
1393bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
1394 DenseMap<const BasicBlock *, BBState> &BBStates,
1395 BlotMapVector<Value *, RRInfo> &Retains) {
1398 bool NestingDetected =
false;
1399 BBState &MyStates = BBStates[BB];
1403 BBState::edge_iterator
SI(MyStates.succ_begin()),
1404 SE(MyStates.succ_end());
1407 auto I = BBStates.
find(Succ);
1409 MyStates.InitFromSucc(
I->second);
1411 for (;
SI != SE; ++
SI) {
1413 I = BBStates.
find(Succ);
1415 MyStates.MergeSucc(
I->second);
1420 << BBStates[BB] <<
"\n"
1421 <<
"Performing Dataflow:\n");
1433 NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates);
1437 if (MyStates.bottom_up_ptr_list_size() >
MaxPtrStates) {
1438 DisableRetainReleasePairing =
true;
1446 for (BBState::edge_iterator PI(MyStates.pred_begin()),
1447 PE(MyStates.pred_end()); PI != PE; ++PI) {
1450 NestingDetected |= VisitInstructionBottomUp(
II, BB, Retains, MyStates);
1453 LLVM_DEBUG(
dbgs() <<
"\nFinal State:\n" << BBStates[BB] <<
"\n");
1455 return NestingDetected;
1464 &ReleaseInsertPtToRCIdentityRoots) {
1465 for (
const auto &
P : Retains) {
1472 for (
const Instruction *InsertPt :
P.second.ReverseInsertPts)
1473 ReleaseInsertPtToRCIdentityRoots[InsertPt].insert(Root);
1479static const SmallPtrSet<const Value *, 2> *
1483 &ReleaseInsertPtToRCIdentityRoots) {
1484 auto I = ReleaseInsertPtToRCIdentityRoots.find(InsertPt);
1485 if (
I == ReleaseInsertPtToRCIdentityRoots.end())
1490bool ObjCARCOpt::VisitInstructionTopDown(
1491 Instruction *Inst, DenseMap<Value *, RRInfo> &Releases, BBState &MyStates,
1492 const DenseMap<
const Instruction *, SmallPtrSet<const Value *, 2>>
1493 &ReleaseInsertPtToRCIdentityRoots) {
1494 bool NestingDetected =
false;
1496 const Value *Arg =
nullptr;
1500 if (
const SmallPtrSet<const Value *, 2> *Roots =
1502 Inst, ReleaseInsertPtToRCIdentityRoots))
1503 for (
const auto *Root : *Roots) {
1504 TopDownPtrState &S = MyStates.getPtrTopDownState(Root);
1517 case ARCInstKind::RetainBlock:
1523 case ARCInstKind::Retain:
1524 case ARCInstKind::RetainRV: {
1526 TopDownPtrState &S = MyStates.getPtrTopDownState(Arg);
1532 case ARCInstKind::Release: {
1534 TopDownPtrState &S = MyStates.getPtrTopDownState(Arg);
1546 case ARCInstKind::AutoreleasepoolPop:
1548 MyStates.clearTopDownPointers();
1550 case ARCInstKind::AutoreleasepoolPush:
1551 case ARCInstKind::None:
1560 for (
auto MI = MyStates.top_down_ptr_begin(),
1561 ME = MyStates.top_down_ptr_end();
1566 TopDownPtrState &S =
MI->second;
1573 return NestingDetected;
1576bool ObjCARCOpt::VisitTopDown(
1577 BasicBlock *BB, DenseMap<const BasicBlock *, BBState> &BBStates,
1578 DenseMap<Value *, RRInfo> &Releases,
1579 const DenseMap<
const Instruction *, SmallPtrSet<const Value *, 2>>
1580 &ReleaseInsertPtToRCIdentityRoots) {
1582 bool NestingDetected =
false;
1583 BBState &MyStates = BBStates[BB];
1587 BBState::edge_iterator PI(MyStates.pred_begin()),
1588 PE(MyStates.pred_end());
1591 auto I = BBStates.
find(Pred);
1593 MyStates.InitFromPred(
I->second);
1595 for (; PI != PE; ++PI) {
1597 I = BBStates.
find(Pred);
1599 MyStates.MergePred(
I->second);
1607 for (
auto I = MyStates.top_down_ptr_begin(),
1608 E = MyStates.top_down_ptr_end();
1610 I->second.SetCFGHazardAfflicted(
true);
1613 << BBStates[BB] <<
"\n"
1614 <<
"Performing Dataflow:\n");
1617 for (Instruction &Inst : *BB) {
1620 NestingDetected |= VisitInstructionTopDown(
1621 &Inst, Releases, MyStates, ReleaseInsertPtToRCIdentityRoots);
1625 if (MyStates.top_down_ptr_list_size() >
MaxPtrStates) {
1626 DisableRetainReleasePairing =
true;
1631 LLVM_DEBUG(
dbgs() <<
"\nState Before Checking for CFG Hazards:\n"
1632 << BBStates[BB] <<
"\n\n");
1633 CheckForCFGHazards(BB, BBStates, MyStates);
1635 return NestingDetected;
1642 unsigned NoObjCARCExceptionsMDKind,
1654 BBState &MyStates = BBStates[EntryBB];
1655 MyStates.SetAsEntry();
1664 while (SuccStack.
back().second != SE) {
1666 if (Visited.
insert(SuccBB).second) {
1668 BBStates[CurrBB].addSucc(SuccBB);
1669 BBState &SuccStates = BBStates[SuccBB];
1670 SuccStates.addPred(CurrBB);
1675 if (!OnStack.
count(SuccBB)) {
1676 BBStates[CurrBB].addSucc(SuccBB);
1677 BBStates[SuccBB].addPred(CurrBB);
1680 OnStack.
erase(CurrBB);
1683 }
while (!SuccStack.
empty());
1692 BBState &MyStates = BBStates[&ExitBB];
1693 if (!MyStates.isExit())
1696 MyStates.SetAsExit();
1698 PredStack.
push_back(std::make_pair(&ExitBB, MyStates.pred_begin()));
1700 while (!PredStack.
empty()) {
1701 reverse_dfs_next_succ:
1702 BBState::edge_iterator PE = BBStates[PredStack.
back().first].pred_end();
1703 while (PredStack.
back().second != PE) {
1705 if (Visited.
insert(BB).second) {
1707 goto reverse_dfs_next_succ;
1716bool ObjCARCOpt::Visit(Function &
F,
1717 DenseMap<const BasicBlock *, BBState> &BBStates,
1718 BlotMapVector<Value *, RRInfo> &Retains,
1719 DenseMap<Value *, RRInfo> &Releases) {
1725 SmallVector<BasicBlock *, 16> PostOrder;
1726 SmallVector<BasicBlock *, 16> ReverseCFGPostOrder;
1728 MDKindCache.
get(ARCMDKindID::NoObjCARCExceptions),
1732 bool BottomUpNestingDetected =
false;
1734 BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains);
1735 if (DisableRetainReleasePairing)
1739 DenseMap<const Instruction *, SmallPtrSet<const Value *, 2>>
1740 ReleaseInsertPtToRCIdentityRoots;
1744 bool TopDownNestingDetected =
false;
1746 TopDownNestingDetected |=
1747 VisitTopDown(BB, BBStates, Releases, ReleaseInsertPtToRCIdentityRoots);
1748 if (DisableRetainReleasePairing)
1752 return TopDownNestingDetected && BottomUpNestingDetected;
1756void ObjCARCOpt::MoveCalls(
Value *Arg, RRInfo &RetainsToMove,
1757 RRInfo &ReleasesToMove,
1758 BlotMapVector<Value *, RRInfo> &Retains,
1759 DenseMap<Value *, RRInfo> &Releases,
1760 SmallVectorImpl<Instruction *> &DeadInsts,
1766 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Retain);
1768 addOpBundleForFunclet(InsertPt->
getParent(), BundleList);
1776 "At insertion point: "
1777 << *InsertPt <<
"\n");
1780 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Release);
1782 addOpBundleForFunclet(InsertPt->
getParent(), BundleList);
1794 "At insertion point: "
1795 << *InsertPt <<
"\n");
1799 for (Instruction *OrigRetain : RetainsToMove.
Calls) {
1800 Retains.
blot(OrigRetain);
1802 LLVM_DEBUG(
dbgs() <<
"Deleting retain: " << *OrigRetain <<
"\n");
1804 for (Instruction *OrigRelease : ReleasesToMove.
Calls) {
1805 Releases.
erase(OrigRelease);
1807 LLVM_DEBUG(
dbgs() <<
"Deleting release: " << *OrigRelease <<
"\n");
1811bool ObjCARCOpt::PairUpRetainsAndReleases(
1812 DenseMap<const BasicBlock *, BBState> &BBStates,
1813 BlotMapVector<Value *, RRInfo> &Retains,
1814 DenseMap<Value *, RRInfo> &Releases,
Module *M,
1816 SmallVectorImpl<Instruction *> &DeadInsts, RRInfo &RetainsToMove,
1817 RRInfo &ReleasesToMove,
Value *Arg,
bool KnownSafe,
1818 bool &AnyPairsCompletelyEliminated) {
1822 bool KnownSafeTD =
true, KnownSafeBU =
true;
1823 bool CFGHazardAfflicted =
false;
1829 unsigned OldDelta = 0;
1830 unsigned NewDelta = 0;
1831 unsigned OldCount = 0;
1832 unsigned NewCount = 0;
1833 bool FirstRelease =
true;
1834 for (SmallVector<Instruction *, 4> NewRetains{
Retain};;) {
1835 SmallVector<Instruction *, 4> NewReleases;
1836 for (Instruction *NewRetain : NewRetains) {
1837 auto It = Retains.
find(NewRetain);
1839 const RRInfo &NewRetainRRI = It->second;
1842 for (Instruction *NewRetainRelease : NewRetainRRI.
Calls) {
1843 auto Jt = Releases.
find(NewRetainRelease);
1844 if (Jt == Releases.
end())
1846 const RRInfo &NewRetainReleaseRRI = Jt->second;
1853 if (!NewRetainReleaseRRI.
Calls.count(NewRetain))
1856 if (ReleasesToMove.
Calls.insert(NewRetainRelease).second) {
1859 const BBState &NRRBBState = BBStates[NewRetainRelease->
getParent()];
1861 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1864 "PathCount at this point can not be "
1865 "OverflowOccurredValue.");
1866 OldDelta -= PathCount;
1874 FirstRelease =
false;
1890 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1892 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1895 "PathCount at this point can not be "
1896 "OverflowOccurredValue.");
1897 NewDelta -= PathCount;
1900 NewReleases.
push_back(NewRetainRelease);
1905 if (NewReleases.
empty())
break;
1908 for (Instruction *NewRelease : NewReleases) {
1909 auto It = Releases.
find(NewRelease);
1911 const RRInfo &NewReleaseRRI = It->second;
1914 for (Instruction *NewReleaseRetain : NewReleaseRRI.
Calls) {
1915 auto Jt = Retains.
find(NewReleaseRetain);
1916 if (Jt == Retains.
end())
1918 const RRInfo &NewReleaseRetainRRI = Jt->second;
1925 if (!NewReleaseRetainRRI.
Calls.count(NewRelease))
1928 if (RetainsToMove.
Calls.insert(NewReleaseRetain).second) {
1931 const BBState &NRRBBState = BBStates[NewReleaseRetain->
getParent()];
1933 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1936 "PathCount at this point can not be "
1937 "OverflowOccurredValue.");
1938 OldDelta += PathCount;
1939 OldCount += PathCount;
1947 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1950 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1953 "PathCount at this point can not be "
1954 "OverflowOccurredValue.");
1955 NewDelta += PathCount;
1956 NewCount += PathCount;
1959 NewRetains.push_back(NewReleaseRetain);
1963 if (NewRetains.empty())
break;
1967 bool UnconditionallySafe = KnownSafeTD && KnownSafeBU;
1968 if (UnconditionallySafe) {
1983 const bool WillPerformCodeMotion =
1986 if (CFGHazardAfflicted && WillPerformCodeMotion)
1999 assert(OldCount != 0 &&
"Unreachable code?");
2000 NumRRs += OldCount - NewCount;
2002 AnyPairsCompletelyEliminated = NewCount == 0;
2010bool ObjCARCOpt::PerformCodePlacement(
2011 DenseMap<const BasicBlock *, BBState> &BBStates,
2012 BlotMapVector<Value *, RRInfo> &Retains,
2013 DenseMap<Value *, RRInfo> &Releases,
Module *M) {
2014 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::PerformCodePlacement ==\n");
2016 bool AnyPairsCompletelyEliminated =
false;
2017 SmallVector<Instruction *, 8> DeadInsts;
2040 if (
const GlobalVariable *GV =
2043 if (GV->isConstant())
2048 RRInfo RetainsToMove, ReleasesToMove;
2050 bool PerformMoveCalls = PairUpRetainsAndReleases(
2051 BBStates, Retains, Releases, M,
Retain, DeadInsts,
2052 RetainsToMove, ReleasesToMove, Arg, KnownSafe,
2053 AnyPairsCompletelyEliminated);
2055 if (PerformMoveCalls) {
2058 MoveCalls(Arg, RetainsToMove, ReleasesToMove,
2059 Retains, Releases, DeadInsts, M);
2065 while (!DeadInsts.
empty())
2068 return AnyPairsCompletelyEliminated;
2072void ObjCARCOpt::OptimizeWeakCalls(Function &
F) {
2084 if (Class != ARCInstKind::LoadWeak &&
2085 Class != ARCInstKind::LoadWeakRetained)
2089 if (Class == ARCInstKind::LoadWeak && Inst->
use_empty()) {
2106 switch (EarlierClass) {
2107 case ARCInstKind::LoadWeak:
2108 case ARCInstKind::LoadWeakRetained: {
2115 switch (PA.
getAA()->
alias(Arg, EarlierArg)) {
2119 if (Class == ARCInstKind::LoadWeakRetained) {
2120 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Retain);
2137 case ARCInstKind::StoreWeak:
2138 case ARCInstKind::InitWeak: {
2145 switch (PA.
getAA()->
alias(Arg, EarlierArg)) {
2149 if (Class == ARCInstKind::LoadWeakRetained) {
2150 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Retain);
2167 case ARCInstKind::MoveWeak:
2168 case ARCInstKind::CopyWeak:
2171 case ARCInstKind::AutoreleasepoolPush:
2172 case ARCInstKind::None:
2173 case ARCInstKind::IntrinsicUser:
2174 case ARCInstKind::User:
2190 if (Class != ARCInstKind::DestroyWeak)
2196 for (
User *U : Alloca->users()) {
2199 case ARCInstKind::InitWeak:
2200 case ARCInstKind::StoreWeak:
2201 case ARCInstKind::DestroyWeak:
2211 case ARCInstKind::InitWeak:
2212 case ARCInstKind::StoreWeak:
2216 case ARCInstKind::DestroyWeak:
2224 Alloca->eraseFromParent();
2232bool ObjCARCOpt::OptimizeSequences(Function &
F) {
2237 DenseMap<Value *, RRInfo> Releases;
2238 BlotMapVector<Value *, RRInfo> Retains;
2242 DenseMap<const BasicBlock *, BBState> BBStates;
2245 bool NestingDetected = Visit(
F, BBStates, Retains, Releases);
2247 if (DisableRetainReleasePairing)
2251 bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
2255 return AnyPairsCompletelyEliminated && NestingDetected;
2300static CallInst *FindPredecessorAutoreleaseWithSafePath(
2301 const Value *Arg, BasicBlock *BB, ReturnInst *Ret, ProvenanceAnalysis &PA) {
2324void ObjCARCOpt::OptimizeReturns(Function &
F) {
2325 if (!
F.getReturnType()->isPointerTy())
2330 for (BasicBlock &BB:
F) {
2343 FindPredecessorAutoreleaseWithSafePath(Arg, &BB, Ret, PA);
2360 (!
Call->isTailCall() &&
2377ObjCARCOpt::GatherStatistics(Function &
F,
bool AfterOptimization) {
2379 AfterOptimization ? NumRetainsAfterOpt : NumRetainsBeforeOpt;
2381 AfterOptimization ? NumReleasesAfterOpt : NumReleasesBeforeOpt;
2388 case ARCInstKind::Retain:
2391 case ARCInstKind::Release:
2399void ObjCARCOpt::init(Function &
F) {
2406 MDKindCache.
init(
F.getParent());
2409 EP.
init(
F.getParent());
2412 if (
F.hasPersonalityFn() &&
2417bool ObjCARCOpt::run(Function &
F, AAResults &AA) {
2422 BundledRetainClaimRVs BRV(EP,
false,
false);
2423 BundledInsts = &BRV;
2425 LLVM_DEBUG(
dbgs() <<
"<<< ObjCARCOpt: Visiting Function: " <<
F.getName()
2431 CFGChanged |=
R.second;
2437 GatherStatistics(
F,
false);
2446 OptimizeIndividualCalls(
F);
2449 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::LoadWeak)) |
2450 (1 <<
unsigned(ARCInstKind::LoadWeakRetained)) |
2451 (1 <<
unsigned(ARCInstKind::StoreWeak)) |
2452 (1 <<
unsigned(ARCInstKind::InitWeak)) |
2453 (1 <<
unsigned(ARCInstKind::CopyWeak)) |
2454 (1 <<
unsigned(ARCInstKind::MoveWeak)) |
2455 (1 <<
unsigned(ARCInstKind::DestroyWeak))))
2456 OptimizeWeakCalls(
F);
2459 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::Retain)) |
2460 (1 <<
unsigned(ARCInstKind::RetainRV)) |
2461 (1 <<
unsigned(ARCInstKind::RetainBlock))))
2462 if (UsedInThisFunction & (1 <<
unsigned(ARCInstKind::Release)))
2465 while (OptimizeSequences(
F)) {}
2468 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::Autorelease)) |
2469 (1 <<
unsigned(ARCInstKind::AutoreleaseRV))))
2473 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::AutoreleasepoolPush)) |
2474 (1 <<
unsigned(ARCInstKind::AutoreleasepoolPop))))
2475 OptimizeAutoreleasePools(
F);
2480 GatherStatistics(
F,
true);
2501 if (!Callee->hasExactDefinition())
2516 if (!PoolStack.
empty())
2526 if (PoolStack.
empty())
2528 PoolStack.
back() =
true;
2551 if (PoolStack.
empty())
2553 PoolStack.
back() =
true;
2574void ObjCARCOpt::OptimizeAutoreleasePools(Function &
F) {
2575 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeAutoreleasePools ==\n");
2577 OptimizationRemarkEmitter ORE(&
F);
2582 for (BasicBlock &BB :
F) {
2591 case ARCInstKind::AutoreleasepoolPush: {
2596 LLVM_DEBUG(
dbgs() <<
"Found autorelease pool push: " << *Push <<
"\n");
2600 case ARCInstKind::AutoreleasepoolPop: {
2603 if (PoolStack.
empty())
2606 auto &TopPool = PoolStack.
back();
2607 CallInst *PendingPush = TopPool.first;
2608 bool HasAutoreleaseInScope = TopPool.second;
2614 if (Pop->getArgOperand(0)->stripPointerCasts() != PendingPush)
2618 if (HasAutoreleaseInScope)
2623 return OptimizationRemark(
DEBUG_TYPE,
"AutoreleasePoolElimination",
2625 <<
"eliminated empty autorelease pool pair";
2632 Pop->eraseFromParent();
2639 case ARCInstKind::CallOrUser:
2640 case ARCInstKind::Call:
2644 case ARCInstKind::Autorelease:
2645 case ARCInstKind::AutoreleaseRV:
2646 case ARCInstKind::FusedRetainAutorelease:
2647 case ARCInstKind::FusedRetainAutoreleaseRV:
2648 case ARCInstKind::LoadWeak: {
2650 if (!PoolStack.
empty()) {
2651 PoolStack.
back().second =
true;
2654 <<
"Found autorelease or potential autorelease in pool scope: "
2661 case ARCInstKind::Retain:
2662 case ARCInstKind::RetainRV:
2663 case ARCInstKind::UnsafeClaimRV:
2664 case ARCInstKind::RetainBlock:
2665 case ARCInstKind::Release:
2666 case ARCInstKind::NoopCast:
2667 case ARCInstKind::LoadWeakRetained:
2668 case ARCInstKind::StoreWeak:
2669 case ARCInstKind::InitWeak:
2670 case ARCInstKind::MoveWeak:
2671 case ARCInstKind::CopyWeak:
2672 case ARCInstKind::DestroyWeak:
2673 case ARCInstKind::StoreStrong:
2674 case ARCInstKind::IntrinsicUser:
2675 case ARCInstKind::User:
2676 case ARCInstKind::None:
2693 bool CFGChanged = OCAO.hasCFGChanged();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains a class ARCRuntimeEntryPoints for use in creating/managing references to entry poi...
Expand Atomic instructions
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseMap class.
This file declares special dependency analysis routines used in Objective C ARC Optimizations.
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
iv Induction Variable Users
Machine Check Debug Module
uint64_t IntrinsicInst * II
This file defines common analysis utilities used by the ObjC ARC Optimizer.
static cl::opt< unsigned > MaxPtrStates("arc-opt-max-ptr-states", cl::Hidden, cl::desc("Maximum number of ptr states the optimizer keeps track of"), cl::init(4095))
This file defines ARC utility functions which are used by various parts of the compiler.
This file declares a special form of Alias Analysis called Provenance / Analysis''.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
void setAA(AAResults *aa)
AAResults * getAA() const
A manager for alias analyses.
LLVM_ABI AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
The main low level interface to the alias analysis implementation.
@ MayAlias
The two locations may or may not alias.
@ NoAlias
The two locations do not alias at all.
@ PartialAlias
The two locations alias, but only due to a partial overlap.
@ MustAlias
The two locations precisely alias each other.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
const Instruction & back() const
InstListType::const_iterator const_iterator
LLVM_ABI bool hasNPredecessors(unsigned N) const
Return true if this block has exactly N predecessors.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
This class represents a no-op cast from one type to another.
An associative container with fast insertion-order (deterministic) iteration over its elements.
void blot(const KeyT &Key)
This is similar to erase, but instead of removing the element from the vector, it just zeros out the ...
iterator find(const KeyT &Key)
typename VectorTy::const_iterator const_iterator
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &InsertPair)
Represents analyses that only rely on functions' control flow.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
OperandBundleUse getOperandBundleAt(unsigned Index) const
Return the operand bundle at a specific index.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
unsigned getNumOperandBundles() const
Return the number of operand bundles associated with this User.
bool onlyReadsMemory(unsigned OpNo) const
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
void setTailCall(bool IsTc=true)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
BIty & getInstructionIterator()
BBIty & getBasicBlockIterator()
LLVM_ABI unsigned getNumSuccessors() const LLVM_READONLY
Return the number of successors that this instruction has.
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
A Module instance is used to store all the information related to an LLVM module.
op_range incoming_values()
BasicBlock * getIncomingBlock(unsigned i) const
Return incoming basic block number i.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
bool erase(PtrType Ptr)
Remove pointer from the set.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
typename SuperClass::const_iterator const_iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool isVoidTy() const
Return true if this is 'void'.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
const ParentTy * getParent() const
self_iterator getIterator()
A cache of MDKinds used by various ARC optimizations.
unsigned get(ARCMDKindID ID)
Declarations for ObjC runtime functions and constants.
Function * get(ARCRuntimeEntryPointKind kind)
bool contains(const Instruction *I) const
See if an instruction is a bundled retainRV/claimRV call.
std::pair< bool, bool > insertAfterInvokes(Function &F, DominatorTree *DT)
Insert a retainRV/claimRV call to the normal destination blocks of invokes with operand bundle "clang...
CallInst * insertRVCall(BasicBlock::iterator InsertPt, CallBase *AnnotatedCall)
Insert a retainRV/claimRV call.
void eraseInst(CallInst *CI)
Remove a retainRV/claimRV call entirely.
This class summarizes several per-pointer runtime properties which are propagated through the flow gr...
void SetCFGHazardAfflicted(const bool NewValue)
const RRInfo & GetRRInfo() const
void ClearSequenceProgress()
This class implements an extremely fast bulk output stream that can only output to a stream.
static void CheckForUseCFGHazard(const Sequence SuccSSeq, const bool SuccSRRIKnownSafe, TopDownPtrState &S, bool &SomeSuccHasSame, bool &AllSuccsHaveSame, bool &NotAllSeqEqualButKnownSafe, bool &ShouldContinue)
If we have a top down pointer in the S_Use state, make sure that there are no CFG hazards by checking...
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 bool isInertARCValue(Value *V, SmallPtrSet< Value *, 1 > &VisitedPhis)
This function returns true if the value is inert.
static void collectReleaseInsertPts(const BlotMapVector< Value *, RRInfo > &Retains, DenseMap< const Instruction *, SmallPtrSet< const Value *, 2 > > &ReleaseInsertPtToRCIdentityRoots)
CallInst * Autorelease
Look for an `‘autorelease’' instruction dependent on Arg such that there are / no instructions depend...
static void ComputePostOrders(Function &F, SmallVectorImpl< BasicBlock * > &PostOrder, SmallVectorImpl< BasicBlock * > &ReverseCFGPostOrder, unsigned NoObjCARCExceptionsMDKind, DenseMap< const BasicBlock *, BBState > &BBStates)
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...
static const SmallPtrSet< const Value *, 2 > * getRCIdentityRootsFromReleaseInsertPt(const Instruction *InsertPt, const DenseMap< const Instruction *, SmallPtrSet< const Value *, 2 > > &ReleaseInsertPtToRCIdentityRoots)
bool MayAutorelease(const CallBase &CB, unsigned Depth=0)
Interprocedurally determine if calls made by the given call site can possibly produce autoreleases.
static const unsigned OverflowOccurredValue
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 ...
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
bool IsRetain(ARCInstKind Class)
Test if the given class is objc_retain or equivalent.
@ AutoreleasePoolBoundary
@ NeedsPositiveRetainCount
bool IsNeverTail(ARCInstKind Class)
Test if the given class represents instructions which are never safe to mark with the "tail" keyword.
bool IsAlwaysTail(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the "tail" keyword...
bool IsNullOrUndef(const Value *V)
bool IsAutorelease(ARCInstKind Class)
Test if the given class is objc_autorelease or equivalent.
ARCInstKind
Equivalence classes of instructions in the ARC Model.
@ DestroyWeak
objc_destroyWeak (derived)
@ FusedRetainAutorelease
objc_retainAutorelease
@ CallOrUser
could call objc_release and/or "use" pointers
@ StoreStrong
objc_storeStrong (derived)
@ LoadWeakRetained
objc_loadWeakRetained (primitive)
@ StoreWeak
objc_storeWeak (primitive)
@ AutoreleasepoolPop
objc_autoreleasePoolPop
@ AutoreleasepoolPush
objc_autoreleasePoolPush
@ InitWeak
objc_initWeak (derived)
@ Autorelease
objc_autorelease
@ LoadWeak
objc_loadWeak (derived)
@ None
anything that is inert from an ARC perspective.
@ MoveWeak
objc_moveWeak (derived)
@ User
could "use" a pointer
@ RetainRV
objc_retainAutoreleasedReturnValue
@ RetainBlock
objc_retainBlock
@ FusedRetainAutoreleaseRV
objc_retainAutoreleaseReturnValue
@ AutoreleaseRV
objc_autoreleaseReturnValue
@ Call
could call objc_release
@ CopyWeak
objc_copyWeak (derived)
@ NoopCast
objc_retainedObject, etc.
@ UnsafeClaimRV
objc_unsafeClaimAutoreleasedReturnValue
@ IntrinsicUser
llvm.objc.clang.arc.use
bool IsObjCIdentifiedObject(const Value *V)
Return true if this value refers to a distinct and identifiable object.
bool EnableARCOpts
A handy option to enable/disable all ARC Optimizations.
void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList)
Return the list of PHI nodes that are equivalent to PN.
bool IsForwarding(ARCInstKind Class)
Test if the given class represents instructions which return their argument verbatim.
bool IsNoopInstruction(const Instruction *I)
llvm::Instruction * findSingleDependency(DependenceKind Flavor, const Value *Arg, BasicBlock *StartBB, Instruction *StartInst, ProvenanceAnalysis &PA)
Find dependent instructions.
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
@ S_CanRelease
foo(x) – x could possibly see a ref count decrement.
@ S_Retain
objc_retain(x).
@ S_Stop
code motion is stopped.
@ S_MovableRelease
objc_release(x), !clang.imprecise_release.
ARCInstKind GetBasicARCInstKind(const Value *V)
Determine which objc runtime call instruction class V belongs to.
ARCInstKind GetARCInstKind(const Value *V)
Map V to its ARCInstKind equivalence class.
Value * GetArgRCIdentityRoot(Value *Inst)
Assuming the given instruction is one of the special calls such as objc_retain or objc_release,...
bool IsNoThrow(ARCInstKind Class)
Test if the given class represents instructions which are always safe to mark with the nounwind attri...
const Value * GetRCIdentityRoot(const Value *V)
The RCIdentity root of a value V is a dominating value U for which retaining or releasing U is equiva...
bool IsNoopOnGlobal(ARCInstKind Class)
Test if the given class represents instructions which do nothing if passed a global variable.
bool IsNoopOnNull(ARCInstKind Class)
Test if the given class represents instructions which do nothing if passed a null pointer.
bool hasAttachedCallOpBundle(const CallBase *CB)
static void EraseInstruction(Instruction *CI)
Erase the given instruction.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
InstIterator< SymbolTableList< BasicBlock >, Function::iterator, BasicBlock::iterator, Instruction > inst_iterator
auto pred_end(const MachineBasicBlock *BB)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
LLVM_ABI DenseMap< BasicBlock *, ColorVector > colorEHFunclets(Function &F)
If an EH funclet personality is in use (see isFuncletEHPersonality), this will recompute which blocks...
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
inst_iterator inst_begin(Function *F)
bool isScopedEHPersonality(EHPersonality Pers)
Returns true if this personality uses scope-style EH IR instructions: catchswitch,...
auto dyn_cast_or_null(const Y &Val)
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI bool AreStatisticsEnabled()
Check if statistics are enabled.
LLVM_ABI EHPersonality classifyEHPersonality(const Value *Pers)
See if the given exception handling personality function is one that we understand.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
inst_iterator inst_end(Function *F)
RNSuccIterator< NodeRef, BlockT, RegionT > succ_begin(NodeRef Node)
RNSuccIterator< NodeRef, BlockT, RegionT > succ_end(NodeRef Node)
Instruction::succ_iterator succ_iterator
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
TinyPtrVector< BasicBlock * > ColorVector
auto pred_begin(const MachineBasicBlock *BB)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A lightweight accessor for an operand bundle meant to be passed around by value.
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I)
(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases.
bool MatchWithRetain()
Return true if this set of releases can be paired with a release.
void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Unidirectional information about either a retain-decrement-use-release sequence or release-use-decrem...
bool KnownSafe
After an objc_retain, the reference count of the referenced object is known to be positive.
SmallPtrSet< Instruction *, 2 > Calls
For a top-down sequence, the set of objc_retains or objc_retainBlocks.
MDNode * ReleaseMetadata
If the Calls are objc_release calls and they all have a clang.imprecise_release tag,...
bool CFGHazardAfflicted
If this is true, we cannot perform code motion but can still remove retain/release pairs.
bool IsTailCallRelease
True of the objc_release calls are all marked with the "tail" keyword.
SmallPtrSet< Instruction *, 2 > ReverseInsertPts
The set of optimal insert positions for moving calls in the opposite sequence.
bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release)
Return true if this set of retains can be paired with the given release.
bool InitTopDown(ARCInstKind Kind, Instruction *I)
(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases.
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class, const BundledRetainClaimRVs &BundledRVs)
void HandlePotentialUse(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)