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());
279 if (InsertAfter
!= BB
->end())
280 InsertAfter
= skipDebugIntrinsics(InsertAfter
);
282 InsertReverseInsertPt(&*InsertAfter
);
285 // Check for possible direct uses.
288 case S_MovableRelease
:
289 if (CanUse(Inst
, Ptr
, PA
, Class
)) {
290 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
292 SetSeqAndInsertReverseInsertPt(S_Use
);
293 } else if (Seq
== S_Release
&& IsUser(Class
)) {
294 LLVM_DEBUG(dbgs() << " PreciseReleaseUse: Seq: " << GetSeq()
295 << "; " << *Ptr
<< "\n");
296 // Non-movable releases depend on any possible objc pointer use.
297 SetSeqAndInsertReverseInsertPt(S_Stop
);
298 } else if (const auto *Call
= getreturnRVOperand(*Inst
, Class
)) {
299 if (CanUse(Call
, Ptr
, PA
, GetBasicARCInstKind(Call
))) {
300 LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
302 SetSeqAndInsertReverseInsertPt(S_Stop
);
307 if (CanUse(Inst
, Ptr
, PA
, Class
)) {
308 LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq()
309 << "; " << *Ptr
<< "\n");
318 llvm_unreachable("bottom-up pointer in retain state!");
322 //===----------------------------------------------------------------------===//
324 //===----------------------------------------------------------------------===//
326 bool TopDownPtrState::InitTopDown(ARCInstKind Kind
, Instruction
*I
) {
327 bool NestingDetected
= false;
328 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
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;
342 ResetSequenceProgress(S_Retain
);
343 SetKnownSafe(HasKnownPositiveRefCount());
347 SetKnownPositiveRefCount();
348 return NestingDetected
;
351 bool TopDownPtrState::MatchWithRelease(ARCMDKindCache
&Cache
,
352 Instruction
*Release
) {
353 ClearKnownPositiveRefCount();
355 Sequence OldSeq
= GetSeq();
357 MDNode
*ReleaseMetadata
=
358 Release
->getMetadata(Cache
.get(ARCMDKindID::ImpreciseRelease
));
363 if (OldSeq
== S_Retain
|| ReleaseMetadata
!= nullptr)
364 ClearReverseInsertPts();
367 SetReleaseMetadata(ReleaseMetadata
);
368 SetTailCallRelease(cast
<CallInst
>(Release
)->isTailCall());
374 case S_MovableRelease
:
375 llvm_unreachable("top-down pointer in bottom up state!");
377 llvm_unreachable("Sequence unknown enum value");
380 bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction
*Inst
,
382 ProvenanceAnalysis
&PA
,
384 // 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
)
390 LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; "
392 ClearKnownPositiveRefCount();
395 SetSeq(S_CanRelease
);
396 assert(!HasReverseInsertPts());
397 InsertReverseInsertPt(Inst
);
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,
409 case S_MovableRelease
:
410 llvm_unreachable("top-down pointer in release state!");
412 llvm_unreachable("covered switch is not covered!?");
415 void TopDownPtrState::HandlePotentialUse(Instruction
*Inst
, const Value
*Ptr
,
416 ProvenanceAnalysis
&PA
,
418 // Check for possible direct uses.
421 if (!CanUse(Inst
, Ptr
, PA
, Class
))
423 LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
433 case S_MovableRelease
:
434 llvm_unreachable("top-down pointer in release state!");