1 //===- 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"
11 #include "DependencyAnalysis.h"
12 #include "ObjCARC.h"
13 #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"
21 #include "llvm/Support/Debug.h"
22 #include "llvm/Support/ErrorHandling.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <cassert>
25 #include <iterator>
26 #include <utility>
27
28 using namespace llvm;
29 using namespace llvm::objcarc;
30
31 #define DEBUG_TYPE "objc-arc-ptr-state"
32
33 //===----------------------------------------------------------------------===//
34 // Utility
35 //===----------------------------------------------------------------------===//
36
operator <<(raw_ostream & OS,const Sequence S)37 raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
38 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
57 //===----------------------------------------------------------------------===//
58 // Sequence
59 //===----------------------------------------------------------------------===//
60
MergeSeqs(Sequence A,Sequence B,bool TopDown)61 static 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
90 //===----------------------------------------------------------------------===//
91 // RRInfo
92 //===----------------------------------------------------------------------===//
93
clear()94 void RRInfo::clear() {
95 KnownSafe = false;
96 IsTailCallRelease = false;
97 ReleaseMetadata = nullptr;
98 Calls.clear();
99 ReverseInsertPts.clear();
100 CFGHazardAfflicted = false;
101 }
102
Merge(const RRInfo & Other)103 bool 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
124 //===----------------------------------------------------------------------===//
125 // PtrState
126 //===----------------------------------------------------------------------===//
127
SetKnownPositiveRefCount()128 void PtrState::SetKnownPositiveRefCount() {
129 LLVM_DEBUG(dbgs() << " Setting Known Positive.\n");
130 KnownPositiveRefCount = true;
131 }
132
ClearKnownPositiveRefCount()133 void PtrState::ClearKnownPositiveRefCount() {
134 LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n");
135 KnownPositiveRefCount = false;
136 }
137
SetSeq(Sequence NewSeq)138 void PtrState::SetSeq(Sequence NewSeq) {
139 LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq
140 << "\n");
141 Seq = NewSeq;
142 }
143
ResetSequenceProgress(Sequence NewSeq)144 void PtrState::ResetSequenceProgress(Sequence NewSeq) {
145 LLVM_DEBUG(dbgs() << " Resetting sequence progress.\n");
146 SetSeq(NewSeq);
147 Partial = false;
148 RRI.clear();
149 }
150
Merge(const PtrState & Other,bool TopDown)151 void PtrState::Merge(const PtrState &Other, bool TopDown) {
152 Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
153 KnownPositiveRefCount &= Other.KnownPositiveRefCount;
154
155 // If we're not in a sequence (anymore), drop all associated state.
156 if (Seq == S_None) {
157 Partial = false;
158 RRI.clear();
159 } else if (Partial || Other.Partial) {
160 // If we're doing a merge on a path that's previously seen a partial
161 // merge, conservatively drop the sequence, to avoid doing partial
162 // RR elimination. If the branch predicates for the two merge differ,
163 // mixing them is unsafe.
164 ClearSequenceProgress();
165 } else {
166 // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
167 // point, we know that currently we are not partial. Stash whether or not
168 // the merge operation caused us to undergo a partial merging of reverse
169 // insertion points.
170 Partial = RRI.Merge(Other.RRI);
171 }
172 }
173
174 //===----------------------------------------------------------------------===//
175 // BottomUpPtrState
176 //===----------------------------------------------------------------------===//
177
InitBottomUp(ARCMDKindCache & Cache,Instruction * I)178 bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
179 // If we see two releases in a row on the same pointer. If so, make
180 // a note, and we'll cicle back to revisit it after we've
181 // hopefully eliminated the second release, which may allow us to
182 // eliminate the first release too.
183 // Theoretically we could implement removal of nested retain+release
184 // pairs by making PtrState hold a stack of states, but this is
185 // simple and avoids adding overhead for the non-nested case.
186 bool NestingDetected = false;
187 if (GetSeq() == S_Release || GetSeq() == S_MovableRelease) {
188 LLVM_DEBUG(
189 dbgs() << " Found nested releases (i.e. a release pair)\n");
190 NestingDetected = true;
191 }
192
193 MDNode *ReleaseMetadata =
194 I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
195 Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
196 ResetSequenceProgress(NewSeq);
197 SetReleaseMetadata(ReleaseMetadata);
198 SetKnownSafe(HasKnownPositiveRefCount());
199 SetTailCallRelease(cast<CallInst>(I)->isTailCall());
200 InsertCall(I);
201 SetKnownPositiveRefCount();
202 return NestingDetected;
203 }
204
MatchWithRetain()205 bool BottomUpPtrState::MatchWithRetain() {
206 SetKnownPositiveRefCount();
207
208 Sequence OldSeq = GetSeq();
209 switch (OldSeq) {
210 case S_Stop:
211 case S_Release:
212 case S_MovableRelease:
213 case S_Use:
214 // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
215 // imprecise release, clear our reverse insertion points.
216 if (OldSeq != S_Use || IsTrackingImpreciseReleases())
217 ClearReverseInsertPts();
218 LLVM_FALLTHROUGH;
219 case S_CanRelease:
220 return true;
221 case S_None:
222 return false;
223 case S_Retain:
224 llvm_unreachable("bottom-up pointer in retain state!");
225 }
226 llvm_unreachable("Sequence unknown enum value");
227 }
228
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)229 bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
230 const Value *Ptr,
231 ProvenanceAnalysis &PA,
232 ARCInstKind Class) {
233 Sequence S = GetSeq();
234
235 // Check for possible releases.
236 if (!CanAlterRefCount(Inst, Ptr, PA, Class))
237 return false;
238
239 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; "
240 << *Ptr << "\n");
241 switch (S) {
242 case S_Use:
243 SetSeq(S_CanRelease);
244 return true;
245 case S_CanRelease:
246 case S_Release:
247 case S_MovableRelease:
248 case S_Stop:
249 case S_None:
250 return false;
251 case S_Retain:
252 llvm_unreachable("bottom-up pointer in retain state!");
253 }
254 llvm_unreachable("Sequence unknown enum value");
255 }
256
HandlePotentialUse(BasicBlock * BB,Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)257 void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
258 const Value *Ptr,
259 ProvenanceAnalysis &PA,
260 ARCInstKind Class) {
261 auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
262 assert(!HasReverseInsertPts());
263 SetSeq(NewSeq);
264 // If this is an invoke instruction, we're scanning it as part of
265 // one of its successor blocks, since we can't insert code after it
266 // in its own block, and we don't want to split critical edges.
267 BasicBlock::iterator InsertAfter;
268 if (isa<InvokeInst>(Inst)) {
269 const auto IP = BB->getFirstInsertionPt();
270 InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP;
271 if (isa<CatchSwitchInst>(InsertAfter))
272 // A catchswitch must be the only non-phi instruction in its basic
273 // block, so attempting to insert an instruction into such a block would
274 // produce invalid IR.
275 SetCFGHazardAfflicted(true);
276 } else {
277 InsertAfter = std::next(Inst->getIterator());
278 }
279 InsertReverseInsertPt(&*InsertAfter);
280 };
281
282 // Check for possible direct uses.
283 switch (GetSeq()) {
284 case S_Release:
285 case S_MovableRelease:
286 if (CanUse(Inst, Ptr, PA, Class)) {
287 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
288 << *Ptr << "\n");
289 SetSeqAndInsertReverseInsertPt(S_Use);
290 } else if (Seq == S_Release && IsUser(Class)) {
291 LLVM_DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq()
292 << "; " << *Ptr << "\n");
293 // Non-movable releases depend on any possible objc pointer use.
294 SetSeqAndInsertReverseInsertPt(S_Stop);
295 } else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
296 if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
297 LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
298 << *Ptr << "\n");
299 SetSeqAndInsertReverseInsertPt(S_Stop);
300 }
301 }
302 break;
303 case S_Stop:
304 if (CanUse(Inst, Ptr, PA, Class)) {
305 LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq()
306 << "; " << *Ptr << "\n");
307 SetSeq(S_Use);
308 }
309 break;
310 case S_CanRelease:
311 case S_Use:
312 case S_None:
313 break;
314 case S_Retain:
315 llvm_unreachable("bottom-up pointer in retain state!");
316 }
317 }
318
319 //===----------------------------------------------------------------------===//
320 // TopDownPtrState
321 //===----------------------------------------------------------------------===//
322
InitTopDown(ARCInstKind Kind,Instruction * I)323 bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
324 bool NestingDetected = false;
325 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
326 // it's
327 // better to let it remain as the first instruction after a call.
328 if (Kind != ARCInstKind::RetainRV) {
329 // If we see two retains in a row on the same pointer. If so, make
330 // a note, and we'll cicle back to revisit it after we've
331 // hopefully eliminated the second retain, which may allow us to
332 // eliminate the first retain too.
333 // Theoretically we could implement removal of nested retain+release
334 // pairs by making PtrState hold a stack of states, but this is
335 // simple and avoids adding overhead for the non-nested case.
336 if (GetSeq() == S_Retain)
337 NestingDetected = true;
338
339 ResetSequenceProgress(S_Retain);
340 SetKnownSafe(HasKnownPositiveRefCount());
341 InsertCall(I);
342 }
343
344 SetKnownPositiveRefCount();
345 return NestingDetected;
346 }
347
MatchWithRelease(ARCMDKindCache & Cache,Instruction * Release)348 bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
349 Instruction *Release) {
350 ClearKnownPositiveRefCount();
351
352 Sequence OldSeq = GetSeq();
353
354 MDNode *ReleaseMetadata =
355 Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
356
357 switch (OldSeq) {
358 case S_Retain:
359 case S_CanRelease:
360 if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
361 ClearReverseInsertPts();
362 LLVM_FALLTHROUGH;
363 case S_Use:
364 SetReleaseMetadata(ReleaseMetadata);
365 SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
366 return true;
367 case S_None:
368 return false;
369 case S_Stop:
370 case S_Release:
371 case S_MovableRelease:
372 llvm_unreachable("top-down pointer in bottom up state!");
373 }
374 llvm_unreachable("Sequence unknown enum value");
375 }
376
HandlePotentialAlterRefCount(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)377 bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
378 const Value *Ptr,
379 ProvenanceAnalysis &PA,
380 ARCInstKind Class) {
381 // Check for possible releases. Treat clang.arc.use as a releasing instruction
382 // to prevent sinking a retain past it.
383 if (!CanAlterRefCount(Inst, Ptr, PA, Class) &&
384 Class != ARCInstKind::IntrinsicUser)
385 return false;
386
387 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; "
388 << *Ptr << "\n");
389 ClearKnownPositiveRefCount();
390 switch (GetSeq()) {
391 case S_Retain:
392 SetSeq(S_CanRelease);
393 assert(!HasReverseInsertPts());
394 InsertReverseInsertPt(Inst);
395
396 // One call can't cause a transition from S_Retain to S_CanRelease
397 // and S_CanRelease to S_Use. If we've made the first transition,
398 // we're done.
399 return true;
400 case S_Use:
401 case S_CanRelease:
402 case S_None:
403 return false;
404 case S_Stop:
405 case S_Release:
406 case S_MovableRelease:
407 llvm_unreachable("top-down pointer in release state!");
408 }
409 llvm_unreachable("covered switch is not covered!?");
410 }
411
HandlePotentialUse(Instruction * Inst,const Value * Ptr,ProvenanceAnalysis & PA,ARCInstKind Class)412 void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
413 ProvenanceAnalysis &PA,
414 ARCInstKind Class) {
415 // Check for possible direct uses.
416 switch (GetSeq()) {
417 case S_CanRelease:
418 if (!CanUse(Inst, Ptr, PA, Class))
419 return;
420 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
421 << *Ptr << "\n");
422 SetSeq(S_Use);
423 return;
424 case S_Retain:
425 case S_Use:
426 case S_None:
427 return;
428 case S_Stop:
429 case S_Release:
430 case S_MovableRelease:
431 llvm_unreachable("top-down pointer in release state!");
432 }
433 }
434