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