1*0b57cec5SDimitry Andric //===- PtrState.cpp -------------------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric
9*0b57cec5SDimitry Andric #include "PtrState.h"
10*0b57cec5SDimitry Andric #include "DependencyAnalysis.h"
11*0b57cec5SDimitry Andric #include "ObjCARC.h"
12*0b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
13*0b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCInstKind.h"
14*0b57cec5SDimitry Andric #include "llvm/Analysis/ObjCARCUtil.h"
15*0b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
16*0b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
17*0b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
18*0b57cec5SDimitry Andric #include "llvm/IR/Value.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
21*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
22*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
23*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
24*0b57cec5SDimitry Andric #include <cassert>
25*0b57cec5SDimitry Andric #include <iterator>
26*0b57cec5SDimitry Andric #include <utility>
27*0b57cec5SDimitry Andric
28*0b57cec5SDimitry Andric using namespace llvm;
29*0b57cec5SDimitry Andric using namespace llvm::objcarc;
30*0b57cec5SDimitry Andric
31*0b57cec5SDimitry Andric #define DEBUG_TYPE "objc-arc-ptr-state"
32*0b57cec5SDimitry Andric
33*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
34*0b57cec5SDimitry Andric // Utility
35*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
36*0b57cec5SDimitry Andric
operator <<(raw_ostream & OS,const Sequence S)37*0b57cec5SDimitry Andric raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
38*0b57cec5SDimitry Andric switch (S) {
39*0b57cec5SDimitry Andric case S_None:
40*0b57cec5SDimitry Andric return OS << "S_None";
41*0b57cec5SDimitry Andric case S_Retain:
42*0b57cec5SDimitry Andric return OS << "S_Retain";
43*0b57cec5SDimitry Andric case S_CanRelease:
44*0b57cec5SDimitry Andric return OS << "S_CanRelease";
45*0b57cec5SDimitry Andric case S_Use:
46*0b57cec5SDimitry Andric return OS << "S_Use";
47*0b57cec5SDimitry Andric case S_MovableRelease:
48*0b57cec5SDimitry Andric return OS << "S_MovableRelease";
49*0b57cec5SDimitry Andric case S_Stop:
50*0b57cec5SDimitry Andric return OS << "S_Stop";
51*0b57cec5SDimitry Andric }
52*0b57cec5SDimitry Andric llvm_unreachable("Unknown sequence type.");
53*0b57cec5SDimitry Andric }
54*0b57cec5SDimitry Andric
55*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
56*0b57cec5SDimitry Andric // Sequence
57*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
58*0b57cec5SDimitry Andric
MergeSeqs(Sequence A,Sequence B,bool TopDown)59*0b57cec5SDimitry Andric static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
60*0b57cec5SDimitry Andric // The easy cases.
61*0b57cec5SDimitry Andric if (A == B)
62*0b57cec5SDimitry Andric return A;
63*0b57cec5SDimitry Andric if (A == S_None || B == S_None)
64*0b57cec5SDimitry Andric return S_None;
65*0b57cec5SDimitry Andric
66*0b57cec5SDimitry Andric if (A > B)
67*0b57cec5SDimitry Andric std::swap(A, B);
68*0b57cec5SDimitry Andric if (TopDown) {
69*0b57cec5SDimitry Andric // Choose the side which is further along in the sequence.
70*0b57cec5SDimitry Andric if ((A == S_Retain || A == S_CanRelease) &&
71*0b57cec5SDimitry Andric (B == S_CanRelease || B == S_Use))
72*0b57cec5SDimitry Andric return B;
73*0b57cec5SDimitry Andric } else {
74*0b57cec5SDimitry Andric // Choose the side which is further along in the sequence.
75*0b57cec5SDimitry Andric if ((A == S_Use || A == S_CanRelease) &&
76*0b57cec5SDimitry Andric (B == S_Use || B == S_Stop || B == S_MovableRelease))
77*0b57cec5SDimitry Andric return A;
78*0b57cec5SDimitry Andric // If both sides are releases, choose the more conservative one.
79*0b57cec5SDimitry Andric if (A == S_Stop && B == S_MovableRelease)
80*0b57cec5SDimitry Andric return A;
81*0b57cec5SDimitry Andric }
82*0b57cec5SDimitry Andric
83*0b57cec5SDimitry Andric return S_None;
84*0b57cec5SDimitry Andric }
85*0b57cec5SDimitry Andric
86*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
87*0b57cec5SDimitry Andric // RRInfo
88*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
89*0b57cec5SDimitry Andric
clear()90*0b57cec5SDimitry Andric void RRInfo::clear() {
91*0b57cec5SDimitry Andric KnownSafe = false;
92*0b57cec5SDimitry Andric IsTailCallRelease = false;
93*0b57cec5SDimitry Andric ReleaseMetadata = nullptr;
94*0b57cec5SDimitry Andric Calls.clear();
95*0b57cec5SDimitry Andric ReverseInsertPts.clear();
96*0b57cec5SDimitry Andric CFGHazardAfflicted = false;
97*0b57cec5SDimitry Andric }
98*0b57cec5SDimitry Andric
Merge(const RRInfo & Other)99*0b57cec5SDimitry Andric bool RRInfo::Merge(const RRInfo &Other) {
100*0b57cec5SDimitry Andric // Conservatively merge the ReleaseMetadata information.
101*0b57cec5SDimitry Andric if (ReleaseMetadata != Other.ReleaseMetadata)
102*0b57cec5SDimitry Andric ReleaseMetadata = nullptr;
103*0b57cec5SDimitry Andric
104*0b57cec5SDimitry Andric // Conservatively merge the boolean state.
105*0b57cec5SDimitry Andric KnownSafe &= Other.KnownSafe;
106*0b57cec5SDimitry Andric IsTailCallRelease &= Other.IsTailCallRelease;
107*0b57cec5SDimitry Andric CFGHazardAfflicted |= Other.CFGHazardAfflicted;
108*0b57cec5SDimitry Andric
109*0b57cec5SDimitry Andric // Merge the call sets.
110*0b57cec5SDimitry Andric Calls.insert(Other.Calls.begin(), Other.Calls.end());
111*0b57cec5SDimitry Andric
112*0b57cec5SDimitry Andric // Merge the insert point sets. If there are any differences,
113*0b57cec5SDimitry Andric // that makes this a partial merge.
114*0b57cec5SDimitry Andric bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
115*0b57cec5SDimitry Andric for (Instruction *Inst : Other.ReverseInsertPts)
116*0b57cec5SDimitry Andric Partial |= ReverseInsertPts.insert(Inst).second;
117*0b57cec5SDimitry Andric return Partial;
118*0b57cec5SDimitry Andric }
119*0b57cec5SDimitry Andric
120*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
121*0b57cec5SDimitry Andric // PtrState
122*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
123*0b57cec5SDimitry Andric
SetKnownPositiveRefCount()124*0b57cec5SDimitry Andric void PtrState::SetKnownPositiveRefCount() {
125*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Setting Known Positive.\n");
126*0b57cec5SDimitry Andric KnownPositiveRefCount = true;
127*0b57cec5SDimitry Andric }
128*0b57cec5SDimitry Andric
ClearKnownPositiveRefCount()129*0b57cec5SDimitry Andric void PtrState::ClearKnownPositiveRefCount() {
130*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n");
131*0b57cec5SDimitry Andric KnownPositiveRefCount = false;
132*0b57cec5SDimitry Andric }
133*0b57cec5SDimitry Andric
SetSeq(Sequence NewSeq)134*0b57cec5SDimitry Andric void PtrState::SetSeq(Sequence NewSeq) {
135*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq
136*0b57cec5SDimitry Andric << "\n");
137*0b57cec5SDimitry Andric Seq = NewSeq;
138*0b57cec5SDimitry Andric }
139*0b57cec5SDimitry Andric
ResetSequenceProgress(Sequence NewSeq)140*0b57cec5SDimitry Andric void PtrState::ResetSequenceProgress(Sequence NewSeq) {
141*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Resetting sequence progress.\n");
142*0b57cec5SDimitry Andric SetSeq(NewSeq);
143*0b57cec5SDimitry Andric Partial = false;
144*0b57cec5SDimitry Andric RRI.clear();
145*0b57cec5SDimitry Andric }
146*0b57cec5SDimitry Andric
Merge(const PtrState & Other,bool TopDown)147*0b57cec5SDimitry Andric void PtrState::Merge(const PtrState &Other, bool TopDown) {
148*0b57cec5SDimitry Andric Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
149*0b57cec5SDimitry Andric KnownPositiveRefCount &= Other.KnownPositiveRefCount;
150*0b57cec5SDimitry Andric
151*0b57cec5SDimitry Andric // If we're not in a sequence (anymore), drop all associated state.
152*0b57cec5SDimitry Andric if (Seq == S_None) {
153*0b57cec5SDimitry Andric Partial = false;
154*0b57cec5SDimitry Andric RRI.clear();
155*0b57cec5SDimitry Andric } else if (Partial || Other.Partial) {
156*0b57cec5SDimitry Andric // If we're doing a merge on a path that's previously seen a partial
157*0b57cec5SDimitry Andric // merge, conservatively drop the sequence, to avoid doing partial
158*0b57cec5SDimitry Andric // RR elimination. If the branch predicates for the two merge differ,
159*0b57cec5SDimitry Andric // mixing them is unsafe.
160*0b57cec5SDimitry Andric ClearSequenceProgress();
161*0b57cec5SDimitry Andric } else {
162*0b57cec5SDimitry Andric // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
163*0b57cec5SDimitry Andric // point, we know that currently we are not partial. Stash whether or not
164*0b57cec5SDimitry Andric // the merge operation caused us to undergo a partial merging of reverse
165*0b57cec5SDimitry Andric // insertion points.
166*0b57cec5SDimitry Andric Partial = RRI.Merge(Other.RRI);
167*0b57cec5SDimitry Andric }
168*0b57cec5SDimitry Andric }
169*0b57cec5SDimitry Andric
170*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
171*0b57cec5SDimitry Andric // BottomUpPtrState
172*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
173*0b57cec5SDimitry Andric
InitBottomUp(ARCMDKindCache & Cache,Instruction * I)174*0b57cec5SDimitry Andric bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
175*0b57cec5SDimitry Andric // If we see two releases in a row on the same pointer. If so, make
176*0b57cec5SDimitry Andric // a note, and we'll cicle back to revisit it after we've
177*0b57cec5SDimitry Andric // hopefully eliminated the second release, which may allow us to
178*0b57cec5SDimitry Andric // eliminate the first release too.
179*0b57cec5SDimitry Andric // Theoretically we could implement removal of nested retain+release
180*0b57cec5SDimitry Andric // pairs by making PtrState hold a stack of states, but this is
181*0b57cec5SDimitry Andric // simple and avoids adding overhead for the non-nested case.
182*0b57cec5SDimitry Andric bool NestingDetected = false;
183*0b57cec5SDimitry Andric if (GetSeq() == S_MovableRelease) {
184*0b57cec5SDimitry Andric LLVM_DEBUG(
185*0b57cec5SDimitry Andric dbgs() << " Found nested releases (i.e. a release pair)\n");
186*0b57cec5SDimitry Andric NestingDetected = true;
187*0b57cec5SDimitry Andric }
188*0b57cec5SDimitry Andric
189*0b57cec5SDimitry Andric MDNode *ReleaseMetadata =
190*0b57cec5SDimitry Andric I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
191*0b57cec5SDimitry Andric Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Stop;
192*0b57cec5SDimitry Andric ResetSequenceProgress(NewSeq);
193*0b57cec5SDimitry Andric if (NewSeq == S_Stop)
194*0b57cec5SDimitry Andric InsertReverseInsertPt(I);
195*0b57cec5SDimitry Andric SetReleaseMetadata(ReleaseMetadata);
196*0b57cec5SDimitry Andric SetKnownSafe(HasKnownPositiveRefCount());
197*0b57cec5SDimitry Andric SetTailCallRelease(cast<CallInst>(I)->isTailCall());
198*0b57cec5SDimitry Andric InsertCall(I);
199*0b57cec5SDimitry Andric SetKnownPositiveRefCount();
200*0b57cec5SDimitry Andric return NestingDetected;
201*0b57cec5SDimitry Andric }
202*0b57cec5SDimitry Andric
MatchWithRetain()203*0b57cec5SDimitry Andric bool BottomUpPtrState::MatchWithRetain() {
204*0b57cec5SDimitry Andric SetKnownPositiveRefCount();
205*0b57cec5SDimitry Andric
206*0b57cec5SDimitry Andric Sequence OldSeq = GetSeq();
207*0b57cec5SDimitry Andric switch (OldSeq) {
208*0b57cec5SDimitry Andric case S_Stop:
209*0b57cec5SDimitry Andric case S_MovableRelease:
210*0b57cec5SDimitry Andric case S_Use:
211*0b57cec5SDimitry Andric // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
212*0b57cec5SDimitry Andric // imprecise release, clear our reverse insertion points.
213*0b57cec5SDimitry Andric if (OldSeq != S_Use || IsTrackingImpreciseReleases())
214*0b57cec5SDimitry Andric ClearReverseInsertPts();
215*0b57cec5SDimitry Andric [[fallthrough]];
216*0b57cec5SDimitry Andric case S_CanRelease:
217*0b57cec5SDimitry Andric return true;
218*0b57cec5SDimitry Andric case S_None:
219*0b57cec5SDimitry Andric return false;
220*0b57cec5SDimitry Andric case S_Retain:
221*0b57cec5SDimitry Andric llvm_unreachable("bottom-up pointer in retain state!");
222*0b57cec5SDimitry Andric }
223*0b57cec5SDimitry Andric llvm_unreachable("Sequence unknown enum value");
224*0b57cec5SDimitry Andric }
225*0b57cec5SDimitry Andric
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)226*0b57cec5SDimitry Andric bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
227*0b57cec5SDimitry Andric const Value *Ptr,
228*0b57cec5SDimitry Andric ProvenanceAnalysis &PA,
229*0b57cec5SDimitry Andric ARCInstKind Class) {
230*0b57cec5SDimitry Andric Sequence S = GetSeq();
231*0b57cec5SDimitry Andric
232*0b57cec5SDimitry Andric // Check for possible releases.
233*0b57cec5SDimitry Andric if (!CanDecrementRefCount(Inst, Ptr, PA, Class))
234*0b57cec5SDimitry Andric return false;
235*0b57cec5SDimitry Andric
236*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; "
237*0b57cec5SDimitry Andric << *Ptr << "\n");
238*0b57cec5SDimitry Andric switch (S) {
239*0b57cec5SDimitry Andric case S_Use:
240*0b57cec5SDimitry Andric SetSeq(S_CanRelease);
241*0b57cec5SDimitry Andric return true;
242*0b57cec5SDimitry Andric case S_CanRelease:
243*0b57cec5SDimitry Andric case S_MovableRelease:
244*0b57cec5SDimitry Andric case S_Stop:
245*0b57cec5SDimitry Andric case S_None:
246*0b57cec5SDimitry Andric return false;
247*0b57cec5SDimitry Andric case S_Retain:
248*0b57cec5SDimitry Andric llvm_unreachable("bottom-up pointer in retain state!");
249*0b57cec5SDimitry Andric }
250*0b57cec5SDimitry Andric llvm_unreachable("Sequence unknown enum value");
251*0b57cec5SDimitry Andric }
252*0b57cec5SDimitry Andric
HandlePotentialUse(BasicBlock * BB,Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)253*0b57cec5SDimitry Andric void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
254*0b57cec5SDimitry Andric const Value *Ptr,
255*0b57cec5SDimitry Andric ProvenanceAnalysis &PA,
256*0b57cec5SDimitry Andric ARCInstKind Class) {
257*0b57cec5SDimitry Andric auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
258*0b57cec5SDimitry Andric assert(!HasReverseInsertPts());
259*0b57cec5SDimitry Andric SetSeq(NewSeq);
260*0b57cec5SDimitry Andric // If this is an invoke instruction, we're scanning it as part of
261*0b57cec5SDimitry Andric // one of its successor blocks, since we can't insert code after it
262*0b57cec5SDimitry Andric // in its own block, and we don't want to split critical edges.
263*0b57cec5SDimitry Andric BasicBlock::iterator InsertAfter;
264*0b57cec5SDimitry Andric if (isa<InvokeInst>(Inst)) {
265*0b57cec5SDimitry Andric const auto IP = BB->getFirstInsertionPt();
266*0b57cec5SDimitry Andric InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP;
267*0b57cec5SDimitry Andric if (isa<CatchSwitchInst>(InsertAfter))
268*0b57cec5SDimitry Andric // A catchswitch must be the only non-phi instruction in its basic
269*0b57cec5SDimitry Andric // block, so attempting to insert an instruction into such a block would
270*0b57cec5SDimitry Andric // produce invalid IR.
271*0b57cec5SDimitry Andric SetCFGHazardAfflicted(true);
272*0b57cec5SDimitry Andric } else {
273*0b57cec5SDimitry Andric InsertAfter = std::next(Inst->getIterator());
274*0b57cec5SDimitry Andric }
275*0b57cec5SDimitry Andric
276*0b57cec5SDimitry Andric if (InsertAfter != BB->end())
277*0b57cec5SDimitry Andric InsertAfter = skipDebugIntrinsics(InsertAfter);
278*0b57cec5SDimitry Andric
279*0b57cec5SDimitry Andric InsertReverseInsertPt(&*InsertAfter);
280*0b57cec5SDimitry Andric
281*0b57cec5SDimitry Andric // Don't insert anything between a call/invoke with operand bundle
282*0b57cec5SDimitry Andric // "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
283*0b57cec5SDimitry Andric // result.
284*0b57cec5SDimitry Andric if (auto *CB = dyn_cast<CallBase>(Inst))
285*0b57cec5SDimitry Andric if (objcarc::hasAttachedCallOpBundle(CB))
286*0b57cec5SDimitry Andric SetCFGHazardAfflicted(true);
287*0b57cec5SDimitry Andric };
288*0b57cec5SDimitry Andric
289*0b57cec5SDimitry Andric // Check for possible direct uses.
290*0b57cec5SDimitry Andric switch (GetSeq()) {
291*0b57cec5SDimitry Andric case S_MovableRelease:
292*0b57cec5SDimitry Andric if (CanUse(Inst, Ptr, PA, Class)) {
293*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
294*0b57cec5SDimitry Andric << *Ptr << "\n");
295*0b57cec5SDimitry Andric SetSeqAndInsertReverseInsertPt(S_Use);
296*0b57cec5SDimitry Andric } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
297*0b57cec5SDimitry Andric if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
298*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
299*0b57cec5SDimitry Andric << *Ptr << "\n");
300*0b57cec5SDimitry Andric SetSeqAndInsertReverseInsertPt(S_Stop);
301*0b57cec5SDimitry Andric }
302*0b57cec5SDimitry Andric }
303*0b57cec5SDimitry Andric break;
304*0b57cec5SDimitry Andric case S_Stop:
305*0b57cec5SDimitry Andric if (CanUse(Inst, Ptr, PA, Class)) {
306*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq()
307*0b57cec5SDimitry Andric << "; " << *Ptr << "\n");
308*0b57cec5SDimitry Andric SetSeq(S_Use);
309*0b57cec5SDimitry Andric }
310*0b57cec5SDimitry Andric break;
311*0b57cec5SDimitry Andric case S_CanRelease:
312*0b57cec5SDimitry Andric case S_Use:
313*0b57cec5SDimitry Andric case S_None:
314*0b57cec5SDimitry Andric break;
315*0b57cec5SDimitry Andric case S_Retain:
316*0b57cec5SDimitry Andric llvm_unreachable("bottom-up pointer in retain state!");
317*0b57cec5SDimitry Andric }
318*0b57cec5SDimitry Andric }
319*0b57cec5SDimitry Andric
320*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
321*0b57cec5SDimitry Andric // TopDownPtrState
322*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
323*0b57cec5SDimitry Andric
InitTopDown(ARCInstKind Kind,Instruction * I)324*0b57cec5SDimitry Andric bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
325*0b57cec5SDimitry Andric bool NestingDetected = false;
326*0b57cec5SDimitry Andric // Don't do retain+release tracking for ARCInstKind::RetainRV, because
327*0b57cec5SDimitry Andric // it's
328*0b57cec5SDimitry Andric // better to let it remain as the first instruction after a call.
329*0b57cec5SDimitry Andric if (Kind != ARCInstKind::RetainRV) {
330*0b57cec5SDimitry Andric // If we see two retains in a row on the same pointer. If so, make
331*0b57cec5SDimitry Andric // a note, and we'll cicle back to revisit it after we've
332*0b57cec5SDimitry Andric // hopefully eliminated the second retain, which may allow us to
333*0b57cec5SDimitry Andric // eliminate the first retain too.
334*0b57cec5SDimitry Andric // Theoretically we could implement removal of nested retain+release
335*0b57cec5SDimitry Andric // pairs by making PtrState hold a stack of states, but this is
336*0b57cec5SDimitry Andric // simple and avoids adding overhead for the non-nested case.
337*0b57cec5SDimitry Andric if (GetSeq() == S_Retain)
338*0b57cec5SDimitry Andric NestingDetected = true;
339*0b57cec5SDimitry Andric
340*0b57cec5SDimitry Andric ResetSequenceProgress(S_Retain);
341*0b57cec5SDimitry Andric SetKnownSafe(HasKnownPositiveRefCount());
342*0b57cec5SDimitry Andric InsertCall(I);
343*0b57cec5SDimitry Andric }
344*0b57cec5SDimitry Andric
345*0b57cec5SDimitry Andric SetKnownPositiveRefCount();
346*0b57cec5SDimitry Andric return NestingDetected;
347*0b57cec5SDimitry Andric }
348*0b57cec5SDimitry Andric
MatchWithRelease(ARCMDKindCache & Cache,Instruction * Release)349*0b57cec5SDimitry Andric bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
350*0b57cec5SDimitry Andric Instruction *Release) {
351*0b57cec5SDimitry Andric ClearKnownPositiveRefCount();
352*0b57cec5SDimitry Andric
353*0b57cec5SDimitry Andric Sequence OldSeq = GetSeq();
354*0b57cec5SDimitry Andric
355*0b57cec5SDimitry Andric MDNode *ReleaseMetadata =
356*0b57cec5SDimitry Andric Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
357*0b57cec5SDimitry Andric
358*0b57cec5SDimitry Andric switch (OldSeq) {
359*0b57cec5SDimitry Andric case S_Retain:
360*0b57cec5SDimitry Andric case S_CanRelease:
361*0b57cec5SDimitry Andric if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
362*0b57cec5SDimitry Andric ClearReverseInsertPts();
363*0b57cec5SDimitry Andric [[fallthrough]];
364*0b57cec5SDimitry Andric case S_Use:
365*0b57cec5SDimitry Andric SetReleaseMetadata(ReleaseMetadata);
366*0b57cec5SDimitry Andric SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
367*0b57cec5SDimitry Andric return true;
368*0b57cec5SDimitry Andric case S_None:
369*0b57cec5SDimitry Andric return false;
370*0b57cec5SDimitry Andric case S_Stop:
371*0b57cec5SDimitry Andric case S_MovableRelease:
372*0b57cec5SDimitry Andric llvm_unreachable("top-down pointer in bottom up state!");
373*0b57cec5SDimitry Andric }
374*0b57cec5SDimitry Andric llvm_unreachable("Sequence unknown enum value");
375*0b57cec5SDimitry Andric }
376*0b57cec5SDimitry Andric
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class,const BundledRetainClaimRVs & BundledRVs)377*0b57cec5SDimitry Andric bool TopDownPtrState::HandlePotentialAlterRefCount(
378*0b57cec5SDimitry Andric Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA,
379*0b57cec5SDimitry Andric ARCInstKind Class, const BundledRetainClaimRVs &BundledRVs) {
380*0b57cec5SDimitry Andric // Check for possible releases. Treat clang.arc.use as a releasing instruction
381*0b57cec5SDimitry Andric // to prevent sinking a retain past it.
382*0b57cec5SDimitry Andric if (!CanDecrementRefCount(Inst, Ptr, PA, Class) &&
383*0b57cec5SDimitry Andric Class != ARCInstKind::IntrinsicUser)
384*0b57cec5SDimitry Andric return false;
385*0b57cec5SDimitry Andric
386*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; "
387*0b57cec5SDimitry Andric << *Ptr << "\n");
388*0b57cec5SDimitry Andric ClearKnownPositiveRefCount();
389*0b57cec5SDimitry Andric switch (GetSeq()) {
390*0b57cec5SDimitry Andric case S_Retain:
391*0b57cec5SDimitry Andric SetSeq(S_CanRelease);
392*0b57cec5SDimitry Andric assert(!HasReverseInsertPts());
393*0b57cec5SDimitry Andric InsertReverseInsertPt(Inst);
394*0b57cec5SDimitry Andric
395*0b57cec5SDimitry Andric // Don't insert anything between a call/invoke with operand bundle
396*0b57cec5SDimitry Andric // "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
397*0b57cec5SDimitry Andric // result.
398*0b57cec5SDimitry Andric if (BundledRVs.contains(Inst))
399*0b57cec5SDimitry Andric SetCFGHazardAfflicted(true);
400*0b57cec5SDimitry Andric
401*0b57cec5SDimitry Andric // One call can't cause a transition from S_Retain to S_CanRelease
402*0b57cec5SDimitry Andric // and S_CanRelease to S_Use. If we've made the first transition,
403*0b57cec5SDimitry Andric // we're done.
404*0b57cec5SDimitry Andric return true;
405*0b57cec5SDimitry Andric case S_Use:
406*0b57cec5SDimitry Andric case S_CanRelease:
407*0b57cec5SDimitry Andric case S_None:
408*0b57cec5SDimitry Andric return false;
409*0b57cec5SDimitry Andric case S_Stop:
410*0b57cec5SDimitry Andric case S_MovableRelease:
411*0b57cec5SDimitry Andric llvm_unreachable("top-down pointer in release state!");
412*0b57cec5SDimitry Andric }
413*0b57cec5SDimitry Andric llvm_unreachable("covered switch is not covered!?");
414*0b57cec5SDimitry Andric }
415*0b57cec5SDimitry Andric
HandlePotentialUse(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)416*0b57cec5SDimitry Andric void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
417*0b57cec5SDimitry Andric ProvenanceAnalysis &PA,
418*0b57cec5SDimitry Andric ARCInstKind Class) {
419*0b57cec5SDimitry Andric // Check for possible direct uses.
420*0b57cec5SDimitry Andric switch (GetSeq()) {
421*0b57cec5SDimitry Andric case S_CanRelease:
422*0b57cec5SDimitry Andric if (!CanUse(Inst, Ptr, PA, Class))
423*0b57cec5SDimitry Andric return;
424*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
425*0b57cec5SDimitry Andric << *Ptr << "\n");
426*0b57cec5SDimitry Andric SetSeq(S_Use);
427*0b57cec5SDimitry Andric return;
428*0b57cec5SDimitry Andric case S_Retain:
429*0b57cec5SDimitry Andric case S_Use:
430*0b57cec5SDimitry Andric case S_None:
431*0b57cec5SDimitry Andric return;
432*0b57cec5SDimitry Andric case S_Stop:
433 case S_MovableRelease:
434 llvm_unreachable("top-down pointer in release state!");
435 }
436 }
437