1 //===- PtrState.cpp -------------------------------------------------------===//
3 // 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
7 //===----------------------------------------------------------------------===//
10 #include "DependencyAnalysis.h"
12 #include "llvm/Analysis/ObjCARCAnalysisUtils.h"
13 #include "llvm/Analysis/ObjCARCInstKind.h"
14 #include "llvm/Analysis/ObjCARCUtil.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"
29 using namespace llvm::objcarc
;
31 #define DEBUG_TYPE "objc-arc-ptr-state"
33 //===----------------------------------------------------------------------===//
35 //===----------------------------------------------------------------------===//
37 raw_ostream
&llvm::objcarc::operator<<(raw_ostream
&OS
, const Sequence S
) {
40 return OS
<< "S_None";
42 return OS
<< "S_Retain";
44 return OS
<< "S_CanRelease";
47 case S_MovableRelease
:
48 return OS
<< "S_MovableRelease";
50 return OS
<< "S_Stop";
52 llvm_unreachable("Unknown sequence type.");
55 //===----------------------------------------------------------------------===//
57 //===----------------------------------------------------------------------===//
59 static Sequence
MergeSeqs(Sequence A
, Sequence B
, bool TopDown
) {
63 if (A
== S_None
|| B
== S_None
)
69 // Choose the side which is further along in the sequence.
70 if ((A
== S_Retain
|| A
== S_CanRelease
) &&
71 (B
== S_CanRelease
|| B
== S_Use
))
74 // Choose the side which is further along in the sequence.
75 if ((A
== S_Use
|| A
== S_CanRelease
) &&
76 (B
== S_Use
|| B
== S_Stop
|| B
== S_MovableRelease
))
78 // If both sides are releases, choose the more conservative one.
79 if (A
== S_Stop
&& B
== S_MovableRelease
)
86 //===----------------------------------------------------------------------===//
88 //===----------------------------------------------------------------------===//
90 void RRInfo::clear() {
92 IsTailCallRelease
= false;
93 ReleaseMetadata
= nullptr;
95 ReverseInsertPts
.clear();
96 CFGHazardAfflicted
= false;
99 bool RRInfo::Merge(const RRInfo
&Other
) {
100 // Conservatively merge the ReleaseMetadata information.
101 if (ReleaseMetadata
!= Other
.ReleaseMetadata
)
102 ReleaseMetadata
= nullptr;
104 // Conservatively merge the boolean state.
105 KnownSafe
&= Other
.KnownSafe
;
106 IsTailCallRelease
&= Other
.IsTailCallRelease
;
107 CFGHazardAfflicted
|= Other
.CFGHazardAfflicted
;
109 // Merge the call sets.
110 Calls
.insert(Other
.Calls
.begin(), Other
.Calls
.end());
112 // Merge the insert point sets. If there are any differences,
113 // that makes this a partial merge.
114 bool Partial
= ReverseInsertPts
.size() != Other
.ReverseInsertPts
.size();
115 for (Instruction
*Inst
: Other
.ReverseInsertPts
)
116 Partial
|= ReverseInsertPts
.insert(Inst
).second
;
120 //===----------------------------------------------------------------------===//
122 //===----------------------------------------------------------------------===//
124 void PtrState::SetKnownPositiveRefCount() {
125 LLVM_DEBUG(dbgs() << " Setting Known Positive.\n");
126 KnownPositiveRefCount
= true;
129 void PtrState::ClearKnownPositiveRefCount() {
130 LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n");
131 KnownPositiveRefCount
= false;
134 void PtrState::SetSeq(Sequence NewSeq
) {
135 LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq
140 void PtrState::ResetSequenceProgress(Sequence NewSeq
) {
141 LLVM_DEBUG(dbgs() << " Resetting sequence progress.\n");
147 void PtrState::Merge(const PtrState
&Other
, bool TopDown
) {
148 Seq
= MergeSeqs(GetSeq(), Other
.GetSeq(), TopDown
);
149 KnownPositiveRefCount
&= Other
.KnownPositiveRefCount
;
151 // If we're not in a sequence (anymore), drop all associated state.
155 } else if (Partial
|| Other
.Partial
) {
156 // If we're doing a merge on a path that's previously seen a partial
157 // merge, conservatively drop the sequence, to avoid doing partial
158 // RR elimination. If the branch predicates for the two merge differ,
159 // mixing them is unsafe.
160 ClearSequenceProgress();
162 // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
163 // point, we know that currently we are not partial. Stash whether or not
164 // the merge operation caused us to undergo a partial merging of reverse
166 Partial
= RRI
.Merge(Other
.RRI
);
170 //===----------------------------------------------------------------------===//
172 //===----------------------------------------------------------------------===//
174 bool BottomUpPtrState::InitBottomUp(ARCMDKindCache
&Cache
, Instruction
*I
) {
175 // If we see two releases in a row on the same pointer. If so, make
176 // a note, and we'll cicle back to revisit it after we've
177 // hopefully eliminated the second release, which may allow us to
178 // eliminate the first release too.
179 // Theoretically we could implement removal of nested retain+release
180 // pairs by making PtrState hold a stack of states, but this is
181 // simple and avoids adding overhead for the non-nested case.
182 bool NestingDetected
= false;
183 if (GetSeq() == S_MovableRelease
) {
185 dbgs() << " Found nested releases (i.e. a release pair)\n");
186 NestingDetected
= true;
189 MDNode
*ReleaseMetadata
=
190 I
->getMetadata(Cache
.get(ARCMDKindID::ImpreciseRelease
));
191 Sequence NewSeq
= ReleaseMetadata
? S_MovableRelease
: S_Stop
;
192 ResetSequenceProgress(NewSeq
);
193 if (NewSeq
== S_Stop
)
194 InsertReverseInsertPt(I
);
195 SetReleaseMetadata(ReleaseMetadata
);
196 SetKnownSafe(HasKnownPositiveRefCount());
197 SetTailCallRelease(cast
<CallInst
>(I
)->isTailCall());
199 SetKnownPositiveRefCount();
200 return NestingDetected
;
203 bool BottomUpPtrState::MatchWithRetain() {
204 SetKnownPositiveRefCount();
206 Sequence OldSeq
= GetSeq();
209 case S_MovableRelease
:
211 // If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
212 // imprecise release, clear our reverse insertion points.
213 if (OldSeq
!= S_Use
|| IsTrackingImpreciseReleases())
214 ClearReverseInsertPts();
221 llvm_unreachable("bottom-up pointer in retain state!");
223 llvm_unreachable("Sequence unknown enum value");
226 bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction
*Inst
,
228 ProvenanceAnalysis
&PA
,
230 Sequence S
= GetSeq();
232 // Check for possible releases.
233 if (!CanDecrementRefCount(Inst
, Ptr
, PA
, Class
))
236 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S
<< "; "
240 SetSeq(S_CanRelease
);
243 case S_MovableRelease
:
248 llvm_unreachable("bottom-up pointer in retain state!");
250 llvm_unreachable("Sequence unknown enum value");
253 void BottomUpPtrState::HandlePotentialUse(BasicBlock
*BB
, Instruction
*Inst
,
255 ProvenanceAnalysis
&PA
,
257 auto SetSeqAndInsertReverseInsertPt
= [&](Sequence NewSeq
){
258 assert(!HasReverseInsertPts());
260 // If this is an invoke instruction, we're scanning it as part of
261 // one of its successor blocks, since we can't insert code after it
262 // in its own block, and we don't want to split critical edges.
263 BasicBlock::iterator InsertAfter
;
264 if (isa
<InvokeInst
>(Inst
)) {
265 const auto IP
= BB
->getFirstInsertionPt();
266 InsertAfter
= IP
== BB
->end() ? std::prev(BB
->end()) : IP
;
267 if (isa
<CatchSwitchInst
>(InsertAfter
))
268 // A catchswitch must be the only non-phi instruction in its basic
269 // block, so attempting to insert an instruction into such a block would
270 // produce invalid IR.
271 SetCFGHazardAfflicted(true);
273 InsertAfter
= std::next(Inst
->getIterator());
276 if (InsertAfter
!= BB
->end())
277 InsertAfter
= skipDebugIntrinsics(InsertAfter
);
279 InsertReverseInsertPt(&*InsertAfter
);
281 // Don't insert anything between a call/invoke with operand bundle
282 // "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
284 if (auto *CB
= dyn_cast
<CallBase
>(Inst
))
285 if (objcarc::hasAttachedCallOpBundle(CB
))
286 SetCFGHazardAfflicted(true);
289 // Check for possible direct uses.
291 case S_MovableRelease
:
292 if (CanUse(Inst
, Ptr
, PA
, Class
)) {
293 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
295 SetSeqAndInsertReverseInsertPt(S_Use
);
296 } else if (const auto *Call
= getreturnRVOperand(*Inst
, Class
)) {
297 if (CanUse(Call
, Ptr
, PA
, GetBasicARCInstKind(Call
))) {
298 LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
300 SetSeqAndInsertReverseInsertPt(S_Stop
);
305 if (CanUse(Inst
, Ptr
, PA
, Class
)) {
306 LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq()
307 << "; " << *Ptr
<< "\n");
316 llvm_unreachable("bottom-up pointer in retain state!");
320 //===----------------------------------------------------------------------===//
322 //===----------------------------------------------------------------------===//
324 bool TopDownPtrState::InitTopDown(ARCInstKind Kind
, Instruction
*I
) {
325 bool NestingDetected
= false;
326 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
328 // better to let it remain as the first instruction after a call.
329 if (Kind
!= ARCInstKind::RetainRV
) {
330 // If we see two retains in a row on the same pointer. If so, make
331 // a note, and we'll cicle back to revisit it after we've
332 // hopefully eliminated the second retain, which may allow us to
333 // eliminate the first retain too.
334 // Theoretically we could implement removal of nested retain+release
335 // pairs by making PtrState hold a stack of states, but this is
336 // simple and avoids adding overhead for the non-nested case.
337 if (GetSeq() == S_Retain
)
338 NestingDetected
= true;
340 ResetSequenceProgress(S_Retain
);
341 SetKnownSafe(HasKnownPositiveRefCount());
345 SetKnownPositiveRefCount();
346 return NestingDetected
;
349 bool TopDownPtrState::MatchWithRelease(ARCMDKindCache
&Cache
,
350 Instruction
*Release
) {
351 ClearKnownPositiveRefCount();
353 Sequence OldSeq
= GetSeq();
355 MDNode
*ReleaseMetadata
=
356 Release
->getMetadata(Cache
.get(ARCMDKindID::ImpreciseRelease
));
361 if (OldSeq
== S_Retain
|| ReleaseMetadata
!= nullptr)
362 ClearReverseInsertPts();
365 SetReleaseMetadata(ReleaseMetadata
);
366 SetTailCallRelease(cast
<CallInst
>(Release
)->isTailCall());
371 case S_MovableRelease
:
372 llvm_unreachable("top-down pointer in bottom up state!");
374 llvm_unreachable("Sequence unknown enum value");
377 bool TopDownPtrState::HandlePotentialAlterRefCount(
378 Instruction
*Inst
, const Value
*Ptr
, ProvenanceAnalysis
&PA
,
379 ARCInstKind Class
, const BundledRetainClaimRVs
&BundledRVs
) {
380 // Check for possible releases. Treat clang.arc.use as a releasing instruction
381 // to prevent sinking a retain past it.
382 if (!CanDecrementRefCount(Inst
, Ptr
, PA
, Class
) &&
383 Class
!= ARCInstKind::IntrinsicUser
)
386 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; "
388 ClearKnownPositiveRefCount();
391 SetSeq(S_CanRelease
);
392 assert(!HasReverseInsertPts());
393 InsertReverseInsertPt(Inst
);
395 // Don't insert anything between a call/invoke with operand bundle
396 // "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
398 if (BundledRVs
.contains(Inst
))
399 SetCFGHazardAfflicted(true);
401 // One call can't cause a transition from S_Retain to S_CanRelease
402 // and S_CanRelease to S_Use. If we've made the first transition,
410 case S_MovableRelease
:
411 llvm_unreachable("top-down pointer in release state!");
413 llvm_unreachable("covered switch is not covered!?");
416 void TopDownPtrState::HandlePotentialUse(Instruction
*Inst
, const Value
*Ptr
,
417 ProvenanceAnalysis
&PA
,
419 // Check for possible direct uses.
422 if (!CanUse(Inst
, Ptr
, PA
, Class
))
424 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
433 case S_MovableRelease
:
434 llvm_unreachable("top-down pointer in release state!");