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