1 //===--- PtrState.cpp -----------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #define DEBUG_TYPE "objc-arc-ptr-state"
11 #include "llvm/Support/Debug.h"
16 using namespace llvm::objcarc;
18 raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
21 return OS << "S_None";
23 return OS << "S_Retain";
25 return OS << "S_CanRelease";
29 return OS << "S_Release";
30 case S_MovableRelease:
31 return OS << "S_MovableRelease";
33 return OS << "S_Stop";
35 llvm_unreachable("Unknown sequence type.");
38 static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
42 if (A == S_None || B == S_None)
48 // Choose the side which is further along in the sequence.
49 if ((A == S_Retain || A == S_CanRelease) &&
50 (B == S_CanRelease || B == S_Use))
53 // Choose the side which is further along in the sequence.
54 if ((A == S_Use || A == S_CanRelease) &&
55 (B == S_Use || B == S_Release || B == S_Stop || B == S_MovableRelease))
57 // If both sides are releases, choose the more conservative one.
58 if (A == S_Stop && (B == S_Release || B == S_MovableRelease))
60 if (A == S_Release && B == S_MovableRelease)
67 void RRInfo::clear() {
69 IsTailCallRelease = false;
70 ReleaseMetadata = nullptr;
72 ReverseInsertPts.clear();
73 CFGHazardAfflicted = false;
76 bool RRInfo::Merge(const RRInfo &Other) {
77 // Conservatively merge the ReleaseMetadata information.
78 if (ReleaseMetadata != Other.ReleaseMetadata)
79 ReleaseMetadata = nullptr;
81 // Conservatively merge the boolean state.
82 KnownSafe &= Other.KnownSafe;
83 IsTailCallRelease &= Other.IsTailCallRelease;
84 CFGHazardAfflicted |= Other.CFGHazardAfflicted;
86 // Merge the call sets.
87 Calls.insert(Other.Calls.begin(), Other.Calls.end());
89 // Merge the insert point sets. If there are any differences,
90 // that makes this a partial merge.
91 bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
92 for (Instruction *Inst : Other.ReverseInsertPts)
93 Partial |= ReverseInsertPts.insert(Inst).second;
97 void PtrState::SetKnownPositiveRefCount() {
98 DEBUG(dbgs() << "Setting Known Positive.\n");
99 KnownPositiveRefCount = true;
102 void PtrState::ClearKnownPositiveRefCount() {
103 DEBUG(dbgs() << "Clearing Known Positive.\n");
104 KnownPositiveRefCount = false;
107 void PtrState::SetSeq(Sequence NewSeq) {
108 DEBUG(dbgs() << "Old: " << Seq << "; New: " << NewSeq << "\n");
112 void PtrState::ResetSequenceProgress(Sequence NewSeq) {
113 DEBUG(dbgs() << "Resetting sequence progress.\n");
119 void PtrState::Merge(const PtrState &Other, bool TopDown) {
120 Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
121 KnownPositiveRefCount &= Other.KnownPositiveRefCount;
123 // If we're not in a sequence (anymore), drop all associated state.
127 } else if (Partial || Other.Partial) {
128 // If we're doing a merge on a path that's previously seen a partial
129 // merge, conservatively drop the sequence, to avoid doing partial
130 // RR elimination. If the branch predicates for the two merge differ,
131 // mixing them is unsafe.
132 ClearSequenceProgress();
134 // Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
135 // point, we know that currently we are not partial. Stash whether or not
136 // the merge operation caused us to undergo a partial merging of reverse
138 Partial = RRI.Merge(Other.RRI);
142 bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
143 // If we see two releases in a row on the same pointer. If so, make
144 // a note, and we'll cicle back to revisit it after we've
145 // hopefully eliminated the second release, which may allow us to
146 // eliminate the first release too.
147 // Theoretically we could implement removal of nested retain+release
148 // pairs by making PtrState hold a stack of states, but this is
149 // simple and avoids adding overhead for the non-nested case.
150 bool NestingDetected = false;
151 if (GetSeq() == S_Release || GetSeq() == S_MovableRelease) {
152 DEBUG(dbgs() << "Found nested releases (i.e. a release pair)\n");
153 NestingDetected = true;
156 MDNode *ReleaseMetadata = I->getMetadata(Cache.ImpreciseReleaseMDKind);
157 Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Release;
158 ResetSequenceProgress(NewSeq);
159 SetReleaseMetadata(ReleaseMetadata);
160 SetKnownSafe(HasKnownPositiveRefCount());
161 SetTailCallRelease(cast<CallInst>(I)->isTailCall());
163 SetKnownPositiveRefCount();
164 return NestingDetected;
167 bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
168 bool NestingDetected = false;
169 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
171 // better to let it remain as the first instruction after a call.
172 if (Kind != ARCInstKind::RetainRV) {
173 // If we see two retains in a row on the same pointer. If so, make
174 // a note, and we'll cicle back to revisit it after we've
175 // hopefully eliminated the second retain, which may allow us to
176 // eliminate the first retain too.
177 // Theoretically we could implement removal of nested retain+release
178 // pairs by making PtrState hold a stack of states, but this is
179 // simple and avoids adding overhead for the non-nested case.
180 if (GetSeq() == S_Retain)
181 NestingDetected = true;
183 ResetSequenceProgress(S_Retain);
184 SetKnownSafe(HasKnownPositiveRefCount());
188 SetKnownPositiveRefCount();
189 return NestingDetected;