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   LLVM_DEBUG(dbgs() << "        Setting Known Positive.\n");
130   KnownPositiveRefCount = true;
131 }
132 
133 void PtrState::ClearKnownPositiveRefCount() {
134   LLVM_DEBUG(dbgs() << "        Clearing Known Positive.\n");
135   KnownPositiveRefCount = false;
136 }
137 
138 void PtrState::SetSeq(Sequence NewSeq) {
139   LLVM_DEBUG(dbgs() << "            Old: " << GetSeq() << "; New: " << NewSeq
140                     << "\n");
141   Seq = NewSeq;
142 }
143 
144 void PtrState::ResetSequenceProgress(Sequence NewSeq) {
145   LLVM_DEBUG(dbgs() << "        Resetting sequence progress.\n");
146   SetSeq(NewSeq);
147   Partial = false;
148   RRI.clear();
149 }
150 
151 void PtrState::Merge(const PtrState &Other, bool TopDown) {
152   Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
153   KnownPositiveRefCount &= Other.KnownPositiveRefCount;
154 
155   // If we're not in a sequence (anymore), drop all associated state.
156   if (Seq == S_None) {
157     Partial = false;
158     RRI.clear();
159   } else if (Partial || Other.Partial) {
160     // If we're doing a merge on a path that's previously seen a partial
161     // merge, conservatively drop the sequence, to avoid doing partial
162     // RR elimination. If the branch predicates for the two merge differ,
163     // mixing them is unsafe.
164     ClearSequenceProgress();
165   } else {
166     // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
167     // point, we know that currently we are not partial. Stash whether or not
168     // the merge operation caused us to undergo a partial merging of reverse
169     // insertion points.
170     Partial = RRI.Merge(Other.RRI);
171   }
172 }
173 
174 //===----------------------------------------------------------------------===//
175 //                              BottomUpPtrState
176 //===----------------------------------------------------------------------===//
177 
178 bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
179   // If we see two releases in a row on the same pointer. If so, make
180   // a note, and we'll cicle back to revisit it after we've
181   // hopefully eliminated the second release, which may allow us to
182   // eliminate the first release too.
183   // Theoretically we could implement removal of nested retain+release
184   // pairs by making PtrState hold a stack of states, but this is
185   // simple and avoids adding overhead for the non-nested case.
186   bool NestingDetected = false;
187   if (GetSeq() == S_Release || GetSeq() == S_MovableRelease) {
188     LLVM_DEBUG(
189         dbgs() << "        Found nested releases (i.e. a release pair)\n");
190     NestingDetected = true;
191   }
192 
193   MDNode *ReleaseMetadata =
194       I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
195   Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
196   ResetSequenceProgress(NewSeq);
197   SetReleaseMetadata(ReleaseMetadata);
198   SetKnownSafe(HasKnownPositiveRefCount());
199   SetTailCallRelease(cast<CallInst>(I)->isTailCall());
200   InsertCall(I);
201   SetKnownPositiveRefCount();
202   return NestingDetected;
203 }
204 
205 bool BottomUpPtrState::MatchWithRetain() {
206   SetKnownPositiveRefCount();
207 
208   Sequence OldSeq = GetSeq();
209   switch (OldSeq) {
210   case S_Stop:
211   case S_Release:
212   case S_MovableRelease:
213   case S_Use:
214     // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
215     // imprecise release, clear our reverse insertion points.
216     if (OldSeq != S_Use || IsTrackingImpreciseReleases())
217       ClearReverseInsertPts();
218     LLVM_FALLTHROUGH;
219   case S_CanRelease:
220     return true;
221   case S_None:
222     return false;
223   case S_Retain:
224     llvm_unreachable("bottom-up pointer in retain state!");
225   }
226   llvm_unreachable("Sequence unknown enum value");
227 }
228 
229 bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
230                                                     const Value *Ptr,
231                                                     ProvenanceAnalysis &PA,
232                                                     ARCInstKind Class) {
233   Sequence S = GetSeq();
234 
235   // Check for possible releases.
236   if (!CanAlterRefCount(Inst, Ptr, PA, Class))
237     return false;
238 
239   LLVM_DEBUG(dbgs() << "            CanAlterRefCount: Seq: " << S << "; "
240                     << *Ptr << "\n");
241   switch (S) {
242   case S_Use:
243     SetSeq(S_CanRelease);
244     return true;
245   case S_CanRelease:
246   case S_Release:
247   case S_MovableRelease:
248   case S_Stop:
249   case S_None:
250     return false;
251   case S_Retain:
252     llvm_unreachable("bottom-up pointer in retain state!");
253   }
254   llvm_unreachable("Sequence unknown enum value");
255 }
256 
257 void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
258                                           const Value *Ptr,
259                                           ProvenanceAnalysis &PA,
260                                           ARCInstKind Class) {
261   auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
262     assert(!HasReverseInsertPts());
263     SetSeq(NewSeq);
264     // If this is an invoke instruction, we're scanning it as part of
265     // one of its successor blocks, since we can't insert code after it
266     // in its own block, and we don't want to split critical edges.
267     BasicBlock::iterator InsertAfter;
268     if (isa<InvokeInst>(Inst)) {
269       const auto IP = BB->getFirstInsertionPt();
270       InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP;
271     } else {
272       InsertAfter = std::next(Inst->getIterator());
273     }
274     InsertReverseInsertPt(&*InsertAfter);
275   };
276 
277   // Check for possible direct uses.
278   switch (GetSeq()) {
279   case S_Release:
280   case S_MovableRelease:
281     if (CanUse(Inst, Ptr, PA, Class)) {
282       LLVM_DEBUG(dbgs() << "            CanUse: Seq: " << GetSeq() << "; "
283                         << *Ptr << "\n");
284       SetSeqAndInsertReverseInsertPt(S_Use);
285     } else if (Seq == S_Release && IsUser(Class)) {
286       LLVM_DEBUG(dbgs() << "            PreciseReleaseUse: Seq: " << GetSeq()
287                         << "; " << *Ptr << "\n");
288       // Non-movable releases depend on any possible objc pointer use.
289       SetSeqAndInsertReverseInsertPt(S_Stop);
290     } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
291       if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
292         LLVM_DEBUG(dbgs() << "            ReleaseUse: Seq: " << GetSeq() << "; "
293                           << *Ptr << "\n");
294         SetSeqAndInsertReverseInsertPt(S_Stop);
295       }
296     }
297     break;
298   case S_Stop:
299     if (CanUse(Inst, Ptr, PA, Class)) {
300       LLVM_DEBUG(dbgs() << "            PreciseStopUse: Seq: " << GetSeq()
301                         << "; " << *Ptr << "\n");
302       SetSeq(S_Use);
303     }
304     break;
305   case S_CanRelease:
306   case S_Use:
307   case S_None:
308     break;
309   case S_Retain:
310     llvm_unreachable("bottom-up pointer in retain state!");
311   }
312 }
313 
314 //===----------------------------------------------------------------------===//
315 //                              TopDownPtrState
316 //===----------------------------------------------------------------------===//
317 
318 bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
319   bool NestingDetected = false;
320   // Don't do retain+release tracking for ARCInstKind::RetainRV, because
321   // it's
322   // better to let it remain as the first instruction after a call.
323   if (Kind != ARCInstKind::RetainRV) {
324     // If we see two retains in a row on the same pointer. If so, make
325     // a note, and we'll cicle back to revisit it after we've
326     // hopefully eliminated the second retain, which may allow us to
327     // eliminate the first retain too.
328     // Theoretically we could implement removal of nested retain+release
329     // pairs by making PtrState hold a stack of states, but this is
330     // simple and avoids adding overhead for the non-nested case.
331     if (GetSeq() == S_Retain)
332       NestingDetected = true;
333 
334     ResetSequenceProgress(S_Retain);
335     SetKnownSafe(HasKnownPositiveRefCount());
336     InsertCall(I);
337   }
338 
339   SetKnownPositiveRefCount();
340   return NestingDetected;
341 }
342 
343 bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
344                                        Instruction *Release) {
345   ClearKnownPositiveRefCount();
346 
347   Sequence OldSeq = GetSeq();
348 
349   MDNode *ReleaseMetadata =
350       Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
351 
352   switch (OldSeq) {
353   case S_Retain:
354   case S_CanRelease:
355     if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
356       ClearReverseInsertPts();
357     LLVM_FALLTHROUGH;
358   case S_Use:
359     SetReleaseMetadata(ReleaseMetadata);
360     SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
361     return true;
362   case S_None:
363     return false;
364   case S_Stop:
365   case S_Release:
366   case S_MovableRelease:
367     llvm_unreachable("top-down pointer in bottom up state!");
368   }
369   llvm_unreachable("Sequence unknown enum value");
370 }
371 
372 bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
373                                                    const Value *Ptr,
374                                                    ProvenanceAnalysis &PA,
375                                                    ARCInstKind Class) {
376   // Check for possible releases. Treat clang.arc.use as a releasing instruction
377   // to prevent sinking a retain past it.
378   if (!CanAlterRefCount(Inst, Ptr, PA, Class) &&
379       Class != ARCInstKind::IntrinsicUser)
380     return false;
381 
382   LLVM_DEBUG(dbgs() << "            CanAlterRefCount: Seq: " << GetSeq() << "; "
383                     << *Ptr << "\n");
384   ClearKnownPositiveRefCount();
385   switch (GetSeq()) {
386   case S_Retain:
387     SetSeq(S_CanRelease);
388     assert(!HasReverseInsertPts());
389     InsertReverseInsertPt(Inst);
390 
391     // One call can't cause a transition from S_Retain to S_CanRelease
392     // and S_CanRelease to S_Use. If we've made the first transition,
393     // we're done.
394     return true;
395   case S_Use:
396   case S_CanRelease:
397   case S_None:
398     return false;
399   case S_Stop:
400   case S_Release:
401   case S_MovableRelease:
402     llvm_unreachable("top-down pointer in release state!");
403   }
404   llvm_unreachable("covered switch is not covered!?");
405 }
406 
407 void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
408                                          ProvenanceAnalysis &PA,
409                                          ARCInstKind Class) {
410   // Check for possible direct uses.
411   switch (GetSeq()) {
412   case S_CanRelease:
413     if (!CanUse(Inst, Ptr, PA, Class))
414       return;
415     LLVM_DEBUG(dbgs() << "             CanUse: Seq: " << GetSeq() << "; "
416                       << *Ptr << "\n");
417     SetSeq(S_Use);
418     return;
419   case S_Retain:
420   case S_Use:
421   case S_None:
422     return;
423   case S_Stop:
424   case S_Release:
425   case S_MovableRelease:
426     llvm_unreachable("top-down pointer in release state!");
427   }
428 }
429