16
16
#include " swift/AST/TypeExpansionContext.h"
17
17
#include " swift/Basic/Debug.h"
18
18
#include " swift/Basic/FrozenMultiMap.h"
19
+ #include " swift/Basic/STLExtras.h"
19
20
#include " swift/SIL/PrunedLiveness.h"
21
+ #include " llvm/ADT/STLExtras.h"
20
22
#include " llvm/ADT/SmallBitVector.h"
21
23
#include " llvm/Support/raw_ostream.h"
22
24
@@ -59,6 +61,13 @@ namespace swift {
59
61
// / [0, 1, 1, 0, 0]
60
62
// / ```
61
63
// /
64
+ // / NOTE: Our representation allows for partial initialization/reinitialization
65
+ // / since we do not include a bit for each level of struct/tuple. The effect of
66
+ // / this is that we cannot distinguish a single field type from its child
67
+ // / field. This makes this type not suited for projection operations. This is a
68
+ // / trade-off that was made to make it easy to support partial
69
+ // / initialization/reinitialization of liveness.
70
+ // /
62
71
// / Linearized Representation of Enums
63
72
// / ----------------------------------
64
73
// /
@@ -141,28 +150,36 @@ namespace swift {
141
150
// / we would only use a single bit in our linearized representation, just for
142
151
// / the discriminator value.
143
152
// /
144
- // / Enums and Partial Initialization
145
- // / --------------------------------
153
+ // / Enums and Partial Initialization/Deinitialization
154
+ // / -------------------------------------------------
146
155
// /
147
156
// / One property of our representation of structs and tuples is that a code
148
- // / generator can reinitialize a struct/tuple completely just by re-initializing
149
- // / each of its sub-types individually. This is not possible for enums in our
150
- // / representation since if one just took the leaf nodes for the payload, one
151
- // / would not update the bit for the enum case itself and any additional spare
152
- // / bits. Luckily for us, this is actually impossible to do in SIL since it is
153
- // / impossible to dynamically change the payload of an enum without destroying
154
- // / the original enum and its payload since that would be a verifier caught
155
- // / leak.
156
- struct SubElementNumber {
157
+ // / generator can init/reinit/deinit a struct/tuple completely just by
158
+ // / performing the relevant operation on each of its sub-types
159
+ // / individually. This is not possible for enums in our representation since if
160
+ // / one just took the leaf nodes for the payload, one would not update the bit
161
+ // / for the enum case itself and any additional spare bits. Luckily for us, this
162
+ // / is safe to assume since we only use this in misc address contexts and move
163
+ // / only object contexts in Raw SIL which have the following invariants:
164
+ // /
165
+ // / 1. SIL addresses of enum type cannot dynamically change the payload of an
166
+ // / enum without destroying the original enum completely. So such an address
167
+ // / can never be reinitialized by storing into the payload of an enum.
168
+ // /
169
+ // / 2. It is illegal in SIL to unchecked_enum_data a move only type in Raw
170
+ // / SIL. One must instead use a switch_enum which creates a new value for the
171
+ // / destructured enum. We when writing such verifiers consider the switch to
172
+ // / produce an entire new value rather than a derived forwarding value.
173
+ struct SubElementOffset {
157
174
// / Our internal sub element representation number. We force 32 bits so that
158
175
// / our type tree span is always pointer width. This is convenient for storing
159
176
// / it in other data structures.
160
177
uint32_t number;
161
178
162
- SubElementNumber (unsigned number) : number(number) {}
179
+ SubElementOffset (unsigned number) : number(number) {}
163
180
164
181
// / Given an arbitrary projection \p projectionFromRoot from the \p
165
- // / rootAddress , compute the sub element number for that \p SILValue. The sub
182
+ // / rootValue , compute the sub element number for that \p SILValue. The sub
166
183
// / element number of a type T is always the index of its first leaf node
167
184
// / descendent in the type tree.
168
185
// /
@@ -175,7 +192,7 @@ struct SubElementNumber {
175
192
// /
176
193
// / \returns None if we didn't know how to compute sub-element for this
177
194
// / projection.
178
- static Optional<SubElementNumber > compute (SILValue projectionFromRoot,
195
+ static Optional<SubElementOffset > compute (SILValue projectionFromRoot,
179
196
SILValue root) {
180
197
assert (projectionFromRoot->getType ().getCategory () ==
181
198
root->getType ().getCategory () &&
@@ -187,10 +204,15 @@ struct SubElementNumber {
187
204
188
205
operator unsigned () const { return number; }
189
206
207
+ SubElementOffset &operator +=(unsigned other) {
208
+ number += other;
209
+ return *this ;
210
+ }
211
+
190
212
private:
191
- static Optional<SubElementNumber >
213
+ static Optional<SubElementOffset >
192
214
computeForAddress (SILValue projectionFromRoot, SILValue rootAddress);
193
- static Optional<SubElementNumber > computeForValue (SILValue projectionFromRoot,
215
+ static Optional<SubElementOffset > computeForValue (SILValue projectionFromRoot,
194
216
SILValue rootValue);
195
217
};
196
218
@@ -226,6 +248,11 @@ struct TypeSubElementCount {
226
248
TypeExpansionContext(*value->getFunction ())) {}
227
249
228
250
operator unsigned () const { return number; }
251
+
252
+ TypeSubElementCount operator -=(unsigned other) {
253
+ *this = TypeSubElementCount (unsigned (*this ) - other);
254
+ return *this ;
255
+ }
229
256
};
230
257
231
258
class FieldSensitivePrunedLiveness ;
@@ -234,18 +261,18 @@ class FieldSensitivePrunedLiveness;
234
261
// / of the type tree of a type T.
235
262
struct TypeTreeLeafTypeRange {
236
263
friend FieldSensitivePrunedLiveness;
237
- SubElementNumber startEltOffset;
238
- SubElementNumber endEltOffset;
239
264
240
- public:
265
+ SubElementOffset startEltOffset;
266
+ SubElementOffset endEltOffset;
267
+
241
268
TypeTreeLeafTypeRange () : startEltOffset(0 ), endEltOffset(0 ) {}
242
269
243
- TypeTreeLeafTypeRange (SubElementNumber start, SubElementNumber end)
270
+ TypeTreeLeafTypeRange (SubElementOffset start, SubElementOffset end)
244
271
: startEltOffset(start), endEltOffset(end) {}
245
272
246
273
// / The leaf type range for the entire type tree.
247
- TypeTreeLeafTypeRange (SILValue rootAddress )
248
- : startEltOffset(0 ), endEltOffset(TypeSubElementCount(rootAddress )) {}
274
+ TypeTreeLeafTypeRange (SILValue rootValue )
275
+ : startEltOffset(0 ), endEltOffset(TypeSubElementCount(rootValue )) {}
249
276
250
277
// / The leaf type range for the entire type tree.
251
278
TypeTreeLeafTypeRange (SILType rootType, SILFunction *fn)
@@ -257,14 +284,13 @@ struct TypeTreeLeafTypeRange {
257
284
// /
258
285
// / \returns None if we are unable to understand the path in between \p
259
286
// / projectedAddress and \p rootAddress.
260
- static Optional<TypeTreeLeafTypeRange> get (SILValue projectedAddress,
261
- SILValue rootAddress) {
262
- auto startEltOffset =
263
- SubElementNumber::compute (projectedAddress, rootAddress);
287
+ static Optional<TypeTreeLeafTypeRange> get (SILValue projectedValue,
288
+ SILValue rootValue) {
289
+ auto startEltOffset = SubElementOffset::compute (projectedValue, rootValue);
264
290
if (!startEltOffset)
265
291
return None;
266
292
return {{*startEltOffset,
267
- *startEltOffset + TypeSubElementCount (projectedAddress )}};
293
+ *startEltOffset + TypeSubElementCount (projectedValue )}};
268
294
}
269
295
270
296
// / Given a type \p rootType and a set of needed elements specified by the bit
@@ -311,7 +337,7 @@ struct TypeTreeLeafTypeRange {
311
337
312
338
// / Is the given leaf type specified by \p singleLeafElementNumber apart of
313
339
// / our \p range of leaf type values in the our larger type.
314
- bool contains (SubElementNumber singleLeafElementNumber) const {
340
+ bool contains (SubElementOffset singleLeafElementNumber) const {
315
341
return startEltOffset <= singleLeafElementNumber &&
316
342
singleLeafElementNumber < endEltOffset;
317
343
}
@@ -343,6 +369,12 @@ struct TypeTreeLeafTypeRange {
343
369
void dump () const { print (llvm::dbgs ()); }
344
370
};
345
371
372
+ inline llvm::raw_ostream &operator <<(llvm::raw_ostream &os,
373
+ const TypeTreeLeafTypeRange &value) {
374
+ value.print (os);
375
+ return os;
376
+ }
377
+
346
378
// / This is exactly like pruned liveness except that instead of tracking a
347
379
// / single bit of liveness, it tracks multiple bits of liveness for leaf type
348
380
// / tree nodes of an allocation one is calculating pruned liveness for.
@@ -353,10 +385,12 @@ struct TypeTreeLeafTypeRange {
353
385
class FieldSensitivePrunedLiveness {
354
386
PrunedLiveBlocks liveBlocks;
355
387
388
+ public:
356
389
struct InterestingUser {
357
390
TypeTreeLeafTypeRange subEltSpan;
358
391
bool isConsuming;
359
392
393
+ InterestingUser () : subEltSpan(), isConsuming(false ) {}
360
394
InterestingUser (TypeTreeLeafTypeRange subEltSpan, bool isConsuming)
361
395
: subEltSpan(subEltSpan), isConsuming(isConsuming) {}
362
396
@@ -366,6 +400,7 @@ class FieldSensitivePrunedLiveness {
366
400
}
367
401
};
368
402
403
+ private:
369
404
// / Map all "interesting" user instructions in this def's live range to a pair
370
405
// / consisting of the SILValue that it uses and a flag indicating whether they
371
406
// / must end the lifetime.
@@ -420,6 +455,40 @@ class FieldSensitivePrunedLiveness {
420
455
return llvm::make_range (users.begin (), users.end ());
421
456
}
422
457
458
+ using LifetimeEndingUserRange = OptionalTransformRange<
459
+ UserRange,
460
+ function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
461
+ const std::pair<SILInstruction *, InterestingUser> &)>>;
462
+ LifetimeEndingUserRange getAllLifetimeEndingUses () const {
463
+ function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
464
+ const std::pair<SILInstruction *, InterestingUser> &)>
465
+ op;
466
+ op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
467
+ -> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
468
+ if (pair.second .isConsuming )
469
+ return {{pair.first , pair.second .subEltSpan }};
470
+ return None;
471
+ };
472
+ return LifetimeEndingUserRange (getAllUsers (), op);
473
+ }
474
+
475
+ using NonLifetimeEndingUserRange = OptionalTransformRange<
476
+ UserRange,
477
+ function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
478
+ const std::pair<SILInstruction *, InterestingUser> &)>>;
479
+ NonLifetimeEndingUserRange getAllNonLifetimeEndingUses () const {
480
+ function_ref<Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>>(
481
+ const std::pair<SILInstruction *, InterestingUser> &)>
482
+ op;
483
+ op = [](const std::pair<SILInstruction *, InterestingUser> &pair)
484
+ -> Optional<std::pair<SILInstruction *, TypeTreeLeafTypeRange>> {
485
+ if (!pair.second .isConsuming )
486
+ return {{pair.first , pair.second .subEltSpan }};
487
+ return None;
488
+ };
489
+ return NonLifetimeEndingUserRange (getAllUsers (), op);
490
+ }
491
+
423
492
using UserBlockRange = TransformRange<
424
493
UserRange, function_ref<SILBasicBlock *(
425
494
const std::pair<SILInstruction *, InterestingUser> &)>>;
0 commit comments