LLVM  4.0.0
PtrState.cpp
Go to the documentation of this file.
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"
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 
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;
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 
117  DEBUG(dbgs() << " Setting Known Positive.\n");
118  KnownPositiveRefCount = true;
119 }
120 
122  DEBUG(dbgs() << " Clearing Known Positive.\n");
123  KnownPositiveRefCount = false;
124 }
125 
127  DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq << "\n");
128  Seq = NewSeq;
129 }
130 
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);
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.
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 
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 =
181  Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
182  ResetSequenceProgress(NewSeq);
183  SetReleaseMetadata(ReleaseMetadata);
185  SetTailCallRelease(cast<CallInst>(I)->isTailCall());
186  InsertCall(I);
188  return NestingDetected;
189 }
190 
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())
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 
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:
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 
244  const Value *Ptr,
245  ProvenanceAnalysis &PA,
246  ARCInstKind Class) {
247  // Check for possible direct uses.
248  switch (GetSeq()) {
249  case S_Release:
250  case S_MovableRelease:
251  if (CanUse(Inst, Ptr, PA, Class)) {
252  DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
253  << "\n");
255  // If this is an invoke instruction, we're scanning it as part of
256  // one of its successor blocks, since we can't insert code after it
257  // in its own block, and we don't want to split critical edges.
258  if (isa<InvokeInst>(Inst))
260  else
261  InsertReverseInsertPt(&*++Inst->getIterator());
262  SetSeq(S_Use);
263  } else if (Seq == S_Release && IsUser(Class)) {
264  DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq() << "; "
265  << *Ptr << "\n");
266  // Non-movable releases depend on any possible objc pointer use.
267  SetSeq(S_Stop);
269  // As above; handle invoke specially.
270  if (isa<InvokeInst>(Inst))
272  else
273  InsertReverseInsertPt(&*++Inst->getIterator());
274  }
275  break;
276  case S_Stop:
277  if (CanUse(Inst, Ptr, PA, Class)) {
278  DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq() << "; "
279  << *Ptr << "\n");
280  SetSeq(S_Use);
281  }
282  break;
283  case S_CanRelease:
284  case S_Use:
285  case S_None:
286  break;
287  case S_Retain:
288  llvm_unreachable("bottom-up pointer in retain state!");
289  }
290 }
291 
292 //===----------------------------------------------------------------------===//
293 // TopDownPtrState
294 //===----------------------------------------------------------------------===//
295 
297  bool NestingDetected = false;
298  // Don't do retain+release tracking for ARCInstKind::RetainRV, because
299  // it's
300  // better to let it remain as the first instruction after a call.
301  if (Kind != ARCInstKind::RetainRV) {
302  // If we see two retains in a row on the same pointer. If so, make
303  // a note, and we'll cicle back to revisit it after we've
304  // hopefully eliminated the second retain, which may allow us to
305  // eliminate the first retain too.
306  // Theoretically we could implement removal of nested retain+release
307  // pairs by making PtrState hold a stack of states, but this is
308  // simple and avoids adding overhead for the non-nested case.
309  if (GetSeq() == S_Retain)
310  NestingDetected = true;
311 
314  InsertCall(I);
315  }
316 
318  return NestingDetected;
319 }
320 
322  Instruction *Release) {
324 
325  Sequence OldSeq = GetSeq();
326 
327  MDNode *ReleaseMetadata =
329 
330  switch (OldSeq) {
331  case S_Retain:
332  case S_CanRelease:
333  if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
336  case S_Use:
337  SetReleaseMetadata(ReleaseMetadata);
338  SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
339  return true;
340  case S_None:
341  return false;
342  case S_Stop:
343  case S_Release:
344  case S_MovableRelease:
345  llvm_unreachable("top-down pointer in bottom up state!");
346  }
347  llvm_unreachable("Sequence unknown enum value");
348 }
349 
351  const Value *Ptr,
352  ProvenanceAnalysis &PA,
353  ARCInstKind Class) {
354  // Check for possible releases.
355  if (!CanAlterRefCount(Inst, Ptr, PA, Class))
356  return false;
357 
358  DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; " << *Ptr
359  << "\n");
361  switch (GetSeq()) {
362  case S_Retain:
365  InsertReverseInsertPt(Inst);
366 
367  // One call can't cause a transition from S_Retain to S_CanRelease
368  // and S_CanRelease to S_Use. If we've made the first transition,
369  // we're done.
370  return true;
371  case S_Use:
372  case S_CanRelease:
373  case S_None:
374  return false;
375  case S_Stop:
376  case S_Release:
377  case S_MovableRelease:
378  llvm_unreachable("top-down pointer in release state!");
379  }
380  llvm_unreachable("covered switch is not covered!?");
381 }
382 
384  ProvenanceAnalysis &PA,
385  ARCInstKind Class) {
386  // Check for possible direct uses.
387  switch (GetSeq()) {
388  case S_CanRelease:
389  if (!CanUse(Inst, Ptr, PA, Class))
390  return;
391  DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
392  << "\n");
393  SetSeq(S_Use);
394  return;
395  case S_Retain:
396  case S_Use:
397  case S_None:
398  return;
399  case S_Stop:
400  case S_Release:
401  case S_MovableRelease:
402  llvm_unreachable("top-down pointer in release state!");
403  }
404 }
bool Merge(const RRInfo &Other)
Conservatively merge the two RRInfo.
Definition: PtrState.cpp:91
This file declares special dependency analysis routines used in Objective C ARC Optimizations.
bool IsUser(ARCInstKind Class)
Test if the given class is a kind of user.
SmallPtrSet< Instruction *, 2 > Calls
For a top-down sequence, the set of objc_retains or objc_retainBlocks.
Definition: PtrState.h:77
void ClearReverseInsertPts()
Definition: PtrState.h:160
bool CanUse(const Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Test whether the given instruction can "use" the given pointer's object in a way that requires the ...
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Definition: PtrState.cpp:215
any use of x.
Definition: PtrState.h:41
bool MatchWithRelease(ARCMDKindCache &Cache, Instruction *Release)
Return true if this set of retains can be paired with the given release.
Definition: PtrState.cpp:321
Metadata node.
Definition: Metadata.h:830
void SetKnownSafe(const bool NewValue)
Definition: PtrState.h:120
bool HasReverseInsertPts() const
Definition: PtrState.h:162
SmallPtrSet< Instruction *, 2 > ReverseInsertPts
The set of optimal insert positions for moving calls in the opposite sequence.
Definition: PtrState.h:81
unsigned char Seq
The current position in the sequence.
Definition: PtrState.h:110
void InsertReverseInsertPt(Instruction *I)
Definition: PtrState.h:158
void InsertCall(Instruction *I)
Definition: PtrState.h:156
This class summarizes several per-pointer runtime properties which are propagated through the flow gr...
Definition: PtrState.h:100
unsigned get(ARCMDKindID ID)
This file defines common definitions/declarations used by the ObjC ARC Optimizer. ...
bool IsTailCallRelease
True of the objc_release calls are all marked with the "tail" keyword.
Definition: PtrState.h:69
bool InitBottomUp(ARCMDKindCache &Cache, Instruction *I)
(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases...
Definition: PtrState.cpp:165
objc_retainAutoreleasedReturnValue
void ClearKnownPositiveRefCount()
Definition: PtrState.cpp:121
void HandlePotentialUse(BasicBlock *BB, Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Definition: PtrState.cpp:243
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
Unidirectional information about either a retain-decrement-use-release sequence or release-use-decrem...
Definition: PtrState.h:53
raw_ostream & operator<<(raw_ostream &OS, const ARCInstKind Class)
Sequence GetSeq() const
Definition: PtrState.h:149
void HandlePotentialUse(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Definition: PtrState.cpp:383
RRInfo RRI
Unidirectional information about the current sequence.
Definition: PtrState.h:113
LLVM Basic Block Representation.
Definition: BasicBlock.h:51
bool KnownPositiveRefCount
True if the reference count is known to be incremented.
Definition: PtrState.h:103
void Merge(const PtrState &Other, bool TopDown)
Definition: PtrState.cpp:138
like S_Release, but code motion is stopped.
Definition: PtrState.h:42
self_iterator getIterator()
Definition: ilist_node.h:81
A cache of MDKinds used by various ARC optimizations.
bool MatchWithRetain()
Return true if this set of releases can be paired with a release.
Definition: PtrState.cpp:191
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void ResetSequenceProgress(Sequence NewSeq)
Definition: PtrState.cpp:131
bool CFGHazardAfflicted
If this is true, we cannot perform code motion but can still remove retain/release pairs...
Definition: PtrState.h:85
objc_release(x), !clang.imprecise_release.
Definition: PtrState.h:44
objc_release(x).
Definition: PtrState.h:43
void SetReleaseMetadata(MDNode *NewValue)
Definition: PtrState.h:134
bool Partial
True if we've seen an opportunity for partial RR elimination, such as pushing calls into a CFG triang...
Definition: PtrState.h:107
ARCInstKind
Equivalence classes of instructions in the ARC Model.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
Definition: Instruction.h:175
bool HandlePotentialAlterRefCount(Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Definition: PtrState.cpp:350
objc_retain(x).
Definition: PtrState.h:39
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:586
MDNode * ReleaseMetadata
If the Calls are objc_release calls and they all have a clang.imprecise_release tag, this is the metadata tag.
Definition: PtrState.h:73
void SetTailCallRelease(const bool NewValue)
Definition: PtrState.h:124
void ClearSequenceProgress()
Definition: PtrState.h:151
static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown)
Definition: PtrState.cpp:49
#define I(x, y, z)
Definition: MD5.cpp:54
Sequence
A sequence of states that a pointer may go through in which an objc_retain and objc_release are actua...
Definition: PtrState.h:37
bool CanAlterRefCount(const Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA, ARCInstKind Class)
Test whether the given instruction can result in a reference count modification (positive or negative...
void SetSeq(Sequence NewSeq)
Definition: PtrState.cpp:126
bool IsTrackingImpreciseReleases() const
Definition: PtrState.h:128
const unsigned Kind
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
LLVM Value Representation.
Definition: Value.h:71
foo(x) – x could possibly see a ref count decrement.
Definition: PtrState.h:40
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
Definition: Compiler.h:239
bool KnownSafe
After an objc_retain, the reference count of the referenced object is known to be positive...
Definition: PtrState.h:66
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:44
#define DEBUG(X)
Definition: Debug.h:100
This is similar to BasicAliasAnalysis, and it uses many of the same techniques, except it uses specia...
iterator getFirstInsertionPt()
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
Definition: BasicBlock.cpp:209
int * Ptr
bool InitTopDown(ARCInstKind Kind, Instruction *I)
(Re-)Initialize this bottom up pointer returning true if we detected a pointer with nested releases...
Definition: PtrState.cpp:296
bool HasKnownPositiveRefCount() const
Definition: PtrState.h:145
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")