74#define DEBUG_TYPE "objc-arc-opts"
78 cl::desc(
"Maximum number of ptr states the optimizer keeps track of"),
96 if (
GEP->hasAllZeroIndices())
156STATISTIC(NumNoops,
"Number of no-op objc calls eliminated");
157STATISTIC(NumPartialNoops,
"Number of partially no-op objc calls eliminated");
158STATISTIC(NumAutoreleases,
"Number of autoreleases converted to releases");
160 "retain+autoreleases eliminated");
161STATISTIC(NumRRs,
"Number of retain+release paths eliminated");
162STATISTIC(NumPeeps,
"Number of calls peephole-optimized");
165 "Number of retains before optimization");
167 "Number of releases before optimization");
169 "Number of retains after optimization");
171 "Number of releases after optimization");
180 unsigned TopDownPathCount = 0;
183 unsigned BottomUpPathCount = 0;
206 using top_down_ptr_iterator =
decltype(PerPtrTopDown)
::iterator;
207 using const_top_down_ptr_iterator =
decltype(PerPtrTopDown)
::const_iterator;
209 top_down_ptr_iterator top_down_ptr_begin() {
return PerPtrTopDown.
begin(); }
210 top_down_ptr_iterator top_down_ptr_end() {
return PerPtrTopDown.
end(); }
211 const_top_down_ptr_iterator top_down_ptr_begin()
const {
212 return PerPtrTopDown.begin();
214 const_top_down_ptr_iterator top_down_ptr_end()
const {
215 return PerPtrTopDown.end();
217 bool hasTopDownPtrs()
const {
218 return !PerPtrTopDown.empty();
221 unsigned top_down_ptr_list_size()
const {
222 return std::distance(top_down_ptr_begin(), top_down_ptr_end());
225 using bottom_up_ptr_iterator =
decltype(PerPtrBottomUp)::iterator;
226 using const_bottom_up_ptr_iterator =
227 decltype(PerPtrBottomUp)::const_iterator;
229 bottom_up_ptr_iterator bottom_up_ptr_begin() {
230 return PerPtrBottomUp.begin();
232 bottom_up_ptr_iterator bottom_up_ptr_end() {
return PerPtrBottomUp.end(); }
233 const_bottom_up_ptr_iterator bottom_up_ptr_begin()
const {
234 return PerPtrBottomUp.begin();
236 const_bottom_up_ptr_iterator bottom_up_ptr_end()
const {
237 return PerPtrBottomUp.end();
239 bool hasBottomUpPtrs()
const {
240 return !PerPtrBottomUp.empty();
243 unsigned bottom_up_ptr_list_size()
const {
244 return std::distance(bottom_up_ptr_begin(), bottom_up_ptr_end());
249 void SetAsEntry() { TopDownPathCount = 1; }
253 void SetAsExit() { BottomUpPathCount = 1; }
258 TopDownPtrState &getPtrTopDownState(
const Value *Arg) {
259 return PerPtrTopDown[Arg];
265 BottomUpPtrState &getPtrBottomUpState(
const Value *Arg) {
266 return PerPtrBottomUp[Arg];
271 bottom_up_ptr_iterator findPtrBottomUpState(
const Value *Arg) {
272 return PerPtrBottomUp.find(Arg);
275 void clearBottomUpPointers() {
276 PerPtrBottomUp.clear();
279 void clearTopDownPointers() {
280 PerPtrTopDown.clear();
283 void InitFromPred(
const BBState &
Other);
284 void InitFromSucc(
const BBState &
Other);
285 void MergePred(
const BBState &
Other);
286 void MergeSucc(
const BBState &
Other);
294 bool GetAllPathCountWithOverflow(
unsigned &PathCount)
const {
298 unsigned long long Product =
299 (
unsigned long long)TopDownPathCount*BottomUpPathCount;
302 return (Product >> 32) ||
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(); }
330void BBState::InitFromPred(
const BBState &
Other) {
331 PerPtrTopDown =
Other.PerPtrTopDown;
332 TopDownPathCount =
Other.TopDownPathCount;
335void BBState::InitFromSucc(
const BBState &
Other) {
336 PerPtrBottomUp =
Other.PerPtrBottomUp;
337 BottomUpPathCount =
Other.BottomUpPathCount;
342void BBState::MergePred(
const BBState &
Other) {
343 if (TopDownPathCount == OverflowOccurredValue)
348 TopDownPathCount +=
Other.TopDownPathCount;
353 if (TopDownPathCount == OverflowOccurredValue) {
354 clearTopDownPointers();
360 if (TopDownPathCount <
Other.TopDownPathCount) {
361 TopDownPathCount = OverflowOccurredValue;
362 clearTopDownPointers();
369 for (
auto MI =
Other.top_down_ptr_begin(), ME =
Other.top_down_ptr_end();
371 auto Pair = PerPtrTopDown.
insert(*
MI);
372 Pair.first->second.Merge(Pair.second ? TopDownPtrState() :
MI->second,
378 for (
auto MI = top_down_ptr_begin(), ME = top_down_ptr_end();
MI != ME; ++
MI)
379 if (
Other.PerPtrTopDown.find(
MI->first) ==
Other.PerPtrTopDown.end())
380 MI->second.Merge(TopDownPtrState(),
true);
385void BBState::MergeSucc(
const BBState &
Other) {
386 if (BottomUpPathCount == OverflowOccurredValue)
391 BottomUpPathCount +=
Other.BottomUpPathCount;
396 if (BottomUpPathCount == OverflowOccurredValue) {
397 clearBottomUpPointers();
403 if (BottomUpPathCount <
Other.BottomUpPathCount) {
404 BottomUpPathCount = OverflowOccurredValue;
405 clearBottomUpPointers();
412 for (
auto MI =
Other.bottom_up_ptr_begin(), ME =
Other.bottom_up_ptr_end();
414 auto Pair = PerPtrBottomUp.
insert(*
MI);
415 Pair.first->second.Merge(Pair.second ? BottomUpPtrState() :
MI->second,
421 for (
auto MI = bottom_up_ptr_begin(), ME = bottom_up_ptr_end();
MI != ME;
423 if (
Other.PerPtrBottomUp.find(
MI->first) ==
Other.PerPtrBottomUp.end())
424 MI->second.Merge(BottomUpPtrState(),
false);
429 OS <<
" TopDown State:\n";
430 if (!BBInfo.hasTopDownPtrs()) {
433 for (
auto I = BBInfo.top_down_ptr_begin(), E = BBInfo.top_down_ptr_end();
436 OS <<
" Ptr: " << *
I->first
437 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
438 <<
"\n ImpreciseRelease: "
439 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n"
440 <<
" HasCFGHazards: "
441 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n"
442 <<
" KnownPositive: "
443 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n"
445 <<
P.GetSeq() <<
"\n";
449 OS <<
" BottomUp State:\n";
450 if (!BBInfo.hasBottomUpPtrs()) {
453 for (
auto I = BBInfo.bottom_up_ptr_begin(), E = BBInfo.bottom_up_ptr_end();
456 OS <<
" Ptr: " << *
I->first
457 <<
"\n KnownSafe: " << (
P.IsKnownSafe()?
"true":
"false")
458 <<
"\n ImpreciseRelease: "
459 << (
P.IsTrackingImpreciseReleases()?
"true":
"false") <<
"\n"
460 <<
" HasCFGHazards: "
461 << (
P.IsCFGHazardAfflicted()?
"true":
"false") <<
"\n"
462 <<
" KnownPositive: "
463 << (
P.HasKnownPositiveRefCount()?
"true":
"false") <<
"\n"
465 <<
P.GetSeq() <<
"\n";
477 bool CFGChanged =
false;
491 bool DisableRetainReleasePairing =
false;
495 unsigned UsedInThisFunction;
510 void OptimizeIndividualCalls(
Function &
F);
523 const Value *&AutoreleaseRVArg);
527 BBState &MyStates)
const;
534 bool VisitInstructionTopDown(
537 &ReleaseInsertPtToRCIdentityRoots);
542 &ReleaseInsertPtToRCIdentityRoots);
558 Value *Arg,
bool KnownSafe,
559 bool &AnyPairsCompletelyEliminated);
571 void OptimizeAutoreleasePools(
Function &
F);
573 template <
typename PredicateT>
574 static void cloneOpBundlesIf(
CallBase *CI,
584 void addOpBundleForFunclet(BasicBlock *BB,
585 SmallVectorImpl<OperandBundleDef> &OpBundles) {
586 if (!BlockEHColors.
empty()) {
589 for (BasicBlock *EHPadBB : CV)
599 void GatherStatistics(
Function &
F,
bool AfterOptimization =
false);
605 bool hasCFGChanged()
const {
return CFGChanged; }
617ObjCARCOpt::FindFollowingAutoreleasePoolPop(Instruction *AutoreleaseInst) {
620 auto It = FollowingPoolPopCache.
find(AutoreleaseInst);
621 if (It != FollowingPoolPopCache.
end()) {
631 AutoreleasesByDepth[0].push_back(AutoreleaseInst);
639 if (Class == ARCInstKind::AutoreleasepoolPush) {
640 if (++
Depth >= AutoreleasesByDepth.size())
641 AutoreleasesByDepth.emplace_back();
644 "reused bucket must be empty");
645 }
else if (Class == ARCInstKind::AutoreleasepoolPop) {
646 for (Instruction *J : AutoreleasesByDepth[
Depth])
647 FollowingPoolPopCache[J] = &*
I;
652 }
else if (Class == ARCInstKind::Autorelease) {
653 AutoreleasesByDepth[
Depth].push_back(&*
I);
654 }
else if (Class == ARCInstKind::Call || Class == ARCInstKind::CallOrUser) {
663 for (
const auto &Autoreleases : AutoreleasesByDepth)
664 for (Instruction *
I : Autoreleases)
665 FollowingPoolPopCache[
I] =
nullptr;
685 if (
II->getNormalDest() == RetainRVParent) {
696 "a bundled retainRV's argument should be a call");
702 LLVM_DEBUG(
dbgs() <<
"Transforming objc_retainAutoreleasedReturnValue => "
703 "objc_retain since the operand is not a return value.\n"
707 Function *NewDecl = EP.
get(ARCRuntimeEntryPointKind::Retain);
715bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall(
727 if (Arg != AutoreleaseRVArg) {
741 LLVM_DEBUG(
dbgs() <<
"Found inlined objc_autoreleaseReturnValue '"
749 if (Class == ARCInstKind::RetainRV) {
758 assert(Class == ARCInstKind::UnsafeClaimRV);
764 "Expected UnsafeClaimRV to be safe to tail call");
770 OptimizeIndividualCallImpl(
F,
Release, ARCInstKind::Release, Arg);
776void ObjCARCOpt::OptimizeAutoreleaseRVCall(
Function &
F,
787 SmallVector<const Value *, 2>
Users;
788 Users.push_back(Ptr);
795 Ptr =
Users.pop_back_val();
802 }
while (!
Users.empty());
808 dbgs() <<
"Transforming objc_autoreleaseReturnValue => "
809 "objc_autorelease since its operand is not used as a return "
815 Function *NewDecl = EP.
get(ARCRuntimeEntryPointKind::Autorelease);
818 Class = ARCInstKind::Autorelease;
825void ObjCARCOpt::OptimizeIndividualCalls(
Function &
F) {
826 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeIndividualCalls ==\n");
828 UsedInThisFunction = 0;
830 FollowingPoolPopCache.
clear();
835 const Value *DelayedAutoreleaseRVArg =
nullptr;
839 DelayedAutoreleaseRVArg =
nullptr;
841 auto optimizeDelayedAutoreleaseRV = [&]() {
842 if (!DelayedAutoreleaseRV)
844 OptimizeIndividualCallImpl(
F, DelayedAutoreleaseRV,
845 ARCInstKind::AutoreleaseRV,
846 DelayedAutoreleaseRVArg);
847 setDelayedAutoreleaseRV(
nullptr);
849 auto shouldDelayAutoreleaseRV = [&](
Instruction *NonARCInst) {
851 if (!DelayedAutoreleaseRV)
856 if (NonARCInst->isTerminator())
885 const Value *Arg =
nullptr;
888 optimizeDelayedAutoreleaseRV();
890 case ARCInstKind::CallOrUser:
891 case ARCInstKind::User:
892 case ARCInstKind::None:
896 if (!shouldDelayAutoreleaseRV(Inst))
897 optimizeDelayedAutoreleaseRV();
899 case ARCInstKind::AutoreleaseRV:
900 optimizeDelayedAutoreleaseRV();
901 setDelayedAutoreleaseRV(Inst);
903 case ARCInstKind::RetainRV:
904 case ARCInstKind::UnsafeClaimRV:
905 if (DelayedAutoreleaseRV) {
907 if (OptimizeInlinedAutoreleaseRVCall(
F, Inst, Arg, Class,
908 DelayedAutoreleaseRV,
909 DelayedAutoreleaseRVArg)) {
910 setDelayedAutoreleaseRV(
nullptr);
913 optimizeDelayedAutoreleaseRV();
918 OptimizeIndividualCallImpl(
F, Inst, Class, Arg);
922 optimizeDelayedAutoreleaseRV();
928 V = V->stripPointerCasts();
935 if (GV->hasAttribute(
"objc_arc_inert"))
940 if (!VisitedPhis.
insert(PN).second)
952void ObjCARCOpt::OptimizeIndividualCallImpl(
Function &
F, Instruction *Inst,
955 LLVM_DEBUG(
dbgs() <<
"Visiting: Class: " << Class <<
"; " << *Inst <<
"\n");
958 SmallPtrSet<Value *, 1> VisitedPhis;
961 UsedInThisFunction |= 1 << unsigned(Class);
986 case ARCInstKind::NoopCast:
994 case ARCInstKind::StoreWeak:
995 case ARCInstKind::LoadWeak:
996 case ARCInstKind::LoadWeakRetained:
997 case ARCInstKind::InitWeak:
998 case ARCInstKind::DestroyWeak: {
1007 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
1009 << *CI <<
"\nNew = " << *NewValue <<
"\n");
1016 case ARCInstKind::CopyWeak:
1017 case ARCInstKind::MoveWeak: {
1028 dbgs() <<
"A null pointer-to-weak-pointer is undefined behavior."
1030 << *CI <<
"\nNew = " << *NewValue <<
"\n");
1038 case ARCInstKind::RetainRV:
1039 if (OptimizeRetainRVCall(
F, Inst))
1042 case ARCInstKind::AutoreleaseRV:
1043 OptimizeAutoreleaseRVCall(
F, Inst, Class);
1057 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Release);
1060 NewCall->
setMetadata(MDKindCache.
get(ARCMDKindID::ImpreciseRelease),
1064 dbgs() <<
"Replacing objc_autorelease(x) with objc_release(x)\n");
1069 Class = ARCInstKind::Release;
1078 if (Class == ARCInstKind::Autorelease) {
1079 if (Instruction *PoolPop = FindFollowingAutoreleasePoolPop(Inst)) {
1085 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Release);
1087 PoolPop->getIterator());
1088 NewCall->
setMetadata(MDKindCache.
get(ARCMDKindID::ImpreciseRelease),
1091 LLVM_DEBUG(
dbgs() <<
"Converting autorelease to release before pool pop."
1093 << *
Call <<
"\nNew: " << *NewCall <<
"\n");
1096 "objc_autorelease result and argument types must match");
1105 Class = ARCInstKind::Release;
1114 dbgs() <<
"Adding tail keyword to function since it can never be "
1115 "passed stack args: "
1124 LLVM_DEBUG(
dbgs() <<
"Removing tail keyword from function: " << *Inst
1132 LLVM_DEBUG(
dbgs() <<
"Found no throw class. Setting nounwind on: " << *Inst
1139 UsedInThisFunction |= 1 << unsigned(Class);
1151 LLVM_DEBUG(
dbgs() <<
"ARC calls with null are no-ops. Erasing: " << *Inst
1159 UsedInThisFunction |= 1 << unsigned(Class);
1167 if (Class == ARCInstKind::Release &&
1168 !Inst->
getMetadata(MDKindCache.
get(ARCMDKindID::ImpreciseRelease)))
1172 Worklist.
push_back(std::make_pair(Inst, Arg));
1174 std::pair<Instruction *, const Value *> Pair = Worklist.
pop_back_val();
1184 bool HasNull =
false;
1185 bool HasCriticalEdges =
false;
1192 HasCriticalEdges =
true;
1197 if (HasCriticalEdges)
1207 case ARCInstKind::Retain:
1208 case ARCInstKind::RetainBlock:
1211 case ARCInstKind::Release:
1217 case ARCInstKind::Autorelease:
1222 case ARCInstKind::UnsafeClaimRV:
1223 case ARCInstKind::RetainRV:
1224 case ARCInstKind::AutoreleaseRV:
1250 cloneOpBundlesIf(CInst, OpBundles, [](
const OperandBundleUse &
B) {
1253 addOpBundleForFunclet(InsertPos->getParent(), OpBundles);
1255 if (
Op->getType() != ParamTy)
1256 Op =
new BitCastInst(
Op, ParamTy,
"", InsertPos);
1258 Clone->
insertBefore(*InsertPos->getParent(), InsertPos);
1261 "And inserting clone at "
1262 << *InsertPos <<
"\n");
1263 Worklist.
push_back(std::make_pair(Clone, Incoming));
1267 FollowingPoolPopCache.
erase(CInst);
1269 }
while (!Worklist.
empty());
1275 const bool SuccSRRIKnownSafe,
1277 bool &SomeSuccHasSame,
1278 bool &AllSuccsHaveSame,
1279 bool &NotAllSeqEqualButKnownSafe,
1280 bool &ShouldContinue) {
1288 ShouldContinue =
true;
1292 SomeSuccHasSame =
true;
1297 AllSuccsHaveSame =
false;
1299 NotAllSeqEqualButKnownSafe =
true;
1312 const bool SuccSRRIKnownSafe,
1314 bool &SomeSuccHasSame,
1315 bool &AllSuccsHaveSame,
1316 bool &NotAllSeqEqualButKnownSafe) {
1319 SomeSuccHasSame =
true;
1325 AllSuccsHaveSame =
false;
1327 NotAllSeqEqualButKnownSafe =
true;
1340ObjCARCOpt::CheckForCFGHazards(
const BasicBlock *BB,
1341 DenseMap<const BasicBlock *, BBState> &BBStates,
1342 BBState &MyStates)
const {
1345 for (
auto I = MyStates.top_down_ptr_begin(),
E = MyStates.top_down_ptr_end();
1347 TopDownPtrState &S =
I->second;
1348 const Sequence Seq =
I->second.GetSeq();
1357 "Unknown top down sequence state.");
1359 const Value *Arg =
I->first;
1360 bool SomeSuccHasSame =
false;
1361 bool AllSuccsHaveSame =
true;
1362 bool NotAllSeqEqualButKnownSafe =
false;
1364 for (
const BasicBlock *Succ :
successors(BB)) {
1367 const auto BBI = BBStates.
find(Succ);
1369 const BottomUpPtrState &SuccS = BBI->second.getPtrBottomUpState(Arg);
1377 if (SuccSSeq ==
S_None) {
1384 const bool SuccSRRIKnownSafe = SuccS.
IsKnownSafe();
1390 bool ShouldContinue =
false;
1392 AllSuccsHaveSame, NotAllSeqEqualButKnownSafe,
1400 SomeSuccHasSame, AllSuccsHaveSame,
1401 NotAllSeqEqualButKnownSafe);
1414 if (SomeSuccHasSame && !AllSuccsHaveSame) {
1416 }
else if (NotAllSeqEqualButKnownSafe) {
1426bool ObjCARCOpt::VisitInstructionBottomUp(
1427 Instruction *Inst, BasicBlock *BB, BlotMapVector<Value *, RRInfo> &Retains,
1428 BBState &MyStates) {
1429 bool NestingDetected =
false;
1431 const Value *Arg =
nullptr;
1436 case ARCInstKind::Release: {
1439 BottomUpPtrState &S = MyStates.getPtrBottomUpState(Arg);
1443 case ARCInstKind::RetainBlock:
1448 case ARCInstKind::Retain:
1449 case ARCInstKind::RetainRV: {
1451 BottomUpPtrState &S = MyStates.getPtrBottomUpState(Arg);
1455 if (Class != ARCInstKind::RetainRV) {
1464 case ARCInstKind::AutoreleasepoolPop:
1466 MyStates.clearBottomUpPointers();
1467 return NestingDetected;
1468 case ARCInstKind::AutoreleasepoolPush:
1469 case ARCInstKind::None:
1471 return NestingDetected;
1478 for (
auto MI = MyStates.bottom_up_ptr_begin(),
1479 ME = MyStates.bottom_up_ptr_end();
1484 BottomUpPtrState &S =
MI->second;
1492 return NestingDetected;
1495bool ObjCARCOpt::VisitBottomUp(BasicBlock *BB,
1496 DenseMap<const BasicBlock *, BBState> &BBStates,
1497 BlotMapVector<Value *, RRInfo> &Retains) {
1500 bool NestingDetected =
false;
1501 BBState &MyStates = BBStates[BB];
1505 BBState::edge_iterator
SI(MyStates.succ_begin()),
1506 SE(MyStates.succ_end());
1509 auto I = BBStates.
find(Succ);
1511 MyStates.InitFromSucc(
I->second);
1513 for (;
SI != SE; ++
SI) {
1515 I = BBStates.
find(Succ);
1517 MyStates.MergeSucc(
I->second);
1522 << BBStates[BB] <<
"\n"
1523 <<
"Performing Dataflow:\n");
1535 NestingDetected |= VisitInstructionBottomUp(Inst, BB, Retains, MyStates);
1539 if (MyStates.bottom_up_ptr_list_size() >
MaxPtrStates) {
1540 DisableRetainReleasePairing =
true;
1548 for (BBState::edge_iterator PI(MyStates.pred_begin()),
1549 PE(MyStates.pred_end()); PI != PE; ++PI) {
1552 NestingDetected |= VisitInstructionBottomUp(
II, BB, Retains, MyStates);
1555 LLVM_DEBUG(
dbgs() <<
"\nFinal State:\n" << BBStates[BB] <<
"\n");
1557 return NestingDetected;
1566 &ReleaseInsertPtToRCIdentityRoots) {
1567 for (
const auto &
P : Retains) {
1574 for (
const Instruction *InsertPt :
P.second.ReverseInsertPts)
1575 ReleaseInsertPtToRCIdentityRoots[InsertPt].insert(Root);
1581static const SmallPtrSet<const Value *, 2> *
1585 &ReleaseInsertPtToRCIdentityRoots) {
1586 auto I = ReleaseInsertPtToRCIdentityRoots.find(InsertPt);
1587 if (
I == ReleaseInsertPtToRCIdentityRoots.end())
1592bool ObjCARCOpt::VisitInstructionTopDown(
1593 Instruction *Inst, DenseMap<Value *, RRInfo> &Releases, BBState &MyStates,
1594 const DenseMap<
const Instruction *, SmallPtrSet<const Value *, 2>>
1595 &ReleaseInsertPtToRCIdentityRoots) {
1596 bool NestingDetected =
false;
1598 const Value *Arg =
nullptr;
1602 if (
const SmallPtrSet<const Value *, 2> *Roots =
1604 Inst, ReleaseInsertPtToRCIdentityRoots))
1605 for (
const auto *Root : *Roots) {
1606 TopDownPtrState &S = MyStates.getPtrTopDownState(Root);
1619 case ARCInstKind::RetainBlock:
1625 case ARCInstKind::Retain:
1626 case ARCInstKind::RetainRV: {
1628 TopDownPtrState &S = MyStates.getPtrTopDownState(Arg);
1634 case ARCInstKind::Release: {
1636 TopDownPtrState &S = MyStates.getPtrTopDownState(Arg);
1648 case ARCInstKind::AutoreleasepoolPop:
1650 MyStates.clearTopDownPointers();
1652 case ARCInstKind::AutoreleasepoolPush:
1653 case ARCInstKind::None:
1662 for (
auto MI = MyStates.top_down_ptr_begin(),
1663 ME = MyStates.top_down_ptr_end();
1668 TopDownPtrState &S =
MI->second;
1675 return NestingDetected;
1678bool ObjCARCOpt::VisitTopDown(
1679 BasicBlock *BB, DenseMap<const BasicBlock *, BBState> &BBStates,
1680 DenseMap<Value *, RRInfo> &Releases,
1681 const DenseMap<
const Instruction *, SmallPtrSet<const Value *, 2>>
1682 &ReleaseInsertPtToRCIdentityRoots) {
1684 bool NestingDetected =
false;
1685 BBState &MyStates = BBStates[BB];
1689 BBState::edge_iterator PI(MyStates.pred_begin()),
1690 PE(MyStates.pred_end());
1693 auto I = BBStates.
find(Pred);
1695 MyStates.InitFromPred(
I->second);
1697 for (; PI != PE; ++PI) {
1699 I = BBStates.
find(Pred);
1701 MyStates.MergePred(
I->second);
1709 for (
auto I = MyStates.top_down_ptr_begin(),
1710 E = MyStates.top_down_ptr_end();
1712 I->second.SetCFGHazardAfflicted(
true);
1715 << BBStates[BB] <<
"\n"
1716 <<
"Performing Dataflow:\n");
1719 for (Instruction &Inst : *BB) {
1722 NestingDetected |= VisitInstructionTopDown(
1723 &Inst, Releases, MyStates, ReleaseInsertPtToRCIdentityRoots);
1727 if (MyStates.top_down_ptr_list_size() >
MaxPtrStates) {
1728 DisableRetainReleasePairing =
true;
1733 LLVM_DEBUG(
dbgs() <<
"\nState Before Checking for CFG Hazards:\n"
1734 << BBStates[BB] <<
"\n\n");
1735 CheckForCFGHazards(BB, BBStates, MyStates);
1737 return NestingDetected;
1744 unsigned NoObjCARCExceptionsMDKind,
1756 BBState &MyStates = BBStates[EntryBB];
1757 MyStates.SetAsEntry();
1766 while (SuccStack.
back().second != SE) {
1768 if (Visited.
insert(SuccBB).second) {
1770 BBStates[CurrBB].addSucc(SuccBB);
1771 BBState &SuccStates = BBStates[SuccBB];
1772 SuccStates.addPred(CurrBB);
1777 if (!OnStack.
count(SuccBB)) {
1778 BBStates[CurrBB].addSucc(SuccBB);
1779 BBStates[SuccBB].addPred(CurrBB);
1782 OnStack.
erase(CurrBB);
1785 }
while (!SuccStack.
empty());
1794 BBState &MyStates = BBStates[&ExitBB];
1795 if (!MyStates.isExit())
1798 MyStates.SetAsExit();
1800 PredStack.
push_back(std::make_pair(&ExitBB, MyStates.pred_begin()));
1802 while (!PredStack.
empty()) {
1803 reverse_dfs_next_succ:
1804 BBState::edge_iterator PE = BBStates[PredStack.
back().first].pred_end();
1805 while (PredStack.
back().second != PE) {
1807 if (Visited.
insert(BB).second) {
1809 goto reverse_dfs_next_succ;
1819 DenseMap<const BasicBlock *, BBState> &BBStates,
1820 BlotMapVector<Value *, RRInfo> &Retains,
1821 DenseMap<Value *, RRInfo> &Releases) {
1827 SmallVector<BasicBlock *, 16> PostOrder;
1828 SmallVector<BasicBlock *, 16> ReverseCFGPostOrder;
1830 MDKindCache.
get(ARCMDKindID::NoObjCARCExceptions),
1834 bool BottomUpNestingDetected =
false;
1836 BottomUpNestingDetected |= VisitBottomUp(BB, BBStates, Retains);
1837 if (DisableRetainReleasePairing)
1841 DenseMap<const Instruction *, SmallPtrSet<const Value *, 2>>
1842 ReleaseInsertPtToRCIdentityRoots;
1846 bool TopDownNestingDetected =
false;
1848 TopDownNestingDetected |=
1849 VisitTopDown(BB, BBStates, Releases, ReleaseInsertPtToRCIdentityRoots);
1850 if (DisableRetainReleasePairing)
1854 return TopDownNestingDetected && BottomUpNestingDetected;
1858void ObjCARCOpt::MoveCalls(
Value *Arg, RRInfo &RetainsToMove,
1859 RRInfo &ReleasesToMove,
1860 BlotMapVector<Value *, RRInfo> &Retains,
1861 DenseMap<Value *, RRInfo> &Releases,
1862 SmallVectorImpl<Instruction *> &DeadInsts,
1868 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Retain);
1870 addOpBundleForFunclet(InsertPt->
getParent(), BundleList);
1878 "At insertion point: "
1879 << *InsertPt <<
"\n");
1882 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Release);
1884 addOpBundleForFunclet(InsertPt->
getParent(), BundleList);
1896 "At insertion point: "
1897 << *InsertPt <<
"\n");
1901 for (Instruction *OrigRetain : RetainsToMove.
Calls) {
1902 Retains.
blot(OrigRetain);
1904 LLVM_DEBUG(
dbgs() <<
"Deleting retain: " << *OrigRetain <<
"\n");
1906 for (Instruction *OrigRelease : ReleasesToMove.
Calls) {
1907 Releases.
erase(OrigRelease);
1909 LLVM_DEBUG(
dbgs() <<
"Deleting release: " << *OrigRelease <<
"\n");
1913bool ObjCARCOpt::PairUpRetainsAndReleases(
1914 DenseMap<const BasicBlock *, BBState> &BBStates,
1915 BlotMapVector<Value *, RRInfo> &Retains,
1916 DenseMap<Value *, RRInfo> &Releases,
Module *M,
1918 SmallVectorImpl<Instruction *> &DeadInsts, RRInfo &RetainsToMove,
1919 RRInfo &ReleasesToMove,
Value *Arg,
bool KnownSafe,
1920 bool &AnyPairsCompletelyEliminated) {
1924 bool KnownSafeTD =
true, KnownSafeBU =
true;
1925 bool CFGHazardAfflicted =
false;
1931 unsigned OldDelta = 0;
1932 unsigned NewDelta = 0;
1933 unsigned OldCount = 0;
1934 unsigned NewCount = 0;
1935 bool FirstRelease =
true;
1936 for (SmallVector<Instruction *, 4> NewRetains{
Retain};;) {
1937 SmallVector<Instruction *, 4> NewReleases;
1938 for (Instruction *NewRetain : NewRetains) {
1939 auto It = Retains.
find(NewRetain);
1941 const RRInfo &NewRetainRRI = It->second;
1944 for (Instruction *NewRetainRelease : NewRetainRRI.
Calls) {
1945 auto Jt = Releases.
find(NewRetainRelease);
1946 if (Jt == Releases.
end())
1948 const RRInfo &NewRetainReleaseRRI = Jt->second;
1955 if (!NewRetainReleaseRRI.
Calls.count(NewRetain))
1958 if (ReleasesToMove.
Calls.insert(NewRetainRelease).second) {
1961 const BBState &NRRBBState = BBStates[NewRetainRelease->
getParent()];
1963 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
1966 "PathCount at this point can not be "
1967 "OverflowOccurredValue.");
1968 OldDelta -= PathCount;
1976 FirstRelease =
false;
1992 const BBState &RIPBBState = BBStates[RIP->
getParent()];
1994 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
1997 "PathCount at this point can not be "
1998 "OverflowOccurredValue.");
1999 NewDelta -= PathCount;
2002 NewReleases.
push_back(NewRetainRelease);
2007 if (NewReleases.
empty())
break;
2010 for (Instruction *NewRelease : NewReleases) {
2011 auto It = Releases.
find(NewRelease);
2013 const RRInfo &NewReleaseRRI = It->second;
2016 for (Instruction *NewReleaseRetain : NewReleaseRRI.
Calls) {
2017 auto Jt = Retains.
find(NewReleaseRetain);
2018 if (Jt == Retains.
end())
2020 const RRInfo &NewReleaseRetainRRI = Jt->second;
2027 if (!NewReleaseRetainRRI.
Calls.count(NewRelease))
2030 if (RetainsToMove.
Calls.insert(NewReleaseRetain).second) {
2033 const BBState &NRRBBState = BBStates[NewReleaseRetain->
getParent()];
2035 if (NRRBBState.GetAllPathCountWithOverflow(PathCount))
2038 "PathCount at this point can not be "
2039 "OverflowOccurredValue.");
2040 OldDelta += PathCount;
2041 OldCount += PathCount;
2049 const BBState &RIPBBState = BBStates[RIP->
getParent()];
2052 if (RIPBBState.GetAllPathCountWithOverflow(PathCount))
2055 "PathCount at this point can not be "
2056 "OverflowOccurredValue.");
2057 NewDelta += PathCount;
2058 NewCount += PathCount;
2061 NewRetains.push_back(NewReleaseRetain);
2065 if (NewRetains.empty())
break;
2069 bool UnconditionallySafe = KnownSafeTD && KnownSafeBU;
2070 if (UnconditionallySafe) {
2085 const bool WillPerformCodeMotion =
2088 if (CFGHazardAfflicted && WillPerformCodeMotion)
2101 assert(OldCount != 0 &&
"Unreachable code?");
2102 NumRRs += OldCount - NewCount;
2104 AnyPairsCompletelyEliminated = NewCount == 0;
2112bool ObjCARCOpt::PerformCodePlacement(
2113 DenseMap<const BasicBlock *, BBState> &BBStates,
2114 BlotMapVector<Value *, RRInfo> &Retains,
2115 DenseMap<Value *, RRInfo> &Releases,
Module *M) {
2116 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::PerformCodePlacement ==\n");
2118 bool AnyPairsCompletelyEliminated =
false;
2119 SmallVector<Instruction *, 8> DeadInsts;
2142 if (
const GlobalVariable *GV =
2145 if (GV->isConstant())
2150 RRInfo RetainsToMove, ReleasesToMove;
2152 bool PerformMoveCalls = PairUpRetainsAndReleases(
2153 BBStates, Retains, Releases, M,
Retain, DeadInsts,
2154 RetainsToMove, ReleasesToMove, Arg, KnownSafe,
2155 AnyPairsCompletelyEliminated);
2157 if (PerformMoveCalls) {
2160 MoveCalls(Arg, RetainsToMove, ReleasesToMove,
2161 Retains, Releases, DeadInsts, M);
2167 while (!DeadInsts.
empty())
2170 return AnyPairsCompletelyEliminated;
2174void ObjCARCOpt::OptimizeWeakCalls(
Function &
F) {
2186 if (Class != ARCInstKind::LoadWeak &&
2187 Class != ARCInstKind::LoadWeakRetained)
2191 if (Class == ARCInstKind::LoadWeak && Inst->
use_empty()) {
2208 switch (EarlierClass) {
2209 case ARCInstKind::LoadWeak:
2210 case ARCInstKind::LoadWeakRetained: {
2217 switch (PA.
getAA()->
alias(Arg, EarlierArg)) {
2221 if (Class == ARCInstKind::LoadWeakRetained) {
2222 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Retain);
2239 case ARCInstKind::StoreWeak:
2240 case ARCInstKind::InitWeak: {
2247 switch (PA.
getAA()->
alias(Arg, EarlierArg)) {
2251 if (Class == ARCInstKind::LoadWeakRetained) {
2252 Function *Decl = EP.
get(ARCRuntimeEntryPointKind::Retain);
2269 case ARCInstKind::MoveWeak:
2270 case ARCInstKind::CopyWeak:
2273 case ARCInstKind::AutoreleasepoolPush:
2274 case ARCInstKind::None:
2275 case ARCInstKind::IntrinsicUser:
2276 case ARCInstKind::User:
2292 if (Class != ARCInstKind::DestroyWeak)
2298 for (
User *U : Alloca->users()) {
2301 case ARCInstKind::InitWeak:
2302 case ARCInstKind::StoreWeak:
2303 case ARCInstKind::DestroyWeak:
2313 case ARCInstKind::InitWeak:
2314 case ARCInstKind::StoreWeak:
2318 case ARCInstKind::DestroyWeak:
2326 Alloca->eraseFromParent();
2334bool ObjCARCOpt::OptimizeSequences(
Function &
F) {
2339 DenseMap<Value *, RRInfo> Releases;
2340 BlotMapVector<Value *, RRInfo> Retains;
2344 DenseMap<const BasicBlock *, BBState> BBStates;
2347 bool NestingDetected = Visit(
F, BBStates, Retains, Releases);
2349 if (DisableRetainReleasePairing)
2353 bool AnyPairsCompletelyEliminated = PerformCodePlacement(BBStates, Retains,
2357 return AnyPairsCompletelyEliminated && NestingDetected;
2402static CallInst *FindPredecessorAutoreleaseWithSafePath(
2403 const Value *Arg, BasicBlock *BB, ReturnInst *Ret, ProvenanceAnalysis &PA) {
2426void ObjCARCOpt::OptimizeReturns(
Function &
F) {
2427 if (!
F.getReturnType()->isPointerTy())
2432 for (BasicBlock &BB:
F) {
2445 FindPredecessorAutoreleaseWithSafePath(Arg, &BB, Ret, PA);
2462 (!
Call->isTailCall() &&
2480ObjCARCOpt::GatherStatistics(
Function &
F,
bool AfterOptimization) {
2482 AfterOptimization ? NumRetainsAfterOpt : NumRetainsBeforeOpt;
2484 AfterOptimization ? NumReleasesAfterOpt : NumReleasesBeforeOpt;
2491 case ARCInstKind::Retain:
2494 case ARCInstKind::Release:
2509 MDKindCache.
init(
F.getParent());
2512 EP.
init(
F.getParent());
2515 if (
F.hasPersonalityFn() &&
2520bool ObjCARCOpt::run(
Function &
F, AAResults &AA) {
2525 BundledRetainClaimRVs BRV(EP,
false,
false);
2526 BundledInsts = &BRV;
2528 LLVM_DEBUG(
dbgs() <<
"<<< ObjCARCOpt: Visiting Function: " <<
F.getName()
2534 CFGChanged |=
R.second;
2540 GatherStatistics(
F,
false);
2549 OptimizeIndividualCalls(
F);
2552 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::LoadWeak)) |
2553 (1 <<
unsigned(ARCInstKind::LoadWeakRetained)) |
2554 (1 <<
unsigned(ARCInstKind::StoreWeak)) |
2555 (1 <<
unsigned(ARCInstKind::InitWeak)) |
2556 (1 <<
unsigned(ARCInstKind::CopyWeak)) |
2557 (1 <<
unsigned(ARCInstKind::MoveWeak)) |
2558 (1 <<
unsigned(ARCInstKind::DestroyWeak))))
2559 OptimizeWeakCalls(
F);
2562 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::Retain)) |
2563 (1 <<
unsigned(ARCInstKind::RetainRV)) |
2564 (1 <<
unsigned(ARCInstKind::RetainBlock))))
2565 if (UsedInThisFunction & (1 <<
unsigned(ARCInstKind::Release)))
2568 while (OptimizeSequences(
F)) {}
2571 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::Autorelease)) |
2572 (1 <<
unsigned(ARCInstKind::AutoreleaseRV))))
2576 if (UsedInThisFunction & ((1 <<
unsigned(ARCInstKind::AutoreleasepoolPush)) |
2577 (1 <<
unsigned(ARCInstKind::AutoreleasepoolPop))))
2578 OptimizeAutoreleasePools(
F);
2583 GatherStatistics(
F,
true);
2604 if (!Callee->hasExactDefinition())
2620 if (!PoolStack.
empty())
2630 if (PoolStack.
empty())
2632 PoolStack.
back() =
true;
2655 if (PoolStack.
empty())
2657 PoolStack.
back() =
true;
2680void ObjCARCOpt::OptimizeAutoreleasePools(
Function &
F) {
2681 LLVM_DEBUG(
dbgs() <<
"\n== ObjCARCOpt::OptimizeAutoreleasePools ==\n");
2683 OptimizationRemarkEmitter ORE(&
F);
2688 for (BasicBlock &BB :
F) {
2697 case ARCInstKind::AutoreleasepoolPush: {
2701 LLVM_DEBUG(
dbgs() <<
"Found autorelease pool push: " << *Push <<
"\n");
2705 case ARCInstKind::AutoreleasepoolPop: {
2709 if (PoolStack.
empty())
2713 CallInst *MatchingPush = PoolStack.
back().first;
2714 bool HadAutoreleaseInScope = PoolStack.
back().second;
2718 if (Pop->getArgOperand(0)->stripPointerCasts() != MatchingPush) {
2724 << *Pop->getArgOperand(0)
2725 <<
" does not match most recent push "
2726 << *MatchingPush <<
"\n");
2734 if (HadAutoreleaseInScope)
2739 return OptimizationRemark(
DEBUG_TYPE,
"AutoreleasePoolElimination",
2741 <<
"eliminated empty autorelease pool pair";
2750 Pop->eraseFromParent();
2756 case ARCInstKind::CallOrUser:
2757 case ARCInstKind::Call:
2762 case ARCInstKind::Autorelease:
2763 case ARCInstKind::AutoreleaseRV:
2764 case ARCInstKind::FusedRetainAutorelease:
2765 case ARCInstKind::FusedRetainAutoreleaseRV:
2766 case ARCInstKind::LoadWeak: {
2768 if (!PoolStack.
empty()) {
2769 PoolStack.
back().second =
true;
2772 <<
"Found autorelease or potential autorelease in pool scope: "
2779 case ARCInstKind::Retain:
2780 case ARCInstKind::RetainRV:
2781 case ARCInstKind::UnsafeClaimRV:
2782 case ARCInstKind::RetainBlock:
2783 case ARCInstKind::Release:
2784 case ARCInstKind::NoopCast:
2785 case ARCInstKind::LoadWeakRetained:
2786 case ARCInstKind::StoreWeak:
2787 case ARCInstKind::InitWeak:
2788 case ARCInstKind::MoveWeak:
2789 case ARCInstKind::CopyWeak:
2790 case ARCInstKind::DestroyWeak:
2791 case ARCInstKind::StoreStrong:
2792 case ARCInstKind::IntrinsicUser:
2793 case ARCInstKind::User:
2794 case ARCInstKind::None:
2811 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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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 MayAutorelease(const CallBase &CB, unsigned Depth=0)
Interprocedurally determine if calls made by the given call site can possibly produce autoreleases.
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)
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.
@ BasicBlock
Various leaf nodes.
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
LLVM_ABI bool IsRetain(ARCInstKind Class)
Test if the given class is objc_retain or equivalent.
@ AutoreleasePoolBoundary
@ NeedsPositiveRetainCount
LLVM_ABI bool IsNeverTail(ARCInstKind Class)
Test if the given class represents instructions which are never safe to mark with the "tail" keyword.
LLVM_ABI 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)
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI 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,...
LLVM_ABI 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...
LLVM_ABI bool IsNoopOnGlobal(ARCInstKind Class)
Test if the given class represents instructions which do nothing if passed a global variable.
LLVM_ABI 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.
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,...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
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)