@@ -353,6 +353,61 @@ struct LiveRangeSummary {
353
353
// / necessarily include liveness up to destroy_value or end_borrow
354
354
// / instructions.
355
355
class PrunedLiveness {
356
+ public:
357
+ // / A tristate describing how an instruction uses the value:
358
+ // / - non-ending: the value's lifetime does not end at the instruction;
359
+ // / results from updateForUse(, lifetimeEnding: false)
360
+ // / - ending: the value's lifetime ends at the instruction; results from
361
+ // / updateForUse(, lifetimeEnding: true)
362
+ // / - non-use: the instruction doesn't use the value but liveness was extended
363
+ // / to it; results from extendToNonUse
364
+ // /
365
+ // / If an instruction is added to liveness with multiple LifetimeEnding
366
+ // / instances, the stored instance needs to be updated appropriately, taking
367
+ // / into account the instances that were already seen.
368
+ // /
369
+ // / For example, if Nonuse is seen after Ending, it is ignored: that the
370
+ // / instruction ends the lifetime takes priority: the instruction doesn't end
371
+ // / the lifetime of the value any less because liveness was extended to it.
372
+ // /
373
+ // / Similarly, if Ending is seen after NonEnding, it is ignored: that the
374
+ // / instruction ends the lifetime of a copy of the value can't change the fact
375
+ // / that liveness already extends _beyond_ the instruction because it was
376
+ // / already recognized as a non-ending use.
377
+ // /
378
+ // / This relationship of "overriding" is captured by the order of the cases in
379
+ // / LifetimeEnding::Value and which case overrides another is computed by
380
+ // / taking the meet--i.e. the lesser of the two cases overrides.
381
+ // /
382
+ // / Note: Taking the meet may not be appropriate for branch instructions
383
+ // / which may need to be recognized as lifetime-ending when they have
384
+ // / as uses both a reborrow and a guaranteed phi.
385
+ struct LifetimeEnding {
386
+ enum class Value {
387
+ // The instruction doesn't consume the value.
388
+ NonEnding,
389
+ // The instruction consumes the value.
390
+ Ending,
391
+ // The instruction doesn't use the value.
392
+ NonUse,
393
+ };
394
+ Value value;
395
+
396
+ LifetimeEnding (Value value) : value(value) {}
397
+ explicit LifetimeEnding (bool lifetimeEnding)
398
+ : value(lifetimeEnding ? Value::Ending : Value::NonEnding) {}
399
+ operator Value () const { return value; }
400
+ LifetimeEnding meet (LifetimeEnding const other) const {
401
+ return value < other.value ? *this : other;
402
+ }
403
+ void meetInPlace (LifetimeEnding const other) { *this = meet (other); }
404
+ bool isEnding () const { return value == Value::Ending; }
405
+
406
+ static LifetimeEnding NonUse () { return {Value::NonUse}; };
407
+ static LifetimeEnding Ending () { return {Value::Ending}; };
408
+ static LifetimeEnding NonEnding () { return {Value::NonEnding}; };
409
+ };
410
+
356
411
protected:
357
412
PrunedLiveBlocks liveBlocks;
358
413
@@ -365,7 +420,7 @@ class PrunedLiveness {
365
420
// they may be the last use in the block.
366
421
//
367
422
// Non-lifetime-ending within a LiveOut block are uninteresting.
368
- llvm::SmallMapVector<SILInstruction *, bool , 8 > users;
423
+ llvm::SmallMapVector<SILInstruction *, LifetimeEnding , 8 > users;
369
424
370
425
public:
371
426
PrunedLiveness (SILFunction *function,
@@ -411,11 +466,12 @@ class PrunedLiveness {
411
466
auto useIter = users.find (user);
412
467
if (useIter == users.end ())
413
468
return NonUser;
414
- return useIter->second ? LifetimeEndingUse : NonLifetimeEndingUse;
469
+ return useIter->second == LifetimeEnding::Ending () ? LifetimeEndingUse
470
+ : NonLifetimeEndingUse;
415
471
}
416
472
417
473
using ConstUserRange =
418
- iterator_range<const std::pair<SILInstruction *, bool > *>;
474
+ iterator_range<const std::pair<SILInstruction *, LifetimeEnding > *>;
419
475
ConstUserRange getAllUsers () const {
420
476
return llvm::make_range (users.begin (), users.end ());
421
477
}
@@ -425,49 +481,53 @@ class PrunedLiveness {
425
481
// / IDE.
426
482
struct RangeIterationHelpers {
427
483
struct MapFunctor {
428
- SILInstruction *
429
- operator ()( const std::pair<SILInstruction *, bool > &pair) const {
484
+ SILInstruction *operator ()(
485
+ const std::pair<SILInstruction *, LifetimeEnding > &pair) const {
430
486
// Strip off the const to ease use with other APIs.
431
487
return const_cast <SILInstruction *>(pair.first );
432
488
}
433
489
};
434
490
435
- struct LifetimeEnding {
491
+ struct IsLifetimeEnding {
436
492
struct FilterFunctor {
437
- bool operator ()(const std::pair<SILInstruction *, bool > &pair) const {
438
- return pair.second ;
493
+ bool operator ()(
494
+ const std::pair<SILInstruction *, LifetimeEnding> &pair) const {
495
+ return pair.second .isEnding ();
439
496
}
440
497
};
441
498
442
499
using MapFilterIter = llvm::mapped_iterator<
443
- llvm::filter_iterator<const std::pair<SILInstruction *, bool > *,
444
- FilterFunctor>,
500
+ llvm::filter_iterator<
501
+ const std::pair<SILInstruction *, LifetimeEnding> *,
502
+ FilterFunctor>,
445
503
MapFunctor>;
446
504
};
447
505
448
506
struct NonLifetimeEnding {
449
507
struct FilterFunctor {
450
- bool operator ()(const std::pair<SILInstruction *, bool > &pair) const {
451
- return !pair.second ;
508
+ bool operator ()(
509
+ const std::pair<SILInstruction *, LifetimeEnding> &pair) const {
510
+ return !pair.second .isEnding ();
452
511
}
453
512
};
454
513
455
514
using MapFilterIter = llvm::mapped_iterator<
456
- llvm::filter_iterator<const std::pair<SILInstruction *, bool > *,
457
- FilterFunctor>,
515
+ llvm::filter_iterator<
516
+ const std::pair<SILInstruction *, LifetimeEnding> *,
517
+ FilterFunctor>,
458
518
MapFunctor>;
459
519
};
460
520
};
461
521
using LifetimeEndingUserRange = llvm::iterator_range<
462
- RangeIterationHelpers::LifetimeEnding ::MapFilterIter>;
522
+ RangeIterationHelpers::IsLifetimeEnding ::MapFilterIter>;
463
523
464
524
// / Return a range consisting of the current set of consuming users fed into
465
525
// / this PrunedLiveness instance.
466
526
LifetimeEndingUserRange getLifetimeEndingUsers () const {
467
527
return map_range (
468
528
llvm::make_filter_range (
469
529
getAllUsers (),
470
- RangeIterationHelpers::LifetimeEnding ::FilterFunctor ()),
530
+ RangeIterationHelpers::IsLifetimeEnding ::FilterFunctor ()),
471
531
RangeIterationHelpers::MapFunctor ());
472
532
}
473
533
@@ -552,6 +612,8 @@ class PrunedLiveRange : public PrunedLiveness {
552
612
ValueSet &visited,
553
613
SILValue value);
554
614
615
+ void updateForUse (SILInstruction *user, LifetimeEnding lifetimeEnding);
616
+
555
617
public:
556
618
// / For flexibility, \p lifetimeEnding is provided by the
557
619
// / caller. PrunedLiveness makes no assumptions about the def-use
@@ -560,6 +622,12 @@ class PrunedLiveRange : public PrunedLiveness {
560
622
// / live range vs. a nested borrow scope within the extended live range.
561
623
void updateForUse (SILInstruction *user, bool lifetimeEnding);
562
624
625
+ // / Adds \p inst which doesn't use the def to liveness.
626
+ // /
627
+ // / Different from calling updateForUse because it never overrides the value
628
+ // / \p lifetimeEnding stored for \p inst.
629
+ void extendToNonUse (SILInstruction *inst);
630
+
563
631
// / Updates the liveness for a whole borrow scope, beginning at \p op.
564
632
// / Returns false if this cannot be done. This assumes that nested OSSA
565
633
// / lifetimes are complete.
0 commit comments