• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
operator <<(raw_ostream & OS,const Sequence S)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 
MergeSeqs(Sequence A,Sequence B,bool TopDown)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 
clear()94 void RRInfo::clear() {
95   KnownSafe = false;
96   IsTailCallRelease = false;
97   ReleaseMetadata = nullptr;
98   Calls.clear();
99   ReverseInsertPts.clear();
100   CFGHazardAfflicted = false;
101 }
102 
Merge(const RRInfo & Other)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 
SetKnownPositiveRefCount()128 void PtrState::SetKnownPositiveRefCount() {
129   LLVM_DEBUG(dbgs() << "        Setting Known Positive.\n");
130   KnownPositiveRefCount = true;
131 }
132 
ClearKnownPositiveRefCount()133 void PtrState::ClearKnownPositiveRefCount() {
134   LLVM_DEBUG(dbgs() << "        Clearing Known Positive.\n");
135   KnownPositiveRefCount = false;
136 }
137 
SetSeq(Sequence NewSeq)138 void PtrState::SetSeq(Sequence NewSeq) {
139   LLVM_DEBUG(dbgs() << "            Old: " << GetSeq() << "; New: " << NewSeq
140                     << "\n");
141   Seq = NewSeq;
142 }
143 
ResetSequenceProgress(Sequence NewSeq)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 
Merge(const PtrState & Other,bool TopDown)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 
InitBottomUp(ARCMDKindCache & Cache,Instruction * I)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 
MatchWithRetain()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 
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)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 
HandlePotentialUse(BasicBlock * BB,Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)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       if (isa<CatchSwitchInst>(InsertAfter))
272         // A catchswitch must be the only non-phi instruction in its basic
273         // block, so attempting to insert an instruction into such a block would
274         // produce invalid IR.
275         SetCFGHazardAfflicted(true);
276     } else {
277       InsertAfter = std::next(Inst->getIterator());
278     }
279     InsertReverseInsertPt(&*InsertAfter);
280   };
281 
282   // Check for possible direct uses.
283   switch (GetSeq()) {
284   case S_Release:
285   case S_MovableRelease:
286     if (CanUse(Inst, Ptr, PA, Class)) {
287       LLVM_DEBUG(dbgs() << "            CanUse: Seq: " << GetSeq() << "; "
288                         << *Ptr << "\n");
289       SetSeqAndInsertReverseInsertPt(S_Use);
290     } else if (Seq == S_Release && IsUser(Class)) {
291       LLVM_DEBUG(dbgs() << "            PreciseReleaseUse: Seq: " << GetSeq()
292                         << "; " << *Ptr << "\n");
293       // Non-movable releases depend on any possible objc pointer use.
294       SetSeqAndInsertReverseInsertPt(S_Stop);
295     } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
296       if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
297         LLVM_DEBUG(dbgs() << "            ReleaseUse: Seq: " << GetSeq() << "; "
298                           << *Ptr << "\n");
299         SetSeqAndInsertReverseInsertPt(S_Stop);
300       }
301     }
302     break;
303   case S_Stop:
304     if (CanUse(Inst, Ptr, PA, Class)) {
305       LLVM_DEBUG(dbgs() << "            PreciseStopUse: Seq: " << GetSeq()
306                         << "; " << *Ptr << "\n");
307       SetSeq(S_Use);
308     }
309     break;
310   case S_CanRelease:
311   case S_Use:
312   case S_None:
313     break;
314   case S_Retain:
315     llvm_unreachable("bottom-up pointer in retain state!");
316   }
317 }
318 
319 //===----------------------------------------------------------------------===//
320 //                              TopDownPtrState
321 //===----------------------------------------------------------------------===//
322 
InitTopDown(ARCInstKind Kind,Instruction * I)323 bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
324   bool NestingDetected = false;
325   // Don't do retain+release tracking for ARCInstKind::RetainRV, because
326   // it's
327   // better to let it remain as the first instruction after a call.
328   if (Kind != ARCInstKind::RetainRV) {
329     // If we see two retains in a row on the same pointer. If so, make
330     // a note, and we'll cicle back to revisit it after we've
331     // hopefully eliminated the second retain, which may allow us to
332     // eliminate the first retain too.
333     // Theoretically we could implement removal of nested retain+release
334     // pairs by making PtrState hold a stack of states, but this is
335     // simple and avoids adding overhead for the non-nested case.
336     if (GetSeq() == S_Retain)
337       NestingDetected = true;
338 
339     ResetSequenceProgress(S_Retain);
340     SetKnownSafe(HasKnownPositiveRefCount());
341     InsertCall(I);
342   }
343 
344   SetKnownPositiveRefCount();
345   return NestingDetected;
346 }
347 
MatchWithRelease(ARCMDKindCache & Cache,Instruction * Release)348 bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
349                                        Instruction *Release) {
350   ClearKnownPositiveRefCount();
351 
352   Sequence OldSeq = GetSeq();
353 
354   MDNode *ReleaseMetadata =
355       Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
356 
357   switch (OldSeq) {
358   case S_Retain:
359   case S_CanRelease:
360     if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
361       ClearReverseInsertPts();
362     LLVM_FALLTHROUGH;
363   case S_Use:
364     SetReleaseMetadata(ReleaseMetadata);
365     SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
366     return true;
367   case S_None:
368     return false;
369   case S_Stop:
370   case S_Release:
371   case S_MovableRelease:
372     llvm_unreachable("top-down pointer in bottom up state!");
373   }
374   llvm_unreachable("Sequence unknown enum value");
375 }
376 
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)377 bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
378                                                    const Value *Ptr,
379                                                    ProvenanceAnalysis &PA,
380                                                    ARCInstKind Class) {
381   // Check for possible releases. Treat clang.arc.use as a releasing instruction
382   // to prevent sinking a retain past it.
383   if (!CanAlterRefCount(Inst, Ptr, PA, Class) &&
384       Class != ARCInstKind::IntrinsicUser)
385     return false;
386 
387   LLVM_DEBUG(dbgs() << "            CanAlterRefCount: Seq: " << GetSeq() << "; "
388                     << *Ptr << "\n");
389   ClearKnownPositiveRefCount();
390   switch (GetSeq()) {
391   case S_Retain:
392     SetSeq(S_CanRelease);
393     assert(!HasReverseInsertPts());
394     InsertReverseInsertPt(Inst);
395 
396     // One call can't cause a transition from S_Retain to S_CanRelease
397     // and S_CanRelease to S_Use. If we've made the first transition,
398     // we're done.
399     return true;
400   case S_Use:
401   case S_CanRelease:
402   case S_None:
403     return false;
404   case S_Stop:
405   case S_Release:
406   case S_MovableRelease:
407     llvm_unreachable("top-down pointer in release state!");
408   }
409   llvm_unreachable("covered switch is not covered!?");
410 }
411 
HandlePotentialUse(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)412 void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
413                                          ProvenanceAnalysis &PA,
414                                          ARCInstKind Class) {
415   // Check for possible direct uses.
416   switch (GetSeq()) {
417   case S_CanRelease:
418     if (!CanUse(Inst, Ptr, PA, Class))
419       return;
420     LLVM_DEBUG(dbgs() << "             CanUse: Seq: " << GetSeq() << "; "
421                       << *Ptr << "\n");
422     SetSeq(S_Use);
423     return;
424   case S_Retain:
425   case S_Use:
426   case S_None:
427     return;
428   case S_Stop:
429   case S_Release:
430   case S_MovableRelease:
431     llvm_unreachable("top-down pointer in release state!");
432   }
433 }
434