blob: 26dd416d618459ce4184ece1317893d28112f30b [file] [log] [blame]
Eugene Zelenko57bd5a02017-10-27 01:09:08 +00001//===- PtrState.cpp -------------------------------------------------------===//
Michael Gottesman68b91db2015-03-05 23:29:03 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Michael Gottesman68b91db2015-03-05 23:29:03 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "PtrState.h"
Michael Gottesman16e6a202015-03-06 02:07:12 +000010#include "DependencyAnalysis.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000011#include "ObjCARC.h"
Eugene Zelenko57bd5a02017-10-27 01:09:08 +000012#include "llvm/Analysis/ObjCARCAnalysisUtils.h"
13#include "llvm/Analysis/ObjCARCInstKind.h"
14#include "llvm/IR/BasicBlock.h"
15#include "llvm/IR/Instruction.h"
16#include "llvm/IR/Instructions.h"
17#include "llvm/IR/Value.h"
18#include "llvm/Support/Casting.h"
19#include "llvm/Support/Compiler.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000020#include "llvm/Support/Debug.h"
Eugene Zelenko57bd5a02017-10-27 01:09:08 +000021#include "llvm/Support/ErrorHandling.h"
Benjamin Kramer799003b2015-03-23 19:32:43 +000022#include "llvm/Support/raw_ostream.h"
Eugene Zelenko57bd5a02017-10-27 01:09:08 +000023#include <cassert>
24#include <iterator>
25#include <utility>
Michael Gottesman68b91db2015-03-05 23:29:03 +000026
27using namespace llvm;
28using namespace llvm::objcarc;
29
Benjamin Kramer799003b2015-03-23 19:32:43 +000030#define DEBUG_TYPE "objc-arc-ptr-state"
31
Michael Gottesman16e6a202015-03-06 02:07:12 +000032//===----------------------------------------------------------------------===//
33// Utility
34//===----------------------------------------------------------------------===//
35
Michael Gottesmand45907b2015-03-05 23:57:07 +000036raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
Michael Gottesman68b91db2015-03-05 23:29:03 +000037 switch (S) {
38 case S_None:
39 return OS << "S_None";
40 case S_Retain:
41 return OS << "S_Retain";
42 case S_CanRelease:
43 return OS << "S_CanRelease";
44 case S_Use:
45 return OS << "S_Use";
46 case S_Release:
47 return OS << "S_Release";
48 case S_MovableRelease:
49 return OS << "S_MovableRelease";
50 case S_Stop:
51 return OS << "S_Stop";
52 }
53 llvm_unreachable("Unknown sequence type.");
54}
55
Michael Gottesman16e6a202015-03-06 02:07:12 +000056//===----------------------------------------------------------------------===//
57// Sequence
58//===----------------------------------------------------------------------===//
59
Michael Gottesman68b91db2015-03-05 23:29:03 +000060static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
61 // The easy cases.
62 if (A == B)
63 return A;
64 if (A == S_None || B == S_None)
65 return S_None;
66
67 if (A > B)
68 std::swap(A, B);
69 if (TopDown) {
70 // Choose the side which is further along in the sequence.
71 if ((A == S_Retain || A == S_CanRelease) &&
72 (B == S_CanRelease || B == S_Use))
73 return B;
74 } else {
75 // Choose the side which is further along in the sequence.
76 if ((A == S_Use || A == S_CanRelease) &&
77 (B == S_Use || B == S_Release || B == S_Stop || B == S_MovableRelease))
78 return A;
79 // If both sides are releases, choose the more conservative one.
80 if (A == S_Stop && (B == S_Release || B == S_MovableRelease))
81 return A;
82 if (A == S_Release && B == S_MovableRelease)
83 return A;
84 }
85
86 return S_None;
87}
88
Michael Gottesman16e6a202015-03-06 02:07:12 +000089//===----------------------------------------------------------------------===//
90// RRInfo
91//===----------------------------------------------------------------------===//
92
Michael Gottesman68b91db2015-03-05 23:29:03 +000093void RRInfo::clear() {
94 KnownSafe = false;
95 IsTailCallRelease = false;
96 ReleaseMetadata = nullptr;
97 Calls.clear();
98 ReverseInsertPts.clear();
99 CFGHazardAfflicted = false;
100}
101
102bool RRInfo::Merge(const RRInfo &Other) {
103 // Conservatively merge the ReleaseMetadata information.
104 if (ReleaseMetadata != Other.ReleaseMetadata)
105 ReleaseMetadata = nullptr;
106
107 // Conservatively merge the boolean state.
108 KnownSafe &= Other.KnownSafe;
109 IsTailCallRelease &= Other.IsTailCallRelease;
110 CFGHazardAfflicted |= Other.CFGHazardAfflicted;
111
112 // Merge the call sets.
113 Calls.insert(Other.Calls.begin(), Other.Calls.end());
114
115 // Merge the insert point sets. If there are any differences,
116 // that makes this a partial merge.
117 bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
118 for (Instruction *Inst : Other.ReverseInsertPts)
119 Partial |= ReverseInsertPts.insert(Inst).second;
120 return Partial;
121}
122
Michael Gottesman16e6a202015-03-06 02:07:12 +0000123//===----------------------------------------------------------------------===//
124// PtrState
125//===----------------------------------------------------------------------===//
126
Michael Gottesmand45907b2015-03-05 23:57:07 +0000127void PtrState::SetKnownPositiveRefCount() {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000128 LLVM_DEBUG(dbgs() << " Setting Known Positive.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000129 KnownPositiveRefCount = true;
130}
131
132void PtrState::ClearKnownPositiveRefCount() {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000133 LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000134 KnownPositiveRefCount = false;
135}
136
137void PtrState::SetSeq(Sequence NewSeq) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000138 LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq
139 << "\n");
Michael Gottesmand45907b2015-03-05 23:57:07 +0000140 Seq = NewSeq;
141}
142
143void PtrState::ResetSequenceProgress(Sequence NewSeq) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000144 LLVM_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) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000187 LLVM_DEBUG(
188 dbgs() << " Found nested releases (i.e. a release pair)\n");
Michael Gottesman4eae3962015-03-06 00:34:39 +0000189 NestingDetected = true;
190 }
191
Michael Gottesman65cb7372015-03-16 07:02:27 +0000192 MDNode *ReleaseMetadata =
193 I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Michael Gottesman4eae3962015-03-06 00:34:39 +0000194 Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
195 ResetSequenceProgress(NewSeq);
196 SetReleaseMetadata(ReleaseMetadata);
197 SetKnownSafe(HasKnownPositiveRefCount());
198 SetTailCallRelease(cast<CallInst>(I)->isTailCall());
199 InsertCall(I);
200 SetKnownPositiveRefCount();
201 return NestingDetected;
202}
203
Michael Gottesman60805962015-03-06 00:34:42 +0000204bool BottomUpPtrState::MatchWithRetain() {
205 SetKnownPositiveRefCount();
206
207 Sequence OldSeq = GetSeq();
208 switch (OldSeq) {
209 case S_Stop:
210 case S_Release:
211 case S_MovableRelease:
212 case S_Use:
213 // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
214 // imprecise release, clear our reverse insertion points.
215 if (OldSeq != S_Use || IsTrackingImpreciseReleases())
216 ClearReverseInsertPts();
Justin Bognercd1d5aa2016-08-17 20:30:52 +0000217 LLVM_FALLTHROUGH;
Michael Gottesman60805962015-03-06 00:34:42 +0000218 case S_CanRelease:
219 return true;
220 case S_None:
221 return false;
222 case S_Retain:
223 llvm_unreachable("bottom-up pointer in retain state!");
224 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000225 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman60805962015-03-06 00:34:42 +0000226}
227
Michael Gottesman16e6a202015-03-06 02:07:12 +0000228bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
229 const Value *Ptr,
230 ProvenanceAnalysis &PA,
231 ARCInstKind Class) {
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000232 Sequence S = GetSeq();
Michael Gottesman16e6a202015-03-06 02:07:12 +0000233
234 // Check for possible releases.
235 if (!CanAlterRefCount(Inst, Ptr, PA, Class))
236 return false;
237
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000238 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; "
239 << *Ptr << "\n");
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000240 switch (S) {
Michael Gottesman16e6a202015-03-06 02:07:12 +0000241 case S_Use:
242 SetSeq(S_CanRelease);
243 return true;
244 case S_CanRelease:
245 case S_Release:
246 case S_MovableRelease:
247 case S_Stop:
248 case S_None:
249 return false;
250 case S_Retain:
251 llvm_unreachable("bottom-up pointer in retain state!");
252 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000253 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000254}
255
256void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
257 const Value *Ptr,
258 ProvenanceAnalysis &PA,
259 ARCInstKind Class) {
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000260 auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
261 assert(!HasReverseInsertPts());
262 SetSeq(NewSeq);
263 // If this is an invoke instruction, we're scanning it as part of
264 // one of its successor blocks, since we can't insert code after it
265 // in its own block, and we don't want to split critical edges.
Saleem Abdulrasool619b3262017-10-24 00:09:10 +0000266 BasicBlock::iterator InsertAfter;
267 if (isa<InvokeInst>(Inst)) {
268 const auto IP = BB->getFirstInsertionPt();
269 InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP;
Shoaib Meenai074728a2018-05-16 04:52:18 +0000270 if (isa<CatchSwitchInst>(InsertAfter))
271 // A catchswitch must be the only non-phi instruction in its basic
272 // block, so attempting to insert an instruction into such a block would
273 // produce invalid IR.
274 SetCFGHazardAfflicted(true);
Saleem Abdulrasool619b3262017-10-24 00:09:10 +0000275 } else {
276 InsertAfter = std::next(Inst->getIterator());
277 }
Akira Hatanaka75fbb172019-09-19 20:58:51 +0000278
279 if (InsertAfter != BB->end())
280 InsertAfter = skipDebugIntrinsics(InsertAfter);
281
Saleem Abdulrasool619b3262017-10-24 00:09:10 +0000282 InsertReverseInsertPt(&*InsertAfter);
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000283 };
284
Michael Gottesman16e6a202015-03-06 02:07:12 +0000285 // Check for possible direct uses.
286 switch (GetSeq()) {
287 case S_Release:
288 case S_MovableRelease:
289 if (CanUse(Inst, Ptr, PA, Class)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000290 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
291 << *Ptr << "\n");
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000292 SetSeqAndInsertReverseInsertPt(S_Use);
Michael Gottesman16e6a202015-03-06 02:07:12 +0000293 } else if (Seq == S_Release && IsUser(Class)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000294 LLVM_DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq()
295 << "; " << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000296 // Non-movable releases depend on any possible objc pointer use.
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000297 SetSeqAndInsertReverseInsertPt(S_Stop);
298 } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
299 if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000300 LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
301 << *Ptr << "\n");
Akira Hatanaka6fdcb3c2017-04-29 00:23:11 +0000302 SetSeqAndInsertReverseInsertPt(S_Stop);
303 }
Michael Gottesman16e6a202015-03-06 02:07:12 +0000304 }
305 break;
306 case S_Stop:
307 if (CanUse(Inst, Ptr, PA, Class)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000308 LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq()
309 << "; " << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000310 SetSeq(S_Use);
311 }
312 break;
313 case S_CanRelease:
314 case S_Use:
315 case S_None:
316 break;
317 case S_Retain:
318 llvm_unreachable("bottom-up pointer in retain state!");
319 }
320}
321
322//===----------------------------------------------------------------------===//
323// TopDownPtrState
324//===----------------------------------------------------------------------===//
325
Michael Gottesman4eae3962015-03-06 00:34:39 +0000326bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
327 bool NestingDetected = false;
328 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
329 // it's
330 // better to let it remain as the first instruction after a call.
331 if (Kind != ARCInstKind::RetainRV) {
332 // If we see two retains in a row on the same pointer. If so, make
333 // a note, and we'll cicle back to revisit it after we've
334 // hopefully eliminated the second retain, which may allow us to
335 // eliminate the first retain too.
336 // Theoretically we could implement removal of nested retain+release
337 // pairs by making PtrState hold a stack of states, but this is
338 // simple and avoids adding overhead for the non-nested case.
339 if (GetSeq() == S_Retain)
340 NestingDetected = true;
341
342 ResetSequenceProgress(S_Retain);
343 SetKnownSafe(HasKnownPositiveRefCount());
344 InsertCall(I);
345 }
346
347 SetKnownPositiveRefCount();
348 return NestingDetected;
349}
Michael Gottesman60805962015-03-06 00:34:42 +0000350
351bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
352 Instruction *Release) {
353 ClearKnownPositiveRefCount();
354
355 Sequence OldSeq = GetSeq();
356
Michael Gottesman65cb7372015-03-16 07:02:27 +0000357 MDNode *ReleaseMetadata =
358 Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
Michael Gottesman60805962015-03-06 00:34:42 +0000359
360 switch (OldSeq) {
361 case S_Retain:
362 case S_CanRelease:
363 if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
364 ClearReverseInsertPts();
Justin Bognercd1d5aa2016-08-17 20:30:52 +0000365 LLVM_FALLTHROUGH;
Michael Gottesman60805962015-03-06 00:34:42 +0000366 case S_Use:
367 SetReleaseMetadata(ReleaseMetadata);
368 SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
369 return true;
370 case S_None:
371 return false;
372 case S_Stop:
373 case S_Release:
374 case S_MovableRelease:
375 llvm_unreachable("top-down pointer in bottom up state!");
376 }
Yaron Keren322bdad2015-03-06 07:49:14 +0000377 llvm_unreachable("Sequence unknown enum value");
Michael Gottesman60805962015-03-06 00:34:42 +0000378}
Michael Gottesman16e6a202015-03-06 02:07:12 +0000379
380bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
381 const Value *Ptr,
382 ProvenanceAnalysis &PA,
383 ARCInstKind Class) {
Akira Hatanaka490397f2017-04-25 04:06:35 +0000384 // Check for possible releases. Treat clang.arc.use as a releasing instruction
385 // to prevent sinking a retain past it.
386 if (!CanAlterRefCount(Inst, Ptr, PA, Class) &&
387 Class != ARCInstKind::IntrinsicUser)
Michael Gottesman16e6a202015-03-06 02:07:12 +0000388 return false;
389
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000390 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; "
391 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000392 ClearKnownPositiveRefCount();
Michael Gottesmanc01ab512015-03-16 07:02:39 +0000393 switch (GetSeq()) {
Michael Gottesman16e6a202015-03-06 02:07:12 +0000394 case S_Retain:
395 SetSeq(S_CanRelease);
396 assert(!HasReverseInsertPts());
397 InsertReverseInsertPt(Inst);
398
399 // One call can't cause a transition from S_Retain to S_CanRelease
400 // and S_CanRelease to S_Use. If we've made the first transition,
401 // we're done.
402 return true;
403 case S_Use:
404 case S_CanRelease:
405 case S_None:
406 return false;
407 case S_Stop:
408 case S_Release:
409 case S_MovableRelease:
410 llvm_unreachable("top-down pointer in release state!");
411 }
412 llvm_unreachable("covered switch is not covered!?");
413}
414
415void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
416 ProvenanceAnalysis &PA,
417 ARCInstKind Class) {
418 // Check for possible direct uses.
419 switch (GetSeq()) {
420 case S_CanRelease:
421 if (!CanUse(Inst, Ptr, PA, Class))
422 return;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000423 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
424 << *Ptr << "\n");
Michael Gottesman16e6a202015-03-06 02:07:12 +0000425 SetSeq(S_Use);
426 return;
427 case S_Retain:
428 case S_Use:
429 case S_None:
430 return;
431 case S_Stop:
432 case S_Release:
433 case S_MovableRelease:
434 llvm_unreachable("top-down pointer in release state!");
435 }
436}