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/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"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/ErrorHandling.h"
22 #include "llvm/Support/raw_ostream.h"
28 using namespace llvm::objcarc
;
30 #define DEBUG_TYPE "objc-arc-ptr-state"
32 //===----------------------------------------------------------------------===//
34 //===----------------------------------------------------------------------===//
36 raw_ostream
&llvm::objcarc::operator<<(raw_ostream
&OS
, const Sequence S
) {
39 return OS
<< "S_None";
41 return OS
<< "S_Retain";
43 return OS
<< "S_CanRelease";
47 return OS
<< "S_Release";
48 case S_MovableRelease
:
49 return OS
<< "S_MovableRelease";
51 return OS
<< "S_Stop";
53 llvm_unreachable("Unknown sequence type.");
56 //===----------------------------------------------------------------------===//
58 //===----------------------------------------------------------------------===//
60 static Sequence
MergeSeqs(Sequence A
, Sequence B
, bool TopDown
) {
64 if (A
== S_None
|| B
== S_None
)
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
))
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
))
79 // If both sides are releases, choose the more conservative one.
80 if (A
== S_Stop
&& (B
== S_Release
|| B
== S_MovableRelease
))
82 if (A
== S_Release
&& B
== S_MovableRelease
)
89 //===----------------------------------------------------------------------===//
91 //===----------------------------------------------------------------------===//
93 void RRInfo::clear() {
95 IsTailCallRelease
= false;
96 ReleaseMetadata
= nullptr;
98 ReverseInsertPts
.clear();
99 CFGHazardAfflicted
= false;
102 bool RRInfo::Merge(const RRInfo
&Other
) {
103 // Conservatively merge the ReleaseMetadata information.
104 if (ReleaseMetadata
!= Other
.ReleaseMetadata
)
105 ReleaseMetadata
= nullptr;
107 // Conservatively merge the boolean state.
108 KnownSafe
&= Other
.KnownSafe
;
109 IsTailCallRelease
&= Other
.IsTailCallRelease
;
110 CFGHazardAfflicted
|= Other
.CFGHazardAfflicted
;
112 // Merge the call sets.
113 Calls
.insert(Other
.Calls
.begin(), Other
.Calls
.end());
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
;
123 //===----------------------------------------------------------------------===//
125 //===----------------------------------------------------------------------===//
127 void PtrState::SetKnownPositiveRefCount() {
128 LLVM_DEBUG(dbgs() << " Setting Known Positive.\n");
129 KnownPositiveRefCount
= true;
132 void PtrState::ClearKnownPositiveRefCount() {
133 LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n");
134 KnownPositiveRefCount
= false;
137 void PtrState::SetSeq(Sequence NewSeq
) {
138 LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq
143 void PtrState::ResetSequenceProgress(Sequence NewSeq
) {
144 LLVM_DEBUG(dbgs() << " Resetting sequence progress.\n");
150 void PtrState::Merge(const PtrState
&Other
, bool TopDown
) {
151 Seq
= MergeSeqs(GetSeq(), Other
.GetSeq(), TopDown
);
152 KnownPositiveRefCount
&= Other
.KnownPositiveRefCount
;
154 // If we're not in a sequence (anymore), drop all associated state.
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();
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
169 Partial
= RRI
.Merge(Other
.RRI
);
173 //===----------------------------------------------------------------------===//
175 //===----------------------------------------------------------------------===//
177 bool 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
) {
188 dbgs() << " Found nested releases (i.e. a release pair)\n");
189 NestingDetected
= true;
192 MDNode
*ReleaseMetadata
=
193 I
->getMetadata(Cache
.get(ARCMDKindID::ImpreciseRelease
));
194 Sequence NewSeq
= ReleaseMetadata
? S_MovableRelease
: S_Release
;
195 ResetSequenceProgress(NewSeq
);
196 SetReleaseMetadata(ReleaseMetadata
);
197 SetKnownSafe(HasKnownPositiveRefCount());
198 SetTailCallRelease(cast
<CallInst
>(I
)->isTailCall());
200 SetKnownPositiveRefCount();
201 return NestingDetected
;
204 bool BottomUpPtrState::MatchWithRetain() {
205 SetKnownPositiveRefCount();
207 Sequence OldSeq
= GetSeq();
211 case S_MovableRelease
:
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();
223 llvm_unreachable("bottom-up pointer in retain state!");
225 llvm_unreachable("Sequence unknown enum value");
228 bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction
*Inst
,
230 ProvenanceAnalysis
&PA
,
232 Sequence S
= GetSeq();
234 // Check for possible releases.
235 if (!CanAlterRefCount(Inst
, Ptr
, PA
, Class
))
238 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S
<< "; "
242 SetSeq(S_CanRelease
);
246 case S_MovableRelease
:
251 llvm_unreachable("bottom-up pointer in retain state!");
253 llvm_unreachable("Sequence unknown enum value");
256 void BottomUpPtrState::HandlePotentialUse(BasicBlock
*BB
, Instruction
*Inst
,
258 ProvenanceAnalysis
&PA
,
260 auto SetSeqAndInsertReverseInsertPt
= [&](Sequence NewSeq
){
261 assert(!HasReverseInsertPts());
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.
266 BasicBlock::iterator InsertAfter
;
267 if (isa
<InvokeInst
>(Inst
)) {
268 const auto IP
= BB
->getFirstInsertionPt();
269 InsertAfter
= IP
== BB
->end() ? std::prev(BB
->end()) : IP
;
270 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);
276 InsertAfter
= std::next(Inst
->getIterator());
278 InsertReverseInsertPt(&*InsertAfter
);
281 // Check for possible direct uses.
284 case S_MovableRelease
:
285 if (CanUse(Inst
, Ptr
, PA
, Class
)) {
286 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
288 SetSeqAndInsertReverseInsertPt(S_Use
);
289 } else if (Seq
== S_Release
&& IsUser(Class
)) {
290 LLVM_DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq()
291 << "; " << *Ptr
<< "\n");
292 // Non-movable releases depend on any possible objc pointer use.
293 SetSeqAndInsertReverseInsertPt(S_Stop
);
294 } else if (const auto *Call
= getreturnRVOperand(*Inst
, Class
)) {
295 if (CanUse(Call
, Ptr
, PA
, GetBasicARCInstKind(Call
))) {
296 LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
298 SetSeqAndInsertReverseInsertPt(S_Stop
);
303 if (CanUse(Inst
, Ptr
, PA
, Class
)) {
304 LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq()
305 << "; " << *Ptr
<< "\n");
314 llvm_unreachable("bottom-up pointer in retain state!");
318 //===----------------------------------------------------------------------===//
320 //===----------------------------------------------------------------------===//
322 bool TopDownPtrState::InitTopDown(ARCInstKind Kind
, Instruction
*I
) {
323 bool NestingDetected
= false;
324 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
326 // better to let it remain as the first instruction after a call.
327 if (Kind
!= ARCInstKind::RetainRV
) {
328 // If we see two retains in a row on the same pointer. If so, make
329 // a note, and we'll cicle back to revisit it after we've
330 // hopefully eliminated the second retain, which may allow us to
331 // eliminate the first retain too.
332 // Theoretically we could implement removal of nested retain+release
333 // pairs by making PtrState hold a stack of states, but this is
334 // simple and avoids adding overhead for the non-nested case.
335 if (GetSeq() == S_Retain
)
336 NestingDetected
= true;
338 ResetSequenceProgress(S_Retain
);
339 SetKnownSafe(HasKnownPositiveRefCount());
343 SetKnownPositiveRefCount();
344 return NestingDetected
;
347 bool TopDownPtrState::MatchWithRelease(ARCMDKindCache
&Cache
,
348 Instruction
*Release
) {
349 ClearKnownPositiveRefCount();
351 Sequence OldSeq
= GetSeq();
353 MDNode
*ReleaseMetadata
=
354 Release
->getMetadata(Cache
.get(ARCMDKindID::ImpreciseRelease
));
359 if (OldSeq
== S_Retain
|| ReleaseMetadata
!= nullptr)
360 ClearReverseInsertPts();
363 SetReleaseMetadata(ReleaseMetadata
);
364 SetTailCallRelease(cast
<CallInst
>(Release
)->isTailCall());
370 case S_MovableRelease
:
371 llvm_unreachable("top-down pointer in bottom up state!");
373 llvm_unreachable("Sequence unknown enum value");
376 bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction
*Inst
,
378 ProvenanceAnalysis
&PA
,
380 // Check for possible releases. Treat clang.arc.use as a releasing instruction
381 // to prevent sinking a retain past it.
382 if (!CanAlterRefCount(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 // One call can't cause a transition from S_Retain to S_CanRelease
396 // and S_CanRelease to S_Use. If we've made the first transition,
405 case S_MovableRelease
:
406 llvm_unreachable("top-down pointer in release state!");
408 llvm_unreachable("covered switch is not covered!?");
411 void TopDownPtrState::HandlePotentialUse(Instruction
*Inst
, const Value
*Ptr
,
412 ProvenanceAnalysis
&PA
,
414 // Check for possible direct uses.
417 if (!CanUse(Inst
, Ptr
, PA
, Class
))
419 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
429 case S_MovableRelease
:
430 llvm_unreachable("top-down pointer in release state!");