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