blob: e1774b88fd35303a7a0484d23dc95899909cd646 [file] [log] [blame]
Eugene Zelenko57bd5a02017-10-27 01:09:08 +00001//===- PtrState.cpp -------------------------------------------------------===//
Michael Gottesman68b91db2015-03-05 23:29:03 +00002//
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"
Eugene Zelenko57bd5a02017-10-27 01:09:08 +000013#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"
Benjamin Kramer799003b2015-03-23 19:32:43 +000021#include "llvm/Support/Debug.h"
Eugene Zelenko57bd5a02017-10-27 01:09:08 +000022#include "llvm/Support/ErrorHandling.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000023#include "llvm/Support/raw_ostream.h"
Eugene Zelenko57bd5a02017-10-27 01:09:08 +000024#include <cassert>
25#include <iterator>
26#include <utility>
Michael Gottesman68b91db2015-03-05 23:29:03 +000027
28using namespace llvm;
29using namespace llvm::objcarc;
30
Benjamin Kramer799003b2015-03-23 19:32:43 +000031#define DEBUG_TYPE "objc-arc-ptr-state"
32
Michael Gottesman16e6a202015-03-06 02:07:12 +000033//===----------------------------------------------------------------------===//
34// Utility
35//===----------------------------------------------------------------------===//
36
Michael Gottesmand45907b2015-03-05 23:57:07 +000037raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
Michael Gottesman68b91db2015-03-05 23:29:03 +000038 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
Michael Gottesman16e6a202015-03-06 02:07:12 +000057//===----------------------------------------------------------------------===//
58// Sequence
59//===----------------------------------------------------------------------===//
60
Michael Gottesman68b91db2015-03-05 23:29:03 +000061static 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
Michael Gottesman16e6a202015-03-06 02:07:12 +000090//===----------------------------------------------------------------------===//
91// RRInfo
92//===----------------------------------------------------------------------===//
93
Michael Gottesman68b91db2015-03-05 23:29:03 +000094void RRInfo::clear() {
95 KnownSafe = false;
96 IsTailCallRelease = false;
97 ReleaseMetadata = nullptr;
98 Calls.clear();
99 ReverseInsertPts.clear();
100 CFGHazardAfflicted = false;
101}
102
103bool 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
Michael Gottesman16e6a202015-03-06 02:07:12 +0000124//===----------------------------------------------------------------------===//
125// PtrState
126//===----------------------------------------------------------------------===//
127
Michael Gottesmand45907b2015-03-05 23:57:07 +0000128void PtrState::SetKnownPositiveRefCount() {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000129 DEBUG(dbgs() << " Setting Known Positive.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000130 KnownPositiveRefCount = true;
131}
132
133void PtrState::ClearKnownPositiveRefCount() {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000134 DEBUG(dbgs() << " Clearing Known Positive.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000135 KnownPositiveRefCount = false;
136}
137
138void PtrState::SetSeq(Sequence NewSeq) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000139 DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq << "\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000140 Seq = NewSeq;
141}
142
143void PtrState::ResetSequenceProgress(Sequence NewSeq) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000144 DEBUG(dbgs() << " Resetting sequence progress.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000145 SetSeq(NewSeq);
146 Partial = false;
147 RRI.clear();
148}
149
Michael Gottesman68b91db2015-03-05 23:29:03 +0000150void PtrState::Merge(const PtrState &Other, bool TopDown) {
151 Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
152 KnownPositiveRefCount &= Other.KnownPositiveRefCount;
153
154 // If we're not in a sequence (anymore), drop all associated state.
155 if (Seq == S_None) {
156 Partial = false;
157 RRI.clear();
158 } else if (Partial || Other.Partial) {
159 // If we're doing a merge on a path that's previously seen a partial
160 // merge, conservatively drop the sequence, to avoid doing partial
161 // RR elimination. If the branch predicates for the two merge differ,
162 // mixing them is unsafe.
163 ClearSequenceProgress();
164 } else {
165 // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
166 // point, we know that currently we are not partial. Stash whether or not
167 // the merge operation caused us to undergo a partial merging of reverse
168 // insertion points.
169 Partial = RRI.Merge(Other.RRI);
170 }
171}
Michael Gottesman4eae3962015-03-06 00:34:39 +0000172
Michael Gottesman16e6a202015-03-06 02:07:12 +0000173//===----------------------------------------------------------------------===//
174// BottomUpPtrState
175//===----------------------------------------------------------------------===//
176
Michael Gottesman4eae3962015-03-06 00:34:39 +0000177bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
178 // If we see two releases in a row on the same pointer. If so, make
179 // a note, and we'll cicle back to revisit it after we've
180 // hopefully eliminated the second release, which may allow us to
181 // eliminate the first release too.
182 // Theoretically we could implement removal of nested retain+release
183 // pairs by making PtrState hold a stack of states, but this is
184 // simple and avoids adding overhead for the non-nested case.
185 bool NestingDetected = false;
186 if (GetSeq() == S_Release || GetSeq() == S_MovableRelease) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000187 DEBUG(dbgs() << " Found nested releases (i.e. a release pair)\n");
Michael Gottesman4eae3962015-03-06 00:34:39 +0000188 NestingDetected = true;
189 }
190
Michael Gottesman65cb7372015-03-16 07:02:27 +0000191 MDNode *ReleaseMetadata =
192 I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Michael Gottesman4eae3962015-03-06 00:34:39 +0000193 Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
194 ResetSequenceProgress(NewSeq);
195 SetReleaseMetadata(ReleaseMetadata);
196 SetKnownSafe(HasKnownPositiveRefCount());
197 SetTailCallRelease(cast<CallInst>(I)->isTailCall());
198 InsertCall(I);
199 SetKnownPositiveRefCount();
200 return NestingDetected;
201}
202
Michael Gottesman60805962015-03-06 00:34:42 +0000203bool BottomUpPtrState::MatchWithRetain() {
204 SetKnownPositiveRefCount();
205
206 Sequence OldSeq = GetSeq();
207 switch (OldSeq) {
208 case S_Stop:
209 case S_Release:
210 case S_MovableRelease:
211 case S_Use:
212 // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
213 // imprecise release, clear our reverse insertion points.
214 if (OldSeq != S_Use || IsTrackingImpreciseReleases())
215 ClearReverseInsertPts();
Justin Bognercd1d5aa2016-08-17 20:30:52 +0000216 LLVM_FALLTHROUGH;
Michael Gottesman60805962015-03-06 00:34:42 +0000217 case S_CanRelease:
218 return true;
219 case S_None:
220 return false;
221 case S_Retain:
222 llvm_unreachable("bottom-up pointer in retain state!");
223 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000224 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman60805962015-03-06 00:34:42 +0000225}
226
Michael Gottesman16e6a202015-03-06 02:07:12 +0000227bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
228 const Value *Ptr,
229 ProvenanceAnalysis &PA,
230 ARCInstKind Class) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000231 Sequence S = GetSeq();
Michael Gottesman16e6a202015-03-06 02:07:12 +0000232
233 // Check for possible releases.
234 if (!CanAlterRefCount(Inst, Ptr, PA, Class))
235 return false;
236
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000237 DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; " << *Ptr
238 << "\n");
239 switch (S) {
Michael Gottesman16e6a202015-03-06 02:07:12 +0000240 case S_Use:
241 SetSeq(S_CanRelease);
242 return true;
243 case S_CanRelease:
244 case S_Release:
245 case S_MovableRelease:
246 case S_Stop:
247 case S_None:
248 return false;
249 case S_Retain:
250 llvm_unreachable("bottom-up pointer in retain state!");
251 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000252 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000253}
254
255void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
256 const Value *Ptr,
257 ProvenanceAnalysis &PA,
258 ARCInstKind Class) {
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000259 auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
260 assert(!HasReverseInsertPts());
261 SetSeq(NewSeq);
262 // If this is an invoke instruction, we're scanning it as part of
263 // one of its successor blocks, since we can't insert code after it
264 // in its own block, and we don't want to split critical edges.
Saleem Abdulrasool619b3262017-10-24 00:09:10 +0000265 BasicBlock::iterator InsertAfter;
266 if (isa<InvokeInst>(Inst)) {
267 const auto IP = BB->getFirstInsertionPt();
268 InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP;
269 } else {
270 InsertAfter = std::next(Inst->getIterator());
271 }
272 InsertReverseInsertPt(&*InsertAfter);
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000273 };
274
Michael Gottesman16e6a202015-03-06 02:07:12 +0000275 // Check for possible direct uses.
276 switch (GetSeq()) {
277 case S_Release:
278 case S_MovableRelease:
279 if (CanUse(Inst, Ptr, PA, Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000280 DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
281 << "\n");
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000282 SetSeqAndInsertReverseInsertPt(S_Use);
Michael Gottesman16e6a202015-03-06 02:07:12 +0000283 } else if (Seq == S_Release && IsUser(Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000284 DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq() << "; "
285 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000286 // Non-movable releases depend on any possible objc pointer use.
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000287 SetSeqAndInsertReverseInsertPt(S_Stop);
288 } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
289 if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
290 DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
291 << *Ptr << "\n");
292 SetSeqAndInsertReverseInsertPt(S_Stop);
293 }
Michael Gottesman16e6a202015-03-06 02:07:12 +0000294 }
295 break;
296 case S_Stop:
297 if (CanUse(Inst, Ptr, PA, Class)) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000298 DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq() << "; "
299 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000300 SetSeq(S_Use);
301 }
302 break;
303 case S_CanRelease:
304 case S_Use:
305 case S_None:
306 break;
307 case S_Retain:
308 llvm_unreachable("bottom-up pointer in retain state!");
309 }
310}
311
312//===----------------------------------------------------------------------===//
313// TopDownPtrState
314//===----------------------------------------------------------------------===//
315
Michael Gottesman4eae3962015-03-06 00:34:39 +0000316bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
317 bool NestingDetected = false;
318 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
319 // it's
320 // better to let it remain as the first instruction after a call.
321 if (Kind != ARCInstKind::RetainRV) {
322 // If we see two retains in a row on the same pointer. If so, make
323 // a note, and we'll cicle back to revisit it after we've
324 // hopefully eliminated the second retain, which may allow us to
325 // eliminate the first retain too.
326 // Theoretically we could implement removal of nested retain+release
327 // pairs by making PtrState hold a stack of states, but this is
328 // simple and avoids adding overhead for the non-nested case.
329 if (GetSeq() == S_Retain)
330 NestingDetected = true;
331
332 ResetSequenceProgress(S_Retain);
333 SetKnownSafe(HasKnownPositiveRefCount());
334 InsertCall(I);
335 }
336
337 SetKnownPositiveRefCount();
338 return NestingDetected;
339}
Michael Gottesman60805962015-03-06 00:34:42 +0000340
341bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
342 Instruction *Release) {
343 ClearKnownPositiveRefCount();
344
345 Sequence OldSeq = GetSeq();
346
Michael Gottesman65cb7372015-03-16 07:02:27 +0000347 MDNode *ReleaseMetadata =
348 Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Michael Gottesman60805962015-03-06 00:34:42 +0000349
350 switch (OldSeq) {
351 case S_Retain:
352 case S_CanRelease:
353 if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
354 ClearReverseInsertPts();
Justin Bognercd1d5aa2016-08-17 20:30:52 +0000355 LLVM_FALLTHROUGH;
Michael Gottesman60805962015-03-06 00:34:42 +0000356 case S_Use:
357 SetReleaseMetadata(ReleaseMetadata);
358 SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
359 return true;
360 case S_None:
361 return false;
362 case S_Stop:
363 case S_Release:
364 case S_MovableRelease:
365 llvm_unreachable("top-down pointer in bottom up state!");
366 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000367 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman60805962015-03-06 00:34:42 +0000368}
Michael Gottesman16e6a202015-03-06 02:07:12 +0000369
370bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
371 const Value *Ptr,
372 ProvenanceAnalysis &PA,
373 ARCInstKind Class) {
Akira Hatanaka490397f2017-04-25 04:06:35 +0000374 // Check for possible releases. Treat clang.arc.use as a releasing instruction
375 // to prevent sinking a retain past it.
376 if (!CanAlterRefCount(Inst, Ptr, PA, Class) &&
377 Class != ARCInstKind::IntrinsicUser)
Michael Gottesman16e6a202015-03-06 02:07:12 +0000378 return false;
379
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000380 DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; " << *Ptr
381 << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000382 ClearKnownPositiveRefCount();
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000383 switch (GetSeq()) {
Michael Gottesman16e6a202015-03-06 02:07:12 +0000384 case S_Retain:
385 SetSeq(S_CanRelease);
386 assert(!HasReverseInsertPts());
387 InsertReverseInsertPt(Inst);
388
389 // One call can't cause a transition from S_Retain to S_CanRelease
390 // and S_CanRelease to S_Use. If we've made the first transition,
391 // we're done.
392 return true;
393 case S_Use:
394 case S_CanRelease:
395 case S_None:
396 return false;
397 case S_Stop:
398 case S_Release:
399 case S_MovableRelease:
400 llvm_unreachable("top-down pointer in release state!");
401 }
402 llvm_unreachable("covered switch is not covered!?");
403}
404
405void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
406 ProvenanceAnalysis &PA,
407 ARCInstKind Class) {
408 // Check for possible direct uses.
409 switch (GetSeq()) {
410 case S_CanRelease:
411 if (!CanUse(Inst, Ptr, PA, Class))
412 return;
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000413 DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; " << *Ptr
414 << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000415 SetSeq(S_Use);
416 return;
417 case S_Retain:
418 case S_Use:
419 case S_None:
420 return;
421 case S_Stop:
422 case S_Release:
423 case S_MovableRelease:
424 llvm_unreachable("top-down pointer in release state!");
425 }
426}