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