xref: /aosp_15_r20/external/llvm/lib/Transforms/ObjCARC/PtrState.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
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