Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/ObjCARC/PtrState.cpp
35266 views
1
//===- PtrState.cpp -------------------------------------------------------===//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "PtrState.h"
10
#include "DependencyAnalysis.h"
11
#include "ObjCARC.h"
12
#include "llvm/Analysis/ObjCARCAnalysisUtils.h"
13
#include "llvm/Analysis/ObjCARCInstKind.h"
14
#include "llvm/Analysis/ObjCARCUtil.h"
15
#include "llvm/IR/BasicBlock.h"
16
#include "llvm/IR/Instruction.h"
17
#include "llvm/IR/Instructions.h"
18
#include "llvm/IR/Value.h"
19
#include "llvm/Support/Casting.h"
20
#include "llvm/Support/Compiler.h"
21
#include "llvm/Support/Debug.h"
22
#include "llvm/Support/ErrorHandling.h"
23
#include "llvm/Support/raw_ostream.h"
24
#include <cassert>
25
#include <iterator>
26
#include <utility>
27
28
using namespace llvm;
29
using namespace llvm::objcarc;
30
31
#define DEBUG_TYPE "objc-arc-ptr-state"
32
33
//===----------------------------------------------------------------------===//
34
// Utility
35
//===----------------------------------------------------------------------===//
36
37
raw_ostream &llvm::objcarc::operator<<(raw_ostream &OS, const Sequence S) {
38
switch (S) {
39
case S_None:
40
return OS << "S_None";
41
case S_Retain:
42
return OS << "S_Retain";
43
case S_CanRelease:
44
return OS << "S_CanRelease";
45
case S_Use:
46
return OS << "S_Use";
47
case S_MovableRelease:
48
return OS << "S_MovableRelease";
49
case S_Stop:
50
return OS << "S_Stop";
51
}
52
llvm_unreachable("Unknown sequence type.");
53
}
54
55
//===----------------------------------------------------------------------===//
56
// Sequence
57
//===----------------------------------------------------------------------===//
58
59
static Sequence MergeSeqs(Sequence A, Sequence B, bool TopDown) {
60
// The easy cases.
61
if (A == B)
62
return A;
63
if (A == S_None || B == S_None)
64
return S_None;
65
66
if (A > B)
67
std::swap(A, B);
68
if (TopDown) {
69
// Choose the side which is further along in the sequence.
70
if ((A == S_Retain || A == S_CanRelease) &&
71
(B == S_CanRelease || B == S_Use))
72
return B;
73
} else {
74
// Choose the side which is further along in the sequence.
75
if ((A == S_Use || A == S_CanRelease) &&
76
(B == S_Use || B == S_Stop || B == S_MovableRelease))
77
return A;
78
// If both sides are releases, choose the more conservative one.
79
if (A == S_Stop && B == S_MovableRelease)
80
return A;
81
}
82
83
return S_None;
84
}
85
86
//===----------------------------------------------------------------------===//
87
// RRInfo
88
//===----------------------------------------------------------------------===//
89
90
void RRInfo::clear() {
91
KnownSafe = false;
92
IsTailCallRelease = false;
93
ReleaseMetadata = nullptr;
94
Calls.clear();
95
ReverseInsertPts.clear();
96
CFGHazardAfflicted = false;
97
}
98
99
bool RRInfo::Merge(const RRInfo &Other) {
100
// Conservatively merge the ReleaseMetadata information.
101
if (ReleaseMetadata != Other.ReleaseMetadata)
102
ReleaseMetadata = nullptr;
103
104
// Conservatively merge the boolean state.
105
KnownSafe &= Other.KnownSafe;
106
IsTailCallRelease &= Other.IsTailCallRelease;
107
CFGHazardAfflicted |= Other.CFGHazardAfflicted;
108
109
// Merge the call sets.
110
Calls.insert(Other.Calls.begin(), Other.Calls.end());
111
112
// Merge the insert point sets. If there are any differences,
113
// that makes this a partial merge.
114
bool Partial = ReverseInsertPts.size() != Other.ReverseInsertPts.size();
115
for (Instruction *Inst : Other.ReverseInsertPts)
116
Partial |= ReverseInsertPts.insert(Inst).second;
117
return Partial;
118
}
119
120
//===----------------------------------------------------------------------===//
121
// PtrState
122
//===----------------------------------------------------------------------===//
123
124
void PtrState::SetKnownPositiveRefCount() {
125
LLVM_DEBUG(dbgs() << " Setting Known Positive.\n");
126
KnownPositiveRefCount = true;
127
}
128
129
void PtrState::ClearKnownPositiveRefCount() {
130
LLVM_DEBUG(dbgs() << " Clearing Known Positive.\n");
131
KnownPositiveRefCount = false;
132
}
133
134
void PtrState::SetSeq(Sequence NewSeq) {
135
LLVM_DEBUG(dbgs() << " Old: " << GetSeq() << "; New: " << NewSeq
136
<< "\n");
137
Seq = NewSeq;
138
}
139
140
void PtrState::ResetSequenceProgress(Sequence NewSeq) {
141
LLVM_DEBUG(dbgs() << " Resetting sequence progress.\n");
142
SetSeq(NewSeq);
143
Partial = false;
144
RRI.clear();
145
}
146
147
void PtrState::Merge(const PtrState &Other, bool TopDown) {
148
Seq = MergeSeqs(GetSeq(), Other.GetSeq(), TopDown);
149
KnownPositiveRefCount &= Other.KnownPositiveRefCount;
150
151
// If we're not in a sequence (anymore), drop all associated state.
152
if (Seq == S_None) {
153
Partial = false;
154
RRI.clear();
155
} else if (Partial || Other.Partial) {
156
// If we're doing a merge on a path that's previously seen a partial
157
// merge, conservatively drop the sequence, to avoid doing partial
158
// RR elimination. If the branch predicates for the two merge differ,
159
// mixing them is unsafe.
160
ClearSequenceProgress();
161
} else {
162
// Otherwise merge the other PtrState's RRInfo into our RRInfo. At this
163
// point, we know that currently we are not partial. Stash whether or not
164
// the merge operation caused us to undergo a partial merging of reverse
165
// insertion points.
166
Partial = RRI.Merge(Other.RRI);
167
}
168
}
169
170
//===----------------------------------------------------------------------===//
171
// BottomUpPtrState
172
//===----------------------------------------------------------------------===//
173
174
bool BottomUpPtrState::InitBottomUp(ARCMDKindCache &Cache, Instruction *I) {
175
// If we see two releases in a row on the same pointer. If so, make
176
// a note, and we'll cicle back to revisit it after we've
177
// hopefully eliminated the second release, which may allow us to
178
// eliminate the first release too.
179
// Theoretically we could implement removal of nested retain+release
180
// pairs by making PtrState hold a stack of states, but this is
181
// simple and avoids adding overhead for the non-nested case.
182
bool NestingDetected = false;
183
if (GetSeq() == S_MovableRelease) {
184
LLVM_DEBUG(
185
dbgs() << " Found nested releases (i.e. a release pair)\n");
186
NestingDetected = true;
187
}
188
189
MDNode *ReleaseMetadata =
190
I->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
191
Sequence NewSeq = ReleaseMetadata ? S_MovableRelease : S_Stop;
192
ResetSequenceProgress(NewSeq);
193
if (NewSeq == S_Stop)
194
InsertReverseInsertPt(I);
195
SetReleaseMetadata(ReleaseMetadata);
196
SetKnownSafe(HasKnownPositiveRefCount());
197
SetTailCallRelease(cast<CallInst>(I)->isTailCall());
198
InsertCall(I);
199
SetKnownPositiveRefCount();
200
return NestingDetected;
201
}
202
203
bool BottomUpPtrState::MatchWithRetain() {
204
SetKnownPositiveRefCount();
205
206
Sequence OldSeq = GetSeq();
207
switch (OldSeq) {
208
case S_Stop:
209
case S_MovableRelease:
210
case S_Use:
211
// If OldSeq is not S_Use or OldSeq is S_Use and we are tracking an
212
// imprecise release, clear our reverse insertion points.
213
if (OldSeq != S_Use || IsTrackingImpreciseReleases())
214
ClearReverseInsertPts();
215
[[fallthrough]];
216
case S_CanRelease:
217
return true;
218
case S_None:
219
return false;
220
case S_Retain:
221
llvm_unreachable("bottom-up pointer in retain state!");
222
}
223
llvm_unreachable("Sequence unknown enum value");
224
}
225
226
bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst,
227
const Value *Ptr,
228
ProvenanceAnalysis &PA,
229
ARCInstKind Class) {
230
Sequence S = GetSeq();
231
232
// Check for possible releases.
233
if (!CanDecrementRefCount(Inst, Ptr, PA, Class))
234
return false;
235
236
LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; "
237
<< *Ptr << "\n");
238
switch (S) {
239
case S_Use:
240
SetSeq(S_CanRelease);
241
return true;
242
case S_CanRelease:
243
case S_MovableRelease:
244
case S_Stop:
245
case S_None:
246
return false;
247
case S_Retain:
248
llvm_unreachable("bottom-up pointer in retain state!");
249
}
250
llvm_unreachable("Sequence unknown enum value");
251
}
252
253
void BottomUpPtrState::HandlePotentialUse(BasicBlock *BB, Instruction *Inst,
254
const Value *Ptr,
255
ProvenanceAnalysis &PA,
256
ARCInstKind Class) {
257
auto SetSeqAndInsertReverseInsertPt = [&](Sequence NewSeq){
258
assert(!HasReverseInsertPts());
259
SetSeq(NewSeq);
260
// If this is an invoke instruction, we're scanning it as part of
261
// one of its successor blocks, since we can't insert code after it
262
// in its own block, and we don't want to split critical edges.
263
BasicBlock::iterator InsertAfter;
264
if (isa<InvokeInst>(Inst)) {
265
const auto IP = BB->getFirstInsertionPt();
266
InsertAfter = IP == BB->end() ? std::prev(BB->end()) : IP;
267
if (isa<CatchSwitchInst>(InsertAfter))
268
// A catchswitch must be the only non-phi instruction in its basic
269
// block, so attempting to insert an instruction into such a block would
270
// produce invalid IR.
271
SetCFGHazardAfflicted(true);
272
} else {
273
InsertAfter = std::next(Inst->getIterator());
274
}
275
276
if (InsertAfter != BB->end())
277
InsertAfter = skipDebugIntrinsics(InsertAfter);
278
279
InsertReverseInsertPt(&*InsertAfter);
280
281
// Don't insert anything between a call/invoke with operand bundle
282
// "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
283
// result.
284
if (auto *CB = dyn_cast<CallBase>(Inst))
285
if (objcarc::hasAttachedCallOpBundle(CB))
286
SetCFGHazardAfflicted(true);
287
};
288
289
// Check for possible direct uses.
290
switch (GetSeq()) {
291
case S_MovableRelease:
292
if (CanUse(Inst, Ptr, PA, Class)) {
293
LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
294
<< *Ptr << "\n");
295
SetSeqAndInsertReverseInsertPt(S_Use);
296
} else if (const auto *Call = getreturnRVOperand(*Inst, Class)) {
297
if (CanUse(Call, Ptr, PA, GetBasicARCInstKind(Call))) {
298
LLVM_DEBUG(dbgs() << " ReleaseUse: Seq: " << GetSeq() << "; "
299
<< *Ptr << "\n");
300
SetSeqAndInsertReverseInsertPt(S_Stop);
301
}
302
}
303
break;
304
case S_Stop:
305
if (CanUse(Inst, Ptr, PA, Class)) {
306
LLVM_DEBUG(dbgs() << " PreciseStopUse: Seq: " << GetSeq()
307
<< "; " << *Ptr << "\n");
308
SetSeq(S_Use);
309
}
310
break;
311
case S_CanRelease:
312
case S_Use:
313
case S_None:
314
break;
315
case S_Retain:
316
llvm_unreachable("bottom-up pointer in retain state!");
317
}
318
}
319
320
//===----------------------------------------------------------------------===//
321
// TopDownPtrState
322
//===----------------------------------------------------------------------===//
323
324
bool TopDownPtrState::InitTopDown(ARCInstKind Kind, Instruction *I) {
325
bool NestingDetected = false;
326
// Don't do retain+release tracking for ARCInstKind::RetainRV, because
327
// it's
328
// better to let it remain as the first instruction after a call.
329
if (Kind != ARCInstKind::RetainRV) {
330
// If we see two retains in a row on the same pointer. If so, make
331
// a note, and we'll cicle back to revisit it after we've
332
// hopefully eliminated the second retain, which may allow us to
333
// eliminate the first retain too.
334
// Theoretically we could implement removal of nested retain+release
335
// pairs by making PtrState hold a stack of states, but this is
336
// simple and avoids adding overhead for the non-nested case.
337
if (GetSeq() == S_Retain)
338
NestingDetected = true;
339
340
ResetSequenceProgress(S_Retain);
341
SetKnownSafe(HasKnownPositiveRefCount());
342
InsertCall(I);
343
}
344
345
SetKnownPositiveRefCount();
346
return NestingDetected;
347
}
348
349
bool TopDownPtrState::MatchWithRelease(ARCMDKindCache &Cache,
350
Instruction *Release) {
351
ClearKnownPositiveRefCount();
352
353
Sequence OldSeq = GetSeq();
354
355
MDNode *ReleaseMetadata =
356
Release->getMetadata(Cache.get(ARCMDKindID::ImpreciseRelease));
357
358
switch (OldSeq) {
359
case S_Retain:
360
case S_CanRelease:
361
if (OldSeq == S_Retain || ReleaseMetadata != nullptr)
362
ClearReverseInsertPts();
363
[[fallthrough]];
364
case S_Use:
365
SetReleaseMetadata(ReleaseMetadata);
366
SetTailCallRelease(cast<CallInst>(Release)->isTailCall());
367
return true;
368
case S_None:
369
return false;
370
case S_Stop:
371
case S_MovableRelease:
372
llvm_unreachable("top-down pointer in bottom up state!");
373
}
374
llvm_unreachable("Sequence unknown enum value");
375
}
376
377
bool TopDownPtrState::HandlePotentialAlterRefCount(
378
Instruction *Inst, const Value *Ptr, ProvenanceAnalysis &PA,
379
ARCInstKind Class, const BundledRetainClaimRVs &BundledRVs) {
380
// Check for possible releases. Treat clang.arc.use as a releasing instruction
381
// to prevent sinking a retain past it.
382
if (!CanDecrementRefCount(Inst, Ptr, PA, Class) &&
383
Class != ARCInstKind::IntrinsicUser)
384
return false;
385
386
LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << GetSeq() << "; "
387
<< *Ptr << "\n");
388
ClearKnownPositiveRefCount();
389
switch (GetSeq()) {
390
case S_Retain:
391
SetSeq(S_CanRelease);
392
assert(!HasReverseInsertPts());
393
InsertReverseInsertPt(Inst);
394
395
// Don't insert anything between a call/invoke with operand bundle
396
// "clang.arc.attachedcall" and the retainRV/claimRV call that uses the call
397
// result.
398
if (BundledRVs.contains(Inst))
399
SetCFGHazardAfflicted(true);
400
401
// One call can't cause a transition from S_Retain to S_CanRelease
402
// and S_CanRelease to S_Use. If we've made the first transition,
403
// we're done.
404
return true;
405
case S_Use:
406
case S_CanRelease:
407
case S_None:
408
return false;
409
case S_Stop:
410
case S_MovableRelease:
411
llvm_unreachable("top-down pointer in release state!");
412
}
413
llvm_unreachable("covered switch is not covered!?");
414
}
415
416
void TopDownPtrState::HandlePotentialUse(Instruction *Inst, const Value *Ptr,
417
ProvenanceAnalysis &PA,
418
ARCInstKind Class) {
419
// Check for possible direct uses.
420
switch (GetSeq()) {
421
case S_CanRelease:
422
if (!CanUse(Inst, Ptr, PA, Class))
423
return;
424
LLVM_DEBUG(dbgs() << " CanUse: Seq: " << GetSeq() << "; "
425
<< *Ptr << "\n");
426
SetSeq(S_Use);
427
return;
428
case S_Retain:
429
case S_Use:
430
case S_None:
431
return;
432
case S_Stop:
433
case S_MovableRelease:
434
llvm_unreachable("top-down pointer in release state!");
435
}
436
}
437
438