blob: db4a81650e46c07b3c2a6784704d6f1a1c3074d5 [file] [log] [blame]
Michael Gottesman68b91db2015-03-05 23:29:03 +00001//===--- PtrState.cpp -----------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Michael Gottesmand45907b2015-03-05 23:57:07 +000010#define DEBUG_TYPE "objc-arc-ptr-state"
11#include "llvm/Support/Debug.h"
Michael Gottesman68b91db2015-03-05 23:29:03 +000012#include "PtrState.h"
Michael Gottesman4eae3962015-03-06 00:34:39 +000013#include "ObjCARC.h"
Michael Gottesman68b91db2015-03-05 23:29:03 +000014
15using namespace llvm;
16using namespace llvm::objcarc;
17
Michael Gottesmand45907b2015-03-05 23:57:07 +000018raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
Michael Gottesman68b91db2015-03-05 23:29:03 +000019 switch (S) {
20 case S_None:
21 return OS << "S_None";
22 case S_Retain:
23 return OS << "S_Retain";
24 case S_CanRelease:
25 return OS << "S_CanRelease";
26 case S_Use:
27 return OS << "S_Use";
28 case S_Release:
29 return OS << "S_Release";
30 case S_MovableRelease:
31 return OS << "S_MovableRelease";
32 case S_Stop:
33 return OS << "S_Stop";
34 }
35 llvm_unreachable("Unknown sequence type.");
36}
37
38static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
39 // The easy cases.
40 if (A == B)
41 return A;
42 if (A == S_None || B == S_None)
43 return S_None;
44
45 if (A > B)
46 std::swap(A, B);
47 if (TopDown) {
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))
51 return B;
52 } else {
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))
56 return A;
57 // If both sides are releases, choose the more conservative one.
58 if (A == S_Stop && (B == S_Release || B == S_MovableRelease))
59 return A;
60 if (A == S_Release && B == S_MovableRelease)
61 return A;
62 }
63
64 return S_None;
65}
66
67void RRInfo::clear() {
68 KnownSafe = false;
69 IsTailCallRelease = false;
70 ReleaseMetadata = nullptr;
71 Calls.clear();
72 ReverseInsertPts.clear();
73 CFGHazardAfflicted = false;
74}
75
76bool RRInfo::Merge(const RRInfo &Other) {
77 // Conservatively merge the ReleaseMetadata information.
78 if (ReleaseMetadata != Other.ReleaseMetadata)
79 ReleaseMetadata = nullptr;
80
81 // Conservatively merge the boolean state.
82 KnownSafe &= Other.KnownSafe;
83 IsTailCallRelease &= Other.IsTailCallRelease;
84 CFGHazardAfflicted |= Other.CFGHazardAfflicted;
85
86 // Merge the call sets.
87 Calls.insert(Other.Calls.begin(), Other.Calls.end());
88
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;
94 return Partial;
95}
96
Michael Gottesmand45907b2015-03-05 23:57:07 +000097void PtrState::SetKnownPositiveRefCount() {
98 DEBUG(dbgs() << "Setting Known Positive.\n");
99 KnownPositiveRefCount = true;
100}
101
102void PtrState::ClearKnownPositiveRefCount() {
103 DEBUG(dbgs() << "Clearing Known Positive.\n");
104 KnownPositiveRefCount = false;
105}
106
107void PtrState::SetSeq(Sequence NewSeq) {
108 DEBUG(dbgs() << "Old: " << Seq << "; New: " << NewSeq << "\n");
109 Seq = NewSeq;
110}
111
112void PtrState::ResetSequenceProgress(Sequence NewSeq) {
113 DEBUG(dbgs() << "Resetting sequence progress.\n");
114 SetSeq(NewSeq);
115 Partial = false;
116 RRI.clear();
117}
118
Michael Gottesman68b91db2015-03-05 23:29:03 +0000119void PtrState::Merge(const PtrState &Other, bool TopDown) {
120 Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
121 KnownPositiveRefCount &= Other.KnownPositiveRefCount;
122
123 // If we're not in a sequence (anymore), drop all associated state.
124 if (Seq == S_None) {
125 Partial = false;
126 RRI.clear();
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();
133 } else {
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
137 // insertion points.
138 Partial = RRI.Merge(Other.RRI);
139 }
140}
Michael Gottesman4eae3962015-03-06 00:34:39 +0000141
142bool 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;
154 }
155
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());
162 InsertCall(I);
163 SetKnownPositiveRefCount();
164 return NestingDetected;
165}
166
167bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
168 bool NestingDetected = false;
169 // Don't do retain+release tracking for ARCInstKind::RetainRV, because
170 // it's
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;
182
183 ResetSequenceProgress(S_Retain);
184 SetKnownSafe(HasKnownPositiveRefCount());
185 InsertCall(I);
186 }
187
188 SetKnownPositiveRefCount();
189 return NestingDetected;
190}