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!");