10b57cec5SDimitry Andric //===- PtrState.cpp -------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "PtrState.h"
100b57cec5SDimitry Andric #include "DependencyAnalysis.h"
110b57cec5SDimitry Andric #include "ObjCARC.h"
120b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
130b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCInstKind.h"
14fe6060f1SDimitry Andric #include "llvm/Analysis/ObjCARCUtil.h"
150b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
160b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
170b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
180b57cec5SDimitry Andric #include "llvm/IR/Value.h"
190b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
200b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
210b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
220b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
240b57cec5SDimitry Andric #include <cassert>
250b57cec5SDimitry Andric #include <iterator>
260b57cec5SDimitry Andric #include <utility>
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric using namespace llvm;
290b57cec5SDimitry Andric using namespace llvm::objcarc;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric #define DEBUG_TYPE "objc-arc-ptr-state"
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
340b57cec5SDimitry Andric //                                  Utility
350b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
360b57cec5SDimitry Andric 
operator <<(raw_ostream & OS,const Sequence S)370b57cec5SDimitry Andric raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
380b57cec5SDimitry Andric   switch (S) {
390b57cec5SDimitry Andric   case S_None:
400b57cec5SDimitry Andric     return OS << "S_None";
410b57cec5SDimitry Andric   case S_Retain:
420b57cec5SDimitry Andric     return OS << "S_Retain";
430b57cec5SDimitry Andric   case S_CanRelease:
440b57cec5SDimitry Andric     return OS << "S_CanRelease";
450b57cec5SDimitry Andric   case S_Use:
460b57cec5SDimitry Andric     return OS << "S_Use";
470b57cec5SDimitry Andric   case S_MovableRelease:
480b57cec5SDimitry Andric     return OS << "S_MovableRelease";
490b57cec5SDimitry Andric   case S_Stop:
500b57cec5SDimitry Andric     return OS << "S_Stop";
510b57cec5SDimitry Andric   }
520b57cec5SDimitry Andric   llvm_unreachable("Unknown sequence type.");
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
560b57cec5SDimitry Andric //                                  Sequence
570b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
580b57cec5SDimitry Andric 
MergeSeqs(Sequence A,Sequence B,bool TopDown)590b57cec5SDimitry Andric static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
600b57cec5SDimitry Andric   // The easy cases.
610b57cec5SDimitry Andric   if (A == B)
620b57cec5SDimitry Andric     return A;
630b57cec5SDimitry Andric   if (A == S_None || B == S_None)
640b57cec5SDimitry Andric     return S_None;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   if (A > B)
670b57cec5SDimitry Andric     std::swap(A, B);
680b57cec5SDimitry Andric   if (TopDown) {
690b57cec5SDimitry Andric     // Choose the side which is further along in the sequence.
700b57cec5SDimitry Andric     if ((A == S_Retain || A == S_CanRelease) &&
710b57cec5SDimitry Andric         (B == S_CanRelease || B == S_Use))
720b57cec5SDimitry Andric       return B;
730b57cec5SDimitry Andric   } else {
740b57cec5SDimitry Andric     // Choose the side which is further along in the sequence.
750b57cec5SDimitry Andric     if ((A == S_Use || A == S_CanRelease) &&
76fe6060f1SDimitry Andric         (B == S_Use || B == S_Stop || B == S_MovableRelease))
770b57cec5SDimitry Andric       return A;
780b57cec5SDimitry Andric     // If both sides are releases, choose the more conservative one.
79fe6060f1SDimitry Andric     if (A == S_Stop && B == S_MovableRelease)
800b57cec5SDimitry Andric       return A;
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   return S_None;
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
870b57cec5SDimitry Andric //                                   RRInfo
880b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
890b57cec5SDimitry Andric 
clear()900b57cec5SDimitry Andric void RRInfo::clear() {
910b57cec5SDimitry Andric   KnownSafe = false;
920b57cec5SDimitry Andric   IsTailCallRelease = false;
930b57cec5SDimitry Andric   ReleaseMetadata = nullptr;
940b57cec5SDimitry Andric   Calls.clear();
950b57cec5SDimitry Andric   ReverseInsertPts.clear();
960b57cec5SDimitry Andric   CFGHazardAfflicted = false;
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
Merge(const RRInfo & Other)990b57cec5SDimitry Andric bool RRInfo::Merge(const RRInfo &Other) {
1000b57cec5SDimitry Andric   // Conservatively merge the ReleaseMetadata information.
1010b57cec5SDimitry Andric   if (ReleaseMetadata != Other.ReleaseMetadata)
1020b57cec5SDimitry Andric     ReleaseMetadata = nullptr;
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   // Conservatively merge the boolean state.
1050b57cec5SDimitry Andric   KnownSafe &= Other.KnownSafe;
1060b57cec5SDimitry Andric   IsTailCallRelease &= Other.IsTailCallRelease;
1070b57cec5SDimitry Andric   CFGHazardAfflicted |= Other.CFGHazardAfflicted;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // Merge the call sets.
1100b57cec5SDimitry Andric   Calls.insert(Other.Calls.begin(), Other.Calls.end());
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Merge the insert point sets. If there are any differences,
1130b57cec5SDimitry Andric   // that makes this a partial merge.
1140b57cec5SDimitry Andric   bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
1150b57cec5SDimitry Andric   for (Instruction *Inst : Other.ReverseInsertPts)
1160b57cec5SDimitry Andric     Partial |= ReverseInsertPts.insert(Inst).second;
1170b57cec5SDimitry Andric   return Partial;
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1210b57cec5SDimitry Andric //                                  PtrState
1220b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1230b57cec5SDimitry Andric 
SetKnownPositiveRefCount()1240b57cec5SDimitry Andric void PtrState::SetKnownPositiveRefCount() {
1250b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "        Setting Known Positive.\n");
1260b57cec5SDimitry Andric   KnownPositiveRefCount = true;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
ClearKnownPositiveRefCount()1290b57cec5SDimitry Andric void PtrState::ClearKnownPositiveRefCount() {
1300b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "        Clearing Known Positive.\n");
1310b57cec5SDimitry Andric   KnownPositiveRefCount = false;
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
SetSeq(Sequence NewSeq)1340b57cec5SDimitry Andric void PtrState::SetSeq(Sequence NewSeq) {
1350b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "            Old: " << GetSeq() << "; New: " << NewSeq
1360b57cec5SDimitry Andric                     << "\n");
1370b57cec5SDimitry Andric   Seq = NewSeq;
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
ResetSequenceProgress(Sequence NewSeq)1400b57cec5SDimitry Andric void PtrState::ResetSequenceProgress(Sequence NewSeq) {
1410b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "        Resetting sequence progress.\n");
1420b57cec5SDimitry Andric   SetSeq(NewSeq);
1430b57cec5SDimitry Andric   Partial = false;
1440b57cec5SDimitry Andric   RRI.clear();
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric 
Merge(const PtrState & Other,bool TopDown)1470b57cec5SDimitry Andric void PtrState::Merge(const PtrState &Other, bool TopDown) {
1480b57cec5SDimitry Andric   Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
1490b57cec5SDimitry Andric   KnownPositiveRefCount &= Other.KnownPositiveRefCount;
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   // If we're not in a sequence (anymore), drop all associated state.
1520b57cec5SDimitry Andric   if (Seq == S_None) {
1530b57cec5SDimitry Andric     Partial = false;
1540b57cec5SDimitry Andric     RRI.clear();
1550b57cec5SDimitry Andric   } else if (Partial || Other.Partial) {
1560b57cec5SDimitry Andric     // If we're doing a merge on a path that's previously seen a partial
1570b57cec5SDimitry Andric     // merge, conservatively drop the sequence, to avoid doing partial
1580b57cec5SDimitry Andric     // RR elimination. If the branch predicates for the two merge differ,
1590b57cec5SDimitry Andric     // mixing them is unsafe.
1600b57cec5SDimitry Andric     ClearSequenceProgress();
1610b57cec5SDimitry Andric   } else {
1620b57cec5SDimitry Andric     // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
1630b57cec5SDimitry Andric     // point, we know that currently we are not partial. Stash whether or not
1640b57cec5SDimitry Andric     // the merge operation caused us to undergo a partial merging of reverse
1650b57cec5SDimitry Andric     // insertion points.
1660b57cec5SDimitry Andric     Partial = RRI.Merge(Other.RRI);
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1710b57cec5SDimitry Andric //                              BottomUpPtrState
1720b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1730b57cec5SDimitry Andric 
InitBottomUp(ARCMDKindCache & Cache,Instruction * I)1740b57cec5SDimitry Andric bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
1750b57cec5SDimitry Andric   // If we see two releases in a row on the same pointer. If so, make
1760b57cec5SDimitry Andric   // a note, and we'll cicle back to revisit it after we've
1770b57cec5SDimitry Andric   // hopefully eliminated the second release, which may allow us to
1780b57cec5SDimitry Andric   // eliminate the first release too.
1790b57cec5SDimitry Andric   // Theoretically we could implement removal of nested retain+release
1800b57cec5SDimitry Andric   // pairs by making PtrState hold a stack of states, but this is
1810b57cec5SDimitry Andric   // simple and avoids adding overhead for the non-nested case.
1820b57cec5SDimitry Andric   bool NestingDetected = false;
183fe6060f1SDimitry Andric   if (GetSeq() == S_MovableRelease) {
1840b57cec5SDimitry Andric     LLVM_DEBUG(
1850b57cec5SDimitry Andric         dbgs() << "        Found nested releases (i.e. a release pair)\n");
1860b57cec5SDimitry Andric     NestingDetected = true;
1870b57cec5SDimitry Andric   }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric   MDNode *ReleaseMetadata =
1900b57cec5SDimitry Andric       I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
191fe6060f1SDimitry Andric   Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Stop;
1920b57cec5SDimitry Andric   ResetSequenceProgress(NewSeq);
193fe6060f1SDimitry Andric   if (NewSeq == S_Stop)
194fe6060f1SDimitry Andric     InsertReverseInsertPt(I);
1950b57cec5SDimitry Andric   SetReleaseMetadata(ReleaseMetadata);
1960b57cec5SDimitry Andric   SetKnownSafe(HasKnownPositiveRefCount());
1970b57cec5SDimitry Andric   SetTailCallRelease(cast<CallInst>(I)->isTailCall());
1980b57cec5SDimitry Andric   InsertCall(I);
1990b57cec5SDimitry Andric   SetKnownPositiveRefCount();
2000b57cec5SDimitry Andric   return NestingDetected;
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric 
MatchWithRetain()2030b57cec5SDimitry Andric bool BottomUpPtrState::MatchWithRetain() {
2040b57cec5SDimitry Andric   SetKnownPositiveRefCount();
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   Sequence OldSeq = GetSeq();
2070b57cec5SDimitry Andric   switch (OldSeq) {
2080b57cec5SDimitry Andric   case S_Stop:
2090b57cec5SDimitry Andric   case S_MovableRelease:
2100b57cec5SDimitry Andric   case S_Use:
2110b57cec5SDimitry Andric     // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
2120b57cec5SDimitry Andric     // imprecise release, clear our reverse insertion points.
2130b57cec5SDimitry Andric     if (OldSeq != S_Use || IsTrackingImpreciseReleases())
2140b57cec5SDimitry Andric       ClearReverseInsertPts();
215bdd1243dSDimitry Andric     [[fallthrough]];
2160b57cec5SDimitry Andric   case S_CanRelease:
2170b57cec5SDimitry Andric     return true;
2180b57cec5SDimitry Andric   case S_None:
2190b57cec5SDimitry Andric     return false;
2200b57cec5SDimitry Andric   case S_Retain:
2210b57cec5SDimitry Andric     llvm_unreachable("bottom-up pointer in retain state!");
2220b57cec5SDimitry Andric   }
2230b57cec5SDimitry Andric   llvm_unreachable("Sequence unknown enum value");
2240b57cec5SDimitry Andric }
2250b57cec5SDimitry Andric 
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)2260b57cec5SDimitry Andric bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
2270b57cec5SDimitry Andric                                                     const Value *Ptr,
2280b57cec5SDimitry Andric                                                     ProvenanceAnalysis &PA,
2290b57cec5SDimitry Andric                                                     ARCInstKind Class) {
2300b57cec5SDimitry Andric   Sequence S = GetSeq();
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // Check for possible releases.
233e8d8bef9SDimitry Andric   if (!CanDecrementRefCount(Inst, Ptr, PA, Class))
2340b57cec5SDimitry Andric     return false;
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "            CanAlterRefCount: Seq: " << S << "; "
2370b57cec5SDimitry Andric                     << *Ptr << "\n");
2380b57cec5SDimitry Andric   switch (S) {
2390b57cec5SDimitry Andric   case S_Use:
2400b57cec5SDimitry Andric     SetSeq(S_CanRelease);
2410b57cec5SDimitry Andric     return true;
2420b57cec5SDimitry Andric   case S_CanRelease:
2430b57cec5SDimitry Andric   case S_MovableRelease:
2440b57cec5SDimitry Andric   case S_Stop:
2450b57cec5SDimitry Andric   case S_None:
2460b57cec5SDimitry Andric     return false;
2470b57cec5SDimitry Andric   case S_Retain:
2480b57cec5SDimitry Andric     llvm_unreachable("bottom-up pointer in retain state!");
2490b57cec5SDimitry Andric   }
2500b57cec5SDimitry Andric   llvm_unreachable("Sequence unknown enum value");
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
HandlePotentialUse(BasicBlock * BB,Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)2530b57cec5SDimitry Andric void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
2540b57cec5SDimitry Andric                                           const Value *Ptr,
2550b57cec5SDimitry Andric                                           ProvenanceAnalysis &PA,
2560b57cec5SDimitry Andric                                           ARCInstKind Class) {
2570b57cec5SDimitry Andric   auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
2580b57cec5SDimitry Andric     assert(!HasReverseInsertPts());
2590b57cec5SDimitry Andric     SetSeq(NewSeq);
2600b57cec5SDimitry Andric     // If this is an invoke instruction, we're scanning it as part of
2610b57cec5SDimitry Andric     // one of its successor blocks, since we can't insert code after it
2620b57cec5SDimitry Andric     // in its own block, and we don't want to split critical edges.
2630b57cec5SDimitry Andric     BasicBlock::iterator InsertAfter;
2640b57cec5SDimitry Andric     if (isa<InvokeInst>(Inst)) {
2650b57cec5SDimitry Andric       const auto IP = BB->getFirstInsertionPt();
2660b57cec5SDimitry Andric       InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP;
2670b57cec5SDimitry Andric       if (isa<CatchSwitchInst>(InsertAfter))
2680b57cec5SDimitry Andric         // A catchswitch must be the only non-phi instruction in its basic
2690b57cec5SDimitry Andric         // block, so attempting to insert an instruction into such a block would
2700b57cec5SDimitry Andric         // produce invalid IR.
2710b57cec5SDimitry Andric         SetCFGHazardAfflicted(true);
2720b57cec5SDimitry Andric     } else {
2730b57cec5SDimitry Andric       InsertAfter = std::next(Inst->getIterator());
2740b57cec5SDimitry Andric     }
2758bcb0991SDimitry Andric 
2768bcb0991SDimitry Andric     if (InsertAfter != BB->end())
2778bcb0991SDimitry Andric       InsertAfter = skipDebugIntrinsics(InsertAfter);
2788bcb0991SDimitry Andric 
2790b57cec5SDimitry Andric     InsertReverseInsertPt(&*InsertAfter);
280fe6060f1SDimitry Andric 
281fe6060f1SDimitry Andric     // Don't insert anything between a call/invoke with operand bundle
282fe6060f1SDimitry Andric     // "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
283fe6060f1SDimitry Andric     // result.
284fe6060f1SDimitry Andric     if (auto *CB = dyn_cast<CallBase>(Inst))
285fe6060f1SDimitry Andric       if (objcarc::hasAttachedCallOpBundle(CB))
286fe6060f1SDimitry Andric         SetCFGHazardAfflicted(true);
2870b57cec5SDimitry Andric   };
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   // Check for possible direct uses.
2900b57cec5SDimitry Andric   switch (GetSeq()) {
2910b57cec5SDimitry Andric   case S_MovableRelease:
2920b57cec5SDimitry Andric     if (CanUse(Inst, Ptr, PA, Class)) {
2930b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "            CanUse: Seq: " << GetSeq() << "; "
2940b57cec5SDimitry Andric                         << *Ptr << "\n");
2950b57cec5SDimitry Andric       SetSeqAndInsertReverseInsertPt(S_Use);
2960b57cec5SDimitry Andric     } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
2970b57cec5SDimitry Andric       if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
2980b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "            ReleaseUse: Seq: " << GetSeq() << "; "
2990b57cec5SDimitry Andric                           << *Ptr << "\n");
3000b57cec5SDimitry Andric         SetSeqAndInsertReverseInsertPt(S_Stop);
3010b57cec5SDimitry Andric       }
3020b57cec5SDimitry Andric     }
3030b57cec5SDimitry Andric     break;
3040b57cec5SDimitry Andric   case S_Stop:
3050b57cec5SDimitry Andric     if (CanUse(Inst, Ptr, PA, Class)) {
3060b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "            PreciseStopUse: Seq: " << GetSeq()
3070b57cec5SDimitry Andric                         << "; " << *Ptr << "\n");
3080b57cec5SDimitry Andric       SetSeq(S_Use);
3090b57cec5SDimitry Andric     }
3100b57cec5SDimitry Andric     break;
3110b57cec5SDimitry Andric   case S_CanRelease:
3120b57cec5SDimitry Andric   case S_Use:
3130b57cec5SDimitry Andric   case S_None:
3140b57cec5SDimitry Andric     break;
3150b57cec5SDimitry Andric   case S_Retain:
3160b57cec5SDimitry Andric     llvm_unreachable("bottom-up pointer in retain state!");
3170b57cec5SDimitry Andric   }
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3210b57cec5SDimitry Andric //                              TopDownPtrState
3220b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3230b57cec5SDimitry Andric 
InitTopDown(ARCInstKind Kind,Instruction * I)3240b57cec5SDimitry Andric bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
3250b57cec5SDimitry Andric   bool NestingDetected = false;
3260b57cec5SDimitry Andric   // Don't do retain+release tracking for ARCInstKind::RetainRV, because
3270b57cec5SDimitry Andric   // it's
3280b57cec5SDimitry Andric   // better to let it remain as the first instruction after a call.
3290b57cec5SDimitry Andric   if (Kind != ARCInstKind::RetainRV) {
3300b57cec5SDimitry Andric     // If we see two retains in a row on the same pointer. If so, make
3310b57cec5SDimitry Andric     // a note, and we'll cicle back to revisit it after we've
3320b57cec5SDimitry Andric     // hopefully eliminated the second retain, which may allow us to
3330b57cec5SDimitry Andric     // eliminate the first retain too.
3340b57cec5SDimitry Andric     // Theoretically we could implement removal of nested retain+release
3350b57cec5SDimitry Andric     // pairs by making PtrState hold a stack of states, but this is
3360b57cec5SDimitry Andric     // simple and avoids adding overhead for the non-nested case.
3370b57cec5SDimitry Andric     if (GetSeq() == S_Retain)
3380b57cec5SDimitry Andric       NestingDetected = true;
3390b57cec5SDimitry Andric 
3400b57cec5SDimitry Andric     ResetSequenceProgress(S_Retain);
3410b57cec5SDimitry Andric     SetKnownSafe(HasKnownPositiveRefCount());
3420b57cec5SDimitry Andric     InsertCall(I);
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   SetKnownPositiveRefCount();
3460b57cec5SDimitry Andric   return NestingDetected;
3470b57cec5SDimitry Andric }
3480b57cec5SDimitry Andric 
MatchWithRelease(ARCMDKindCache & Cache,Instruction * Release)3490b57cec5SDimitry Andric bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
3500b57cec5SDimitry Andric                                        Instruction *Release) {
3510b57cec5SDimitry Andric   ClearKnownPositiveRefCount();
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric   Sequence OldSeq = GetSeq();
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric   MDNode *ReleaseMetadata =
3560b57cec5SDimitry Andric       Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric   switch (OldSeq) {
3590b57cec5SDimitry Andric   case S_Retain:
3600b57cec5SDimitry Andric   case S_CanRelease:
3610b57cec5SDimitry Andric     if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
3620b57cec5SDimitry Andric       ClearReverseInsertPts();
363bdd1243dSDimitry Andric     [[fallthrough]];
3640b57cec5SDimitry Andric   case S_Use:
3650b57cec5SDimitry Andric     SetReleaseMetadata(ReleaseMetadata);
3660b57cec5SDimitry Andric     SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
3670b57cec5SDimitry Andric     return true;
3680b57cec5SDimitry Andric   case S_None:
3690b57cec5SDimitry Andric     return false;
3700b57cec5SDimitry Andric   case S_Stop:
3710b57cec5SDimitry Andric   case S_MovableRelease:
3720b57cec5SDimitry Andric     llvm_unreachable("top-down pointer in bottom up state!");
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric   llvm_unreachable("Sequence unknown enum value");
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric 
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class,const BundledRetainClaimRVs & BundledRVs)377fe6060f1SDimitry Andric bool TopDownPtrState::HandlePotentialAlterRefCount(
378fe6060f1SDimitry Andric     Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA,
379fe6060f1SDimitry Andric     ARCInstKind Class, const BundledRetainClaimRVs &BundledRVs) {
3800b57cec5SDimitry Andric   // Check for possible releases. Treat clang.arc.use as a releasing instruction
3810b57cec5SDimitry Andric   // to prevent sinking a retain past it.
382e8d8bef9SDimitry Andric   if (!CanDecrementRefCount(Inst, Ptr, PA, Class) &&
3830b57cec5SDimitry Andric       Class != ARCInstKind::IntrinsicUser)
3840b57cec5SDimitry Andric     return false;
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "            CanAlterRefCount: Seq: " << GetSeq() << "; "
3870b57cec5SDimitry Andric                     << *Ptr << "\n");
3880b57cec5SDimitry Andric   ClearKnownPositiveRefCount();
3890b57cec5SDimitry Andric   switch (GetSeq()) {
3900b57cec5SDimitry Andric   case S_Retain:
3910b57cec5SDimitry Andric     SetSeq(S_CanRelease);
3920b57cec5SDimitry Andric     assert(!HasReverseInsertPts());
3930b57cec5SDimitry Andric     InsertReverseInsertPt(Inst);
3940b57cec5SDimitry Andric 
395fe6060f1SDimitry Andric     // Don't insert anything between a call/invoke with operand bundle
396fe6060f1SDimitry Andric     // "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
397fe6060f1SDimitry Andric     // result.
398fe6060f1SDimitry Andric     if (BundledRVs.contains(Inst))
399fe6060f1SDimitry Andric       SetCFGHazardAfflicted(true);
400fe6060f1SDimitry Andric 
4010b57cec5SDimitry Andric     // One call can't cause a transition from S_Retain to S_CanRelease
4020b57cec5SDimitry Andric     // and S_CanRelease to S_Use. If we've made the first transition,
4030b57cec5SDimitry Andric     // we're done.
4040b57cec5SDimitry Andric     return true;
4050b57cec5SDimitry Andric   case S_Use:
4060b57cec5SDimitry Andric   case S_CanRelease:
4070b57cec5SDimitry Andric   case S_None:
4080b57cec5SDimitry Andric     return false;
4090b57cec5SDimitry Andric   case S_Stop:
4100b57cec5SDimitry Andric   case S_MovableRelease:
4110b57cec5SDimitry Andric     llvm_unreachable("top-down pointer in release state!");
4120b57cec5SDimitry Andric   }
4130b57cec5SDimitry Andric   llvm_unreachable("covered switch is not covered!?");
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric 
HandlePotentialUse(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)4160b57cec5SDimitry Andric void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
4170b57cec5SDimitry Andric                                          ProvenanceAnalysis &PA,
4180b57cec5SDimitry Andric                                          ARCInstKind Class) {
4190b57cec5SDimitry Andric   // Check for possible direct uses.
4200b57cec5SDimitry Andric   switch (GetSeq()) {
4210b57cec5SDimitry Andric   case S_CanRelease:
4220b57cec5SDimitry Andric     if (!CanUse(Inst, Ptr, PA, Class))
4230b57cec5SDimitry Andric       return;
4240b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "             CanUse: Seq: " << GetSeq() << "; "
4250b57cec5SDimitry Andric                       << *Ptr << "\n");
4260b57cec5SDimitry Andric     SetSeq(S_Use);
4270b57cec5SDimitry Andric     return;
4280b57cec5SDimitry Andric   case S_Retain:
4290b57cec5SDimitry Andric   case S_Use:
4300b57cec5SDimitry Andric   case S_None:
4310b57cec5SDimitry Andric     return;
4320b57cec5SDimitry Andric   case S_Stop:
4330b57cec5SDimitry Andric   case S_MovableRelease:
4340b57cec5SDimitry Andric     llvm_unreachable("top-down pointer in release state!");
4350b57cec5SDimitry Andric   }
4360b57cec5SDimitry Andric }
437