13
13
#ifndef SWIFT_SIL_FIELDSENSITIVEPRUNTEDLIVENESS_H
14
14
#define SWIFT_SIL_FIELDSENSITIVEPRUNTEDLIVENESS_H
15
15
16
+ #include " swift/AST/TypeExpansionContext.h"
16
17
#include " swift/SIL/PrunedLiveness.h"
17
18
18
19
namespace swift {
@@ -149,7 +150,10 @@ namespace swift {
149
150
// / the original enum and its payload since that would be a verifier caught
150
151
// / leak.
151
152
struct SubElementNumber {
152
- unsigned number;
153
+ // / Our internal sub element representation number. We force 32 bits so that
154
+ // / our type tree span is always pointer width. This is convenient for storing
155
+ // / it in other data structures.
156
+ uint32_t number;
153
157
154
158
SubElementNumber (unsigned number) : number(number) {}
155
159
@@ -168,9 +172,22 @@ struct SubElementNumber {
168
172
// / \returns None if we didn't know how to compute sub-element for this
169
173
// / projection.
170
174
static Optional<SubElementNumber> compute (SILValue projectionFromRoot,
171
- SILValue root);
175
+ SILValue root) {
176
+ assert (projectionFromRoot->getType ().getCategory () ==
177
+ root->getType ().getCategory () &&
178
+ " projectionFromRoot and root must both be objects or address." );
179
+ if (root->getType ().isObject ())
180
+ return computeForValue (projectionFromRoot, root);
181
+ return computeForAddress (projectionFromRoot, root);
182
+ }
172
183
173
184
operator unsigned () const { return number; }
185
+
186
+ private:
187
+ static Optional<SubElementNumber>
188
+ computeForAddress (SILValue projectionFromRoot, SILValue rootAddress);
189
+ static Optional<SubElementNumber> computeForValue (SILValue projectionFromRoot,
190
+ SILValue rootValue);
174
191
};
175
192
176
193
// / Given a type T, this is the number of leaf field types in T's type tree. A
@@ -196,16 +213,24 @@ struct TypeSubElementCount {
196
213
TypeSubElementCount (SILType type, SILModule &mod,
197
214
TypeExpansionContext context);
198
215
216
+ // / Helper method that invokes the SILModule &mod entry point.
217
+ TypeSubElementCount (SILType type, SILFunction *fn)
218
+ : TypeSubElementCount(type, fn->getModule (),
219
+ TypeExpansionContext(*fn)) {}
220
+
199
221
TypeSubElementCount (SILValue value)
200
222
: TypeSubElementCount(value->getType (), *value->getModule(),
201
223
TypeExpansionContext(*value->getFunction ())) {}
202
224
203
225
operator unsigned () const { return number; }
204
226
};
205
227
228
+ class FieldSensitivePrunedLiveness ;
229
+
206
230
// / A span of leaf elements in the sub-element break down of the linearization
207
231
// / of the type tree of a type T.
208
232
struct TypeTreeLeafTypeRange {
233
+ friend FieldSensitivePrunedLiveness;
209
234
SubElementNumber startEltOffset;
210
235
SubElementNumber endEltOffset;
211
236
@@ -218,6 +243,10 @@ struct TypeTreeLeafTypeRange {
218
243
TypeTreeLeafTypeRange (SILValue rootAddress)
219
244
: startEltOffset(0 ), endEltOffset(TypeSubElementCount(rootAddress)) {}
220
245
246
+ // / The leaf type range for the entire type tree.
247
+ TypeTreeLeafTypeRange (SILType rootType, SILFunction *fn)
248
+ : startEltOffset(0 ), endEltOffset(TypeSubElementCount(rootType, fn)) {}
249
+
221
250
// / The leaf type sub-range of the type tree of \p rootAddress, consisting of
222
251
// / \p projectedAddress and all of \p projectedAddress's descendent fields in
223
252
// / the type tree.
@@ -234,6 +263,32 @@ struct TypeTreeLeafTypeRange {
234
263
*startEltOffset + TypeSubElementCount (projectedAddress)}};
235
264
}
236
265
266
+ // / Given a type \p rootType and a set of needed elements specified by the bit
267
+ // / vector \p neededElements, place into \p foundContiguousTypeRanges a set of
268
+ // / TypeTreeLeafTypeRanges that are associated with the bit vectors
269
+ // / elements. As a constraint, we ensure that if \p neededElements has bits
270
+ // / set that are part of subsequent fields of a type that is only partially
271
+ // / needed, the two fields are represented as separate ranges. This ensures
272
+ // / that it is easy to use this API to correspond to independent operations
273
+ // / for the fields.
274
+ static void convertNeededElementsToContiguousTypeRanges (
275
+ SILFunction *fn,
276
+ SILType rootType, SmallBitVector &neededElements,
277
+ SmallVectorImpl<TypeTreeLeafTypeRange> &foundContiguousTypeRanges);
278
+
279
+ static void constructProjectionsForNeededElements (
280
+ SILValue rootValue, SILInstruction *insertPt, SmallBitVector &neededElements,
281
+ SmallVectorImpl<SILValue> &resultingProjections);
282
+
283
+ bool operator ==(const TypeTreeLeafTypeRange &other) const {
284
+ return startEltOffset == other.startEltOffset &&
285
+ endEltOffset == other.endEltOffset ;
286
+ }
287
+
288
+ bool operator !=(const TypeTreeLeafTypeRange &other) const {
289
+ return !(*this == other);
290
+ }
291
+
237
292
// / Is the given leaf type specified by \p singleLeafElementNumber apart of
238
293
// / our \p range of leaf type values in the our larger type.
239
294
bool contains (SubElementNumber singleLeafElementNumber) const {
@@ -256,6 +311,21 @@ struct TypeTreeLeafTypeRange {
256
311
// Othrwise, see if endEltOffset - 1 is within the range.
257
312
return startEltOffset <= rangeLastElt && rangeLastElt < endEltOffset;
258
313
}
314
+
315
+ IntRange<unsigned > getRange () const {
316
+ return range (startEltOffset, endEltOffset);
317
+ }
318
+
319
+ bool empty () const { return startEltOffset == endEltOffset; }
320
+
321
+ unsigned size () const { return endEltOffset - startEltOffset; }
322
+
323
+ void getPerFieldTypeRange (SILType type, SILFunction *fn, llvm::function_ref<void (SILType, TypeTreeLeafTypeRange)> callback);
324
+
325
+ // / Construct per field projections if the projection range has any bits in
326
+ // / common with filterBitVector.
327
+ void constructFilteredProjections (SILValue value, SILInstruction *insertPt, SmallBitVector &filterBitVector,
328
+ llvm::function_ref<void (SILValue, TypeTreeLeafTypeRange)> callback);
259
329
};
260
330
261
331
// / This is exactly like pruned liveness except that instead of tracking a
@@ -265,7 +335,7 @@ struct TypeTreeLeafTypeRange {
265
335
// / DISCUSSION: One can view a type T as a tree with recursively each field F of
266
336
// / the type T being a child of T in the tree. We say recursively since the tree
267
337
// / unfolds for F and its children as well.
268
- class FieldSensitiveAddressPrunedLiveness {
338
+ class FieldSensitivePrunedLiveness {
269
339
PrunedLiveBlocks liveBlocks;
270
340
271
341
struct InterestingUser {
@@ -295,14 +365,14 @@ class FieldSensitiveAddressPrunedLiveness {
295
365
llvm::SmallMapVector<SILInstruction *, InterestingUser, 8 > users;
296
366
297
367
// / The root address of our type tree.
298
- SILValue rootAddress ;
368
+ SILValue rootValue ;
299
369
300
370
public:
301
- FieldSensitiveAddressPrunedLiveness (
371
+ FieldSensitivePrunedLiveness (
302
372
SILFunction *fn, SILValue rootValue,
303
373
SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
304
374
: liveBlocks(TypeSubElementCount(rootValue), discoveredBlocks),
305
- rootAddress (rootValue) {}
375
+ rootValue (rootValue) {}
306
376
307
377
bool empty () const {
308
378
assert (!liveBlocks.empty () || users.empty ());
@@ -314,10 +384,15 @@ class FieldSensitiveAddressPrunedLiveness {
314
384
users.clear ();
315
385
}
316
386
317
- SILValue getRootAddress () const { return rootAddress; }
387
+ SILValue getRootValue () const { return rootValue; }
388
+ SILType getRootType () const { return rootValue->getType (); }
318
389
319
390
unsigned numLiveBlocks () const { return liveBlocks.numLiveBlocks (); }
320
391
392
+ TypeTreeLeafTypeRange getTopLevelSpan () const {
393
+ return TypeTreeLeafTypeRange (0 , getNumSubElements ());
394
+ }
395
+
321
396
// / If the constructor was provided with a vector to populate, then this
322
397
// / returns the list of all live blocks with no duplicates.
323
398
ArrayRef<SILBasicBlock *> getDiscoveredBlocks () const {
@@ -396,49 +471,142 @@ class FieldSensitiveAddressPrunedLiveness {
396
471
}
397
472
398
473
unsigned getNumSubElements () const { return liveBlocks.getNumBitsToTrack (); }
399
-
400
- // / Return true if \p inst occurs before the liveness boundary. Used when the
401
- // / client already knows that inst occurs after the start of liveness.
402
- void isWithinBoundary (SILInstruction *inst, SmallBitVector &outVector) const ;
403
474
};
404
475
405
- // / Record the last use points and CFG edges that form the boundary of
406
- // / FieldSensitiveAddressPrunedLiveness. It does this on a per type tree leaf
407
- // / node basis.
408
- struct FieldSensitiveAddressPrunedLivenessBoundary {
409
- // / The list of last users and an associated SILValue that is the address that
410
- // / is being used. The address can be used to determine the start sub element
411
- // / number of the user in the type tree and the end sub element number.
476
+ template <typename LivenessWithDefs>
477
+ class FieldSensitivePrunedLiveRange : public FieldSensitivePrunedLiveness {
478
+ const LivenessWithDefs &asImpl () const {
479
+ return reinterpret_cast <const LivenessWithDefs &>(*this );
480
+ }
481
+
482
+ public:
483
+ FieldSensitivePrunedLiveRange (
484
+ SILFunction *fn, SILValue rootValue,
485
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
486
+ : FieldSensitivePrunedLiveness(fn, rootValue, discoveredBlocks) {}
487
+
488
+ // / Check if \p inst occurs in between the definition of a def and the
489
+ // / liveness boundary for bits in \p span.
412
490
// /
413
- // / TODO (MG): If we don't eventually need to store the SILValue here (I am
414
- // / not sure yet...), just store a tuple with the start/end sub element
415
- // / number.
416
- SmallVector<std::tuple<SILInstruction *, TypeTreeLeafTypeRange>, 8 > lastUsers;
491
+ // / NOTE: It is assumed that \p inst is correctly described by span.
492
+ bool isWithinBoundary (SILInstruction *inst, TypeTreeLeafTypeRange span) const __attribute__((optnone));
493
+ };
494
+
495
+ // / Single defined liveness.
496
+ // /
497
+ // An SSA def results in pruned liveness with a contiguous liverange.
498
+ // /
499
+ // / An unreachable self-loop might result in a "gap" between the last use above
500
+ // / the def in the same block.
501
+ // /
502
+ // / For SSA live ranges, a single "def" block dominates all uses. If no def
503
+ // / block is provided, liveness is computed as if defined by a function
504
+ // / argument. If the client does not provide a single, dominating def block,
505
+ // / then the client must at least ensure that no uses precede the first
506
+ // / definition in a def block. Since this analysis does not remember the
507
+ // / positions of defs, it assumes that, within a block, uses follow
508
+ // / defs. Breaking this assumption will result in a "hole" in the live range in
509
+ // / which the def block's predecessors incorrectly remain dead. This situation
510
+ // / could be handled by adding an updateForUseBeforeFirstDef() API.
511
+ class FieldSensitiveSSAPrunedLiveRange
512
+ : public FieldSensitivePrunedLiveRange<FieldSensitiveSSAPrunedLiveRange> {
513
+ std::pair<SILValue, Optional<TypeTreeLeafTypeRange>> def = {{}, {}};
514
+
515
+ // / None for arguments.
516
+ std::pair<SILInstruction *, Optional<TypeTreeLeafTypeRange>> defInst = {
517
+ nullptr , None};
518
+
519
+ public:
520
+ FieldSensitiveSSAPrunedLiveRange (
521
+ SILFunction *fn, SILValue rootValue,
522
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
523
+ : FieldSensitivePrunedLiveRange(fn, rootValue, discoveredBlocks) {}
417
524
418
- // / Blocks where the value was live out but had a successor that was dead.
419
- SmallVector<SILBasicBlock *, 8 > boundaryEdges;
525
+ std::pair<SILValue, Optional<TypeTreeLeafTypeRange>> getDef () const {
526
+ return def;
527
+ }
420
528
421
529
void clear () {
422
- lastUsers.clear ();
423
- boundaryEdges.clear ();
530
+ def = {{}, {}};
531
+ defInst = {{}, {}};
532
+ FieldSensitivePrunedLiveRange::clear ();
424
533
}
425
534
426
- // / Compute the boundary from the blocks discovered during liveness analysis.
427
- // /
428
- // / Precondition: \p liveness.getDiscoveredBlocks() is a valid list of all
429
- // / live blocks with no duplicates.
430
- // /
431
- // / The computed boundary will completely post-dominate, including dead end
432
- // / paths. The client should query DeadEndBlocks to ignore those dead end
433
- // / paths.
434
- void compute (const FieldSensitiveAddressPrunedLiveness &liveness);
535
+ void initializeDef (SILValue def, TypeTreeLeafTypeRange span) {
536
+ assert (!this ->def .first && !this ->def .second && " reinitialization" );
435
537
436
- private:
437
- void
438
- findLastUserInBlock (SILBasicBlock *bb,
439
- FieldSensitiveAddressPrunedLivenessBoundary &boundary,
440
- const FieldSensitiveAddressPrunedLiveness &liveness,
441
- unsigned subElementNumber);
538
+ this ->def = {def, span};
539
+ defInst = {def->getDefiningInstruction (), span};
540
+ initializeDefBlock (def->getParentBlock (), span);
541
+ }
542
+
543
+ bool isInitialized () const { return bool (def.first ) && bool (def.second ); }
544
+
545
+ bool isDef (SILInstruction *inst, unsigned bit) const {
546
+ return inst == defInst.first && defInst.second ->contains (bit);
547
+ }
548
+
549
+ bool isDefBlock (SILBasicBlock *block, unsigned bit) const {
550
+ return def.first ->getParentBlock () == block && def.second ->contains (bit);
551
+ }
552
+ };
553
+
554
+ // / MultiDefPrunedLiveness is computed incrementally by calling updateForUse.
555
+ // /
556
+ // / Defs should be initialized before calling updatingForUse on any def
557
+ // / that reaches the use.
558
+ class FieldSensitiveMultiDefPrunedLiveRange
559
+ : public FieldSensitivePrunedLiveRange<
560
+ FieldSensitiveMultiDefPrunedLiveRange> {
561
+ // TODO: See if we can make this more efficient.
562
+ llvm::SmallMapVector<SILNode *, TypeTreeLeafTypeRange, 8 > defs;
563
+ llvm::SmallMapVector<SILBasicBlock *, TypeTreeLeafTypeRange, 8 > defBlocks;
564
+
565
+ public:
566
+ FieldSensitiveMultiDefPrunedLiveRange (
567
+ SILFunction *fn, SILValue rootValue,
568
+ SmallVectorImpl<SILBasicBlock *> *discoveredBlocks = nullptr )
569
+ : FieldSensitivePrunedLiveRange(fn, rootValue, discoveredBlocks) {}
570
+
571
+ void clear () { llvm_unreachable (" multi-def liveness cannot be reused" ); }
572
+
573
+ void initializeDef (SILValue def, TypeTreeLeafTypeRange span) {
574
+ defs.insert ({def, span});
575
+ auto *block = def->getParentBlock ();
576
+ defBlocks.insert ({block, span});
577
+ initializeDefBlock (block, span);
578
+ }
579
+
580
+ void initializeDef (SILInstruction *def, TypeTreeLeafTypeRange span) {
581
+ defs.insert ({cast<SILNode>(def), span});
582
+ auto *block = def->getParent ();
583
+ defBlocks.insert ({block, span});
584
+ initializeDefBlock (block, span);
585
+ }
586
+
587
+ bool isInitialized () const { return !defs.empty (); }
588
+
589
+ // / Return true if this block is a def block for this specific bit.
590
+ bool isDefBlock (SILBasicBlock *block, unsigned bit) const {
591
+ auto iter = defBlocks.find (block);
592
+ if (iter == defBlocks.end ())
593
+ return false ;
594
+ return iter->second .contains (bit);
595
+ }
596
+
597
+ bool isDef (SILInstruction *inst, unsigned bit) const {
598
+ auto iter = defs.find (cast<SILNode>(inst));
599
+ if (iter == defs.end ())
600
+ return false ;
601
+ return iter->second .contains (bit);
602
+ }
603
+
604
+ bool isDef (SILValue value, unsigned bit) const {
605
+ auto iter = defs.find (cast<SILNode>(value));
606
+ if (iter == defs.end ())
607
+ return false ;
608
+ return iter->second .contains (bit);
609
+ }
442
610
};
443
611
444
612
} // namespace swift
0 commit comments