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