21
21
#ifndef SWIFT_SIL_ADDRESSWALKER_H
22
22
#define SWIFT_SIL_ADDRESSWALKER_H
23
23
24
+ #include " swift/Basic/Defer.h"
24
25
#include " swift/SIL/AddressUseKind.h"
26
+ #include " swift/SIL/BasicBlockDatastructures.h"
27
+ #include " swift/SIL/InstructionUtils.h"
28
+ #include " swift/SIL/Projection.h"
25
29
#include " swift/SIL/SILValue.h"
26
30
27
31
namespace swift {
@@ -33,15 +37,16 @@ namespace swift {
33
37
// / Validated by the SIL verifier as always being able to visit all addresses
34
38
// / derived from alloc_stack, ref_element_addr, project_box, ref_tail_addr and
35
39
// / all other address roots.
40
+ template <typename Impl>
36
41
class TransitiveAddressWalker {
37
42
// / Whether we could tell if this address use didn't escape, did have a
38
43
// / pointer escape, or unknown if we failed to understand something.
39
44
AddressUseKind result = AddressUseKind::NonEscaping;
40
45
41
46
unsigned didInvalidate = false ;
42
47
43
- public:
44
- virtual ~TransitiveAddressWalker () { }
48
+ Impl & asImpl () { return * reinterpret_cast <Impl *>( this ); }
49
+ const Impl & asImpl () const { return * reinterpret_cast < const Impl *>( this ); }
45
50
46
51
protected:
47
52
// / Customization point for visiting uses. Returns true if we should continue
@@ -50,9 +55,17 @@ class TransitiveAddressWalker {
50
55
// / NOTE: Do not call this directly from within
51
56
// / findTransitiveUsesForAddress. Please call callVisitUse. This is intended
52
57
// / just for subclasses to override.
53
- virtual bool visitUse (Operand *use) { return true ; }
58
+ bool visitUse (Operand *use) { return true ; }
59
+
60
+ // / Customization point for visiting operands that we were unable to
61
+ // / understand. These cause us to return AddressUseKind::Unknown.
62
+ void onError (Operand *use) {}
54
63
55
- virtual void onError (Operand *use) {}
64
+ // / Customization point that causes the walker to treat a specific transitive
65
+ // / use as an end point use.
66
+ // /
67
+ // / Example: Visiting a mutable or immutable open_existential_addr.
68
+ bool visitTransitiveUseAsEndPointUse (Operand *use) { return false ; }
56
69
57
70
void meet (AddressUseKind other) {
58
71
assert (!didInvalidate);
@@ -63,21 +76,219 @@ class TransitiveAddressWalker {
63
76
// / Shim that actually calls visitUse and changes early exit.
64
77
void callVisitUse (Operand *use) {
65
78
assert (!didInvalidate);
66
- if (!visitUse (use))
79
+ if (!asImpl (). visitUse (use))
67
80
result = AddressUseKind::Unknown;
68
81
}
69
82
70
83
public:
71
84
AddressUseKind walk (SILValue address) &&;
72
85
};
73
86
74
- // / The algorithm that is used to determine what the verifier will consider to
75
- // / be transitive uses of the given address. Used to implement \see
76
- // / findTransitiveUses.
77
- // /
78
- // / Returns \p AccessUseKind::Unknown on error.
79
- AddressUseKind findTransitiveUsesForAddress (SILValue address,
80
- TransitiveAddressWalker &visitor);
87
+ template <typename Impl>
88
+ inline AddressUseKind
89
+ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) && {
90
+ assert (!didInvalidate);
91
+
92
+ // When we exit, set the result to be invalidated so we can't use this again.
93
+ SWIFT_DEFER { didInvalidate = true ; };
94
+
95
+ StackList<Operand *> worklist (projectedAddress->getFunction ());
96
+ SmallPtrSet<Operand *, 32 > visitedOperands;
97
+
98
+ auto addToWorklist = [&](Operand *use) {
99
+ if (visitedOperands.insert (use).second )
100
+ worklist.push_back (use);
101
+ };
102
+
103
+ for (auto *use : projectedAddress->getUses ()) {
104
+ addToWorklist (use);
105
+ }
106
+
107
+ // Record all uses that aren't transitively followed. These are either
108
+ // instanteneous uses of the addres, or cause a pointer escape.
109
+ auto transitiveResultUses = [&](Operand *use) {
110
+ auto *svi = cast<SingleValueInstruction>(use->getUser ());
111
+ if (svi->use_empty ()) {
112
+ return callVisitUse (use);
113
+ }
114
+
115
+ if (asImpl ().visitTransitiveUseAsEndPointUse (use))
116
+ return callVisitUse (use);
117
+
118
+ for (auto *use : svi->getUses ())
119
+ addToWorklist (use);
120
+ };
121
+
122
+ while (!worklist.empty ()) {
123
+ if (result == AddressUseKind::Unknown)
124
+ return AddressUseKind::Unknown;
125
+
126
+ auto *op = worklist.pop_back_val ();
127
+
128
+ // Skip type dependent operands.
129
+ if (op->isTypeDependent ())
130
+ continue ;
131
+
132
+ // Then update the worklist with new things to find if we recognize this
133
+ // inst and then continue. If we fail, we emit an error at the bottom of the
134
+ // loop that we didn't recognize the user.
135
+ auto *user = op->getUser ();
136
+
137
+ if (auto *ti = dyn_cast<TermInst>(user)) {
138
+ switch (ti->getTermKind ()) {
139
+ case TermKind::BranchInst:
140
+ case TermKind::CondBranchInst:
141
+ // We could have an address phi. To be conservative, just treat this as
142
+ // a point escape.
143
+ meet (AddressUseKind::PointerEscape);
144
+ for (auto succBlockArgList : ti->getSuccessorBlockArgumentLists ()) {
145
+ auto *succ = succBlockArgList[op->getOperandNumber ()];
146
+ for (auto *use : succ->getUses ())
147
+ addToWorklist (use);
148
+ }
149
+ continue ;
150
+
151
+ case TermKind::UnreachableInst:
152
+ case TermKind::UnwindInst:
153
+ llvm_unreachable (" Should never be used" );
154
+ case TermKind::SwitchEnumInst:
155
+ case TermKind::SwitchValueInst:
156
+ case TermKind::DynamicMethodBranchInst:
157
+ case TermKind::AwaitAsyncContinuationInst:
158
+ case TermKind::CheckedCastBranchInst:
159
+ llvm_unreachable (" Never takes an address" );
160
+ // Point uses.
161
+ case TermKind::ReturnInst:
162
+ case TermKind::ThrowInst:
163
+ case TermKind::YieldInst:
164
+ case TermKind::TryApplyInst:
165
+ case TermKind::SwitchEnumAddrInst:
166
+ case TermKind::CheckedCastAddrBranchInst:
167
+ callVisitUse (op);
168
+ continue ;
169
+ }
170
+ }
171
+
172
+ // TODO: Partial apply should be NonEscaping, but then we need to consider
173
+ // the apply to be a use point.
174
+ if (isa<PartialApplyInst>(user) || isa<AddressToPointerInst>(user)) {
175
+ meet (AddressUseKind::PointerEscape);
176
+ callVisitUse (op);
177
+ continue ;
178
+ }
179
+
180
+ // First, eliminate "end point uses" that we just need to check liveness at
181
+ // and do not need to check transitive uses of.
182
+ if (isa<LoadInst>(user) || isa<CopyAddrInst>(user) ||
183
+ isa<MarkUnresolvedMoveAddrInst>(user) || isIncidentalUse (user) ||
184
+ isa<StoreInst>(user) || isa<DestroyAddrInst>(user) ||
185
+ isa<AssignInst>(user) || isa<LoadUnownedInst>(user) ||
186
+ isa<StoreUnownedInst>(user) || isa<EndApplyInst>(user) ||
187
+ isa<LoadWeakInst>(user) || isa<StoreWeakInst>(user) ||
188
+ isa<AssignByWrapperInst>(user) || isa<AssignOrInitInst>(user) ||
189
+ isa<BeginUnpairedAccessInst>(user) ||
190
+ isa<EndUnpairedAccessInst>(user) || isa<WitnessMethodInst>(user) ||
191
+ isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user) ||
192
+ isa<IsUniqueInst>(user) || isa<ValueMetatypeInst>(user) ||
193
+ isa<DebugValueInst>(user) || isa<EndBorrowInst>(user) ||
194
+ isa<ExplicitCopyAddrInst>(user) || isa<DeallocStackInst>(user) ||
195
+ isa<InitBlockStorageHeaderInst>(user) ||
196
+ isa<GetAsyncContinuationAddrInst>(user) ||
197
+ isa<ExistentialMetatypeInst>(user) ||
198
+ isa<UncheckedRefCastAddrInst>(user) || isa<KeyPathInst>(user) ||
199
+ isa<RetainValueAddrInst>(user) || isa<ReleaseValueAddrInst>(user) ||
200
+ isa<PackElementSetInst>(user) || isa<PackElementGetInst>(user) ||
201
+ isa<DeinitExistentialAddrInst>(user) || isa<LoadBorrowInst>(user)) {
202
+ callVisitUse (op);
203
+ continue ;
204
+ }
205
+
206
+ if (isa<UnconditionalCheckedCastAddrInst>(user) ||
207
+ isa<MarkFunctionEscapeInst>(user)) {
208
+ assert (!user->hasResults ());
209
+ callVisitUse (op);
210
+ continue ;
211
+ }
212
+
213
+ // Then handle users that we need to look at transitive uses of.
214
+ if (Projection::isAddressProjection (user) ||
215
+ isa<ProjectBlockStorageInst>(user) ||
216
+ isa<OpenExistentialAddrInst>(user) ||
217
+ isa<InitExistentialAddrInst>(user) || isa<InitEnumDataAddrInst>(user) ||
218
+ isa<BeginAccessInst>(user) || isa<TailAddrInst>(user) ||
219
+ isa<IndexAddrInst>(user) || isa<StoreBorrowInst>(user) ||
220
+ isa<UncheckedAddrCastInst>(user) || isa<MarkMustCheckInst>(user) ||
221
+ isa<MarkUninitializedInst>(user) || isa<DropDeinitInst>(user) ||
222
+ isa<ProjectBlockStorageInst>(user) || isa<UpcastInst>(user) ||
223
+ isa<TuplePackElementAddrInst>(user) ||
224
+ isa<CopyableToMoveOnlyWrapperAddrInst>(user) ||
225
+ isa<MoveOnlyWrapperToCopyableAddrInst>(user)) {
226
+ transitiveResultUses (op);
227
+ continue ;
228
+ }
229
+
230
+ if (auto *builtin = dyn_cast<BuiltinInst>(user)) {
231
+ if (auto kind = builtin->getBuiltinKind ()) {
232
+ switch (*kind) {
233
+ case BuiltinValueKind::TSanInoutAccess:
234
+ case BuiltinValueKind::ResumeThrowingContinuationReturning:
235
+ case BuiltinValueKind::ResumeNonThrowingContinuationReturning:
236
+ case BuiltinValueKind::Copy:
237
+ case BuiltinValueKind::GenericAdd:
238
+ case BuiltinValueKind::GenericFAdd:
239
+ case BuiltinValueKind::GenericAnd:
240
+ case BuiltinValueKind::GenericAShr:
241
+ case BuiltinValueKind::GenericLShr:
242
+ case BuiltinValueKind::GenericOr:
243
+ case BuiltinValueKind::GenericFDiv:
244
+ case BuiltinValueKind::GenericMul:
245
+ case BuiltinValueKind::GenericFMul:
246
+ case BuiltinValueKind::GenericSDiv:
247
+ case BuiltinValueKind::GenericExactSDiv:
248
+ case BuiltinValueKind::GenericShl:
249
+ case BuiltinValueKind::GenericSRem:
250
+ case BuiltinValueKind::GenericSub:
251
+ case BuiltinValueKind::GenericFSub:
252
+ case BuiltinValueKind::GenericUDiv:
253
+ case BuiltinValueKind::GenericExactUDiv:
254
+ case BuiltinValueKind::GenericURem:
255
+ case BuiltinValueKind::GenericFRem:
256
+ case BuiltinValueKind::GenericXor:
257
+ case BuiltinValueKind::TaskRunInline:
258
+ case BuiltinValueKind::ZeroInitializer:
259
+ callVisitUse (op);
260
+ continue ;
261
+ default :
262
+ break ;
263
+ }
264
+ }
265
+ }
266
+
267
+ if (auto fas = FullApplySite::isa (user)) {
268
+ callVisitUse (op);
269
+ continue ;
270
+ }
271
+
272
+ if (auto *mdi = dyn_cast<MarkDependenceInst>(user)) {
273
+ // If this is the base, just treat it as a liveness use.
274
+ if (op->get () == mdi->getBase ()) {
275
+ callVisitUse (op);
276
+ continue ;
277
+ }
278
+
279
+ // If we are the value use, look through it.
280
+ transitiveResultUses (op);
281
+ continue ;
282
+ }
283
+
284
+ // We were unable to recognize this user, so set AddressUseKind to unknown
285
+ // and call onError with the specific user that caused the problem.
286
+ asImpl ().onError (op);
287
+ return AddressUseKind::Unknown;
288
+ }
289
+
290
+ return result;
291
+ }
81
292
82
293
} // namespace swift
83
294
0 commit comments