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