blob: df64fa32f3f881951edcebb8c79014de32bc7743 [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
10#include "PtrState.h"
Michael Gottesman16e6a202015-03-06 02:07:12 +000011#include "DependencyAnalysis.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000012#include "ObjCARC.h"
13#include "llvm/Support/Debug.h"
14#include "llvm/Support/raw_ostream.h"
Michael Gottesman68b91db2015-03-05 23:29:03 +000015
16using namespace llvm;
17using namespace llvm::objcarc;
18
Benjamin Kramer799003b2015-03-23 19:32:43 +000019#define DEBUG_TYPE "objc-arc-ptr-state"
20
Michael Gottesman16e6a202015-03-06 02:07:12 +000021//===----------------------------------------------------------------------===//
22// Utility
23//===----------------------------------------------------------------------===//
24
Michael Gottesmand45907b2015-03-05 23:57:07 +000025raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
Michael Gottesman68b91db2015-03-05 23:29:03 +000026 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
Michael Gottesman16e6a202015-03-06 02:07:12 +000045//===----------------------------------------------------------------------===//
46// Sequence
47//===----------------------------------------------------------------------===//
48
Michael Gottesman68b91db2015-03-05 23:29:03 +000049static 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
Michael Gottesman16e6a202015-03-06 02:07:12 +000078//===----------------------------------------------------------------------===//
79// RRInfo
80//===----------------------------------------------------------------------===//
81
Michael Gottesman68b91db2015-03-05 23:29:03 +000082void RRInfo::clear() {
83 KnownSafe = false;
84 IsTailCallRelease = false;
85 ReleaseMetadata = nullptr;
86 Calls.clear();
87 ReverseInsertPts.clear();
88 CFGHazardAfflicted = false;
89}
90
91bool 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;
98 IsTailCallRelease &= Other.IsTailCallRelease;
99 CFGHazardAfflicted |= Other.CFGHazardAfflicted;
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
Michael Gottesman16e6a202015-03-06 02:07:12 +0000112//===----------------------------------------------------------------------===//
113// PtrState
114//===----------------------------------------------------------------------===//
115
Michael Gottesmand45907b2015-03-05 23:57:07 +0000116void PtrState::SetKnownPositiveRefCount() {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000117 DEBUG(dbgs() << " Setting Known Positive.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000118 KnownPositiveRefCount = true;
119}
120
121void PtrState::ClearKnownPositiveRefCount() {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000122 DEBUG(dbgs() << " Clearing Known Positive.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000123 KnownPositiveRefCount = false;
124}
125
126void PtrState::SetSeq(Sequence NewSeq) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000127 DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq << "\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000128 Seq = NewSeq;
129}
130
131void PtrState::ResetSequenceProgress(Sequence NewSeq) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000132 DEBUG(dbgs() << " Resetting sequence progress.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000133 SetSeq(NewSeq);
134 Partial = false;
135 RRI.clear();
136}
137
Michael Gottesman68b91db2015-03-05 23:29:03 +0000138void PtrState::Merge(const PtrState &Other, bool TopDown) {
139 Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
140 KnownPositiveRefCount &= Other.KnownPositiveRefCount;
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.
151 ClearSequenceProgress();
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}
Michael Gottesman4eae3962015-03-06 00:34:39 +0000160
Michael Gottesman16e6a202015-03-06 02:07:12 +0000161//===----------------------------------------------------------------------===//
162// BottomUpPtrState
163//===----------------------------------------------------------------------===//
164
Michael Gottesman4eae3962015-03-06 00:34:39 +0000165bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
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) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000175 DEBUG(dbgs() << " Found nested releases (i.e. a release pair)\n");
Michael Gottesman4eae3962015-03-06 00:34:39 +0000176 NestingDetected = true;
177 }
178
Michael Gottesman65cb7372015-03-16 07:02:27 +0000179 MDNode *ReleaseMetadata =
180 I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Michael Gottesman4eae3962015-03-06 00:34:39 +0000181 Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
182 ResetSequenceProgress(NewSeq);
183 SetReleaseMetadata(ReleaseMetadata);
184 SetKnownSafe(HasKnownPositiveRefCount());
185 SetTailCallRelease(cast<CallInst>(I)->isTailCall());
186 InsertCall(I);
187 SetKnownPositiveRefCount();
188 return NestingDetected;
189}
190
Michael Gottesman60805962015-03-06 00:34:42 +0000191bool BottomUpPtrState::MatchWithRetain() {
192 SetKnownPositiveRefCount();
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())
203 ClearReverseInsertPts();
204 // FALL THROUGH
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 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000212 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman60805962015-03-06 00:34:42 +0000213}
214
Michael Gottesman16e6a202015-03-06 02:07:12 +0000215bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
216 const Value *Ptr,
217 ProvenanceAnalysis &PA,
218 ARCInstKind Class) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000219 Sequence S = GetSeq();
Michael Gottesman16e6a202015-03-06 02:07:12 +0000220
221 // Check for possible releases.
222 if (!CanAlterRefCount(Inst, Ptr, PA, Class))
223 return false;
224
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000225 DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; " << *Ptr
226 << "\n");
227 switch (S) {
Michael Gottesman16e6a202015-03-06 02:07:12 +0000228 case S_Use:
229 SetSeq(S_CanRelease);
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 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000240 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000241}
242
243void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
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)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000252 DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
253 << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000254 assert(!HasReverseInsertPts());
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))
Duncan P. N. Exon Smith1e59a662015-10-19 23:20:14 +0000259 InsertReverseInsertPt(&*BB->getFirstInsertionPt());
Michael Gottesman16e6a202015-03-06 02:07:12 +0000260 else
Duncan P. N. Exon Smith1e59a662015-10-19 23:20:14 +0000261 InsertReverseInsertPt(&*++Inst->getIterator());
Michael Gottesman16e6a202015-03-06 02:07:12 +0000262 SetSeq(S_Use);
263 } else if (Seq == S_Release && IsUser(Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000264 DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq() << "; "
265 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000266 // Non-movable releases depend on any possible objc pointer use.
267 SetSeq(S_Stop);
268 assert(!HasReverseInsertPts());
269 // As above; handle invoke specially.
270 if (isa<InvokeInst>(Inst))
Duncan P. N. Exon Smith1e59a662015-10-19 23:20:14 +0000271 InsertReverseInsertPt(&*BB->getFirstInsertionPt());
Michael Gottesman16e6a202015-03-06 02:07:12 +0000272 else
Duncan P. N. Exon Smith1e59a662015-10-19 23:20:14 +0000273 InsertReverseInsertPt(&*++Inst->getIterator());
Michael Gottesman16e6a202015-03-06 02:07:12 +0000274 }
275 break;
276 case S_Stop:
277 if (CanUse(Inst, Ptr, PA, Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000278 DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq() << "; "
279 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000280 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
Michael Gottesman4eae3962015-03-06 00:34:39 +0000296bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
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
312 ResetSequenceProgress(S_Retain);
313 SetKnownSafe(HasKnownPositiveRefCount());
314 InsertCall(I);
315 }
316
317 SetKnownPositiveRefCount();
318 return NestingDetected;
319}
Michael Gottesman60805962015-03-06 00:34:42 +0000320
321bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
322 Instruction *Release) {
323 ClearKnownPositiveRefCount();
324
325 Sequence OldSeq = GetSeq();
326
Michael Gottesman65cb7372015-03-16 07:02:27 +0000327 MDNode *ReleaseMetadata =
328 Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Michael Gottesman60805962015-03-06 00:34:42 +0000329
330 switch (OldSeq) {
331 case S_Retain:
332 case S_CanRelease:
333 if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
334 ClearReverseInsertPts();
335 // FALL THROUGH
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 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000347 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman60805962015-03-06 00:34:42 +0000348}
Michael Gottesman16e6a202015-03-06 02:07:12 +0000349
350bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
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
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000358 DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; " << *Ptr
359 << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000360 ClearKnownPositiveRefCount();
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000361 switch (GetSeq()) {
Michael Gottesman16e6a202015-03-06 02:07:12 +0000362 case S_Retain:
363 SetSeq(S_CanRelease);
364 assert(!HasReverseInsertPts());
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
383void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
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;
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000391 DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
392 << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000393 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}