blob: d13e941044f14835bbef5158ac066c88d8569c9c [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();
Justin Bognercd1d5aa2016-08-17 20:30:52 +0000204 LLVM_FALLTHROUGH;
Michael Gottesman60805962015-03-06 00:34:42 +0000205 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) {
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000247 auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
248 assert(!HasReverseInsertPts());
249 SetSeq(NewSeq);
250 // If this is an invoke instruction, we're scanning it as part of
251 // one of its successor blocks, since we can't insert code after it
252 // in its own block, and we don't want to split critical edges.
253 if (isa<InvokeInst>(Inst))
254 InsertReverseInsertPt(&*BB->getFirstInsertionPt());
255 else
256 InsertReverseInsertPt(&*++Inst->getIterator());
257 };
258
Michael Gottesman16e6a202015-03-06 02:07:12 +0000259 // Check for possible direct uses.
260 switch (GetSeq()) {
261 case S_Release:
262 case S_MovableRelease:
263 if (CanUse(Inst, Ptr, PA, Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000264 DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
265 << "\n");
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000266 SetSeqAndInsertReverseInsertPt(S_Use);
Michael Gottesman16e6a202015-03-06 02:07:12 +0000267 } else if (Seq == S_Release && IsUser(Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000268 DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq() << "; "
269 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000270 // Non-movable releases depend on any possible objc pointer use.
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000271 SetSeqAndInsertReverseInsertPt(S_Stop);
272 } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
273 if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
274 DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
275 << *Ptr << "\n");
276 SetSeqAndInsertReverseInsertPt(S_Stop);
277 }
Michael Gottesman16e6a202015-03-06 02:07:12 +0000278 }
279 break;
280 case S_Stop:
281 if (CanUse(Inst, Ptr, PA, Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000282 DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq() << "; "
283 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000284 SetSeq(S_Use);
285 }
286 break;
287 case S_CanRelease:
288 case S_Use:
289 case S_None:
290 break;
291 case S_Retain:
292 llvm_unreachable("bottom-up pointer in retain state!");
293 }
294}
295
296//===----------------------------------------------------------------------===//
297// TopDownPtrState
298//===----------------------------------------------------------------------===//
299
Michael Gottesman4eae3962015-03-06 00:34:39 +0000300bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
301 bool NestingDetected = false;
302 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
303 // it's
304 // better to let it remain as the first instruction after a call.
305 if (Kind != ARCInstKind::RetainRV) {
306 // If we see two retains in a row on the same pointer. If so, make
307 // a note, and we'll cicle back to revisit it after we've
308 // hopefully eliminated the second retain, which may allow us to
309 // eliminate the first retain too.
310 // Theoretically we could implement removal of nested retain+release
311 // pairs by making PtrState hold a stack of states, but this is
312 // simple and avoids adding overhead for the non-nested case.
313 if (GetSeq() == S_Retain)
314 NestingDetected = true;
315
316 ResetSequenceProgress(S_Retain);
317 SetKnownSafe(HasKnownPositiveRefCount());
318 InsertCall(I);
319 }
320
321 SetKnownPositiveRefCount();
322 return NestingDetected;
323}
Michael Gottesman60805962015-03-06 00:34:42 +0000324
325bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
326 Instruction *Release) {
327 ClearKnownPositiveRefCount();
328
329 Sequence OldSeq = GetSeq();
330
Michael Gottesman65cb7372015-03-16 07:02:27 +0000331 MDNode *ReleaseMetadata =
332 Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Michael Gottesman60805962015-03-06 00:34:42 +0000333
334 switch (OldSeq) {
335 case S_Retain:
336 case S_CanRelease:
337 if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
338 ClearReverseInsertPts();
Justin Bognercd1d5aa2016-08-17 20:30:52 +0000339 LLVM_FALLTHROUGH;
Michael Gottesman60805962015-03-06 00:34:42 +0000340 case S_Use:
341 SetReleaseMetadata(ReleaseMetadata);
342 SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
343 return true;
344 case S_None:
345 return false;
346 case S_Stop:
347 case S_Release:
348 case S_MovableRelease:
349 llvm_unreachable("top-down pointer in bottom up state!");
350 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000351 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman60805962015-03-06 00:34:42 +0000352}
Michael Gottesman16e6a202015-03-06 02:07:12 +0000353
354bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
355 const Value *Ptr,
356 ProvenanceAnalysis &PA,
357 ARCInstKind Class) {
Akira Hatanaka490397f2017-04-25 04:06:35 +0000358 // Check for possible releases. Treat clang.arc.use as a releasing instruction
359 // to prevent sinking a retain past it.
360 if (!CanAlterRefCount(Inst, Ptr, PA, Class) &&
361 Class != ARCInstKind::IntrinsicUser)
Michael Gottesman16e6a202015-03-06 02:07:12 +0000362 return false;
363
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000364 DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; " << *Ptr
365 << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000366 ClearKnownPositiveRefCount();
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000367 switch (GetSeq()) {
Michael Gottesman16e6a202015-03-06 02:07:12 +0000368 case S_Retain:
369 SetSeq(S_CanRelease);
370 assert(!HasReverseInsertPts());
371 InsertReverseInsertPt(Inst);
372
373 // One call can't cause a transition from S_Retain to S_CanRelease
374 // and S_CanRelease to S_Use. If we've made the first transition,
375 // we're done.
376 return true;
377 case S_Use:
378 case S_CanRelease:
379 case S_None:
380 return false;
381 case S_Stop:
382 case S_Release:
383 case S_MovableRelease:
384 llvm_unreachable("top-down pointer in release state!");
385 }
386 llvm_unreachable("covered switch is not covered!?");
387}
388
389void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
390 ProvenanceAnalysis &PA,
391 ARCInstKind Class) {
392 // Check for possible direct uses.
393 switch (GetSeq()) {
394 case S_CanRelease:
395 if (!CanUse(Inst, Ptr, PA, Class))
396 return;
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000397 DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
398 << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000399 SetSeq(S_Use);
400 return;
401 case S_Retain:
402 case S_Use:
403 case S_None:
404 return;
405 case S_Stop:
406 case S_Release:
407 case S_MovableRelease:
408 llvm_unreachable("top-down pointer in release state!");
409 }
410}