@@ -414,7 +414,7 @@ void CanonicalizeOSSALifetime::extendLivenessThroughOverlappingAccess() {
414
414
// liveness computed in Step 1.
415
415
// ===----------------------------------------------------------------------===//
416
416
417
- namespace swift {
417
+ namespace {
418
418
// / Extends the boundary from PrunedLiveness down to preexisting destroys of the
419
419
// / def which aren't separated from the original boundary by "interesting"
420
420
// / instructions.
@@ -423,39 +423,38 @@ namespace swift {
423
423
// / iterating to a fixed point by canonicalizing the lifetimes of several
424
424
// / values with overlapping live ranges and failing to find a fixed point
425
425
// / because their destroys are repeatedly hoisted over one another.
426
- class CanonicalizeOSSALifetimeBoundaryExtender {
426
+ class ExtendBoundaryToDestroys final {
427
427
SSAPrunedLiveness &liveness;
428
- PrunedLivenessBoundary &originalBoundary;
428
+ PrunedLivenessBoundary const &originalBoundary;
429
429
SILValue currentDef;
430
+ BasicBlockSet seenMergePoints;
430
431
431
432
public:
432
- CanonicalizeOSSALifetimeBoundaryExtender (
433
- SSAPrunedLiveness &liveness, PrunedLivenessBoundary &originalBoundary,
434
- SILValue currentDef)
433
+ ExtendBoundaryToDestroys (SSAPrunedLiveness &liveness,
434
+ PrunedLivenessBoundary const &originalBoundary,
435
+ SILValue currentDef)
435
436
: liveness(liveness), originalBoundary(originalBoundary),
436
- currentDef (currentDef){};
437
+ currentDef (currentDef), seenMergePoints(currentDef->getFunction ()){};
438
+ ExtendBoundaryToDestroys (ExtendBoundaryToDestroys const &) = delete;
439
+ ExtendBoundaryToDestroys &
440
+ operator =(ExtendBoundaryToDestroys const &) = delete;
437
441
438
442
// / Compute the extended boundary by walking out from the original boundary
439
443
// / (from PrunedLiveness::computeBoundary) down to any destroys that appear
440
444
// / later but which aren't separated from the original boundary by
441
445
// / "interesting" users.
442
446
void extend (PrunedLivenessBoundary &boundary) {
443
447
for (auto *def : originalBoundary.deadDefs ) {
444
- if (auto *argument = dyn_cast<SILArgument>(def)) {
445
- extendBoundaryFromCFGEdge (argument->getParent (), boundary);
446
- } else {
447
- extendBoundaryFromInstruction (cast<SILInstruction>(def), boundary);
448
- }
448
+ extendBoundaryFromDef (def, boundary);
449
449
}
450
450
for (auto *destination : originalBoundary.boundaryEdges ) {
451
- extendBoundaryFromCFGEdge (destination, boundary);
451
+ extendBoundaryFromBoundaryEdge (destination, boundary);
452
452
}
453
453
for (auto *user : originalBoundary.lastUsers ) {
454
- extendBoundaryFromInstruction (user, boundary);
454
+ extendBoundaryFromUser (user, boundary);
455
455
}
456
456
}
457
457
458
- private:
459
458
// / Look past ignoreable instructions to find the _last_ destroy after the
460
459
// / specified instruction that destroys \p def.
461
460
static DestroyValueInst *findDestroyAfter (SILInstruction *previous,
@@ -481,21 +480,48 @@ class CanonicalizeOSSALifetimeBoundaryExtender {
481
480
return findDestroyAfter (start, def);
482
481
}
483
482
484
- // / Look past ignoreable instructions to find the _last_ destroy "on" the edge
485
- // / that ends at \p destination (i.e. looking from the beginning of \p
486
- // / destination) that destroys \p def .
487
- static DestroyValueInst *findDestroyOnCFGEdge (SILBasicBlock *destination,
488
- SILValue def) {
483
+ // / Look past ignoreable instructions to find the _first_ destroy in \p
484
+ // / destination that destroys \p def and isn't separated from the beginning
485
+ // / by "interesting" instructions .
486
+ static DestroyValueInst *findDestroyFromBlockBegin (SILBasicBlock *destination,
487
+ SILValue def) {
489
488
return findDestroyAtOrAfter (&*destination->begin (), def);
490
489
}
491
490
491
+ private:
492
+ // / Compute the points on the extended boundary found by walking forward from
493
+ // / the dead def (starting either with the top of the block in the case of a
494
+ // / dead arg or the next instruction in the case of an instruction) down to
495
+ // / any destroys that appear later but which aren't separated from the
496
+ // / original boundary by "interesting" users.
497
+ // /
498
+ // / If a destroy is found, it becomes a last user. Otherwise, the boundary
499
+ // / stays in place and \p def remains a dead def.
500
+ void extendBoundaryFromDef (SILNode *def, PrunedLivenessBoundary &boundary) {
501
+ if (auto *arg = dyn_cast<SILArgument>(def)) {
502
+ if (auto *dvi = findDestroyFromBlockBegin (arg->getParent (), currentDef)) {
503
+ boundary.lastUsers .push_back (dvi);
504
+ return ;
505
+ }
506
+ } else {
507
+ if (auto *dvi = findDestroyAfter (cast<SILInstruction>(def), currentDef)) {
508
+ boundary.lastUsers .push_back (dvi);
509
+ return ;
510
+ }
511
+ }
512
+ boundary.deadDefs .push_back (def);
513
+ }
514
+
492
515
// / Compute the points on the extended boundary found by walking down from the
493
516
// / boundary edge in the original boundary (uniquely determined by the
494
517
// / specified destination edge) down to any destroys that appear later but
495
518
// / which aren't separated from the original boundary by "interesting" users.
496
- void extendBoundaryFromCFGEdge (SILBasicBlock *destination,
497
- PrunedLivenessBoundary &boundary) {
498
- if (auto *dvi = findDestroyOnCFGEdge (destination, currentDef)) {
519
+ // /
520
+ // / If a destroy is found, it becomes a last user. Otherwise, the boundary
521
+ // / stays in place and \p destination remains a boundary edge.
522
+ void extendBoundaryFromBoundaryEdge (SILBasicBlock *destination,
523
+ PrunedLivenessBoundary &boundary) {
524
+ if (auto *dvi = findDestroyFromBlockBegin (destination, currentDef)) {
499
525
boundary.lastUsers .push_back (dvi);
500
526
} else {
501
527
boundary.boundaryEdges .push_back (destination);
@@ -506,8 +532,16 @@ class CanonicalizeOSSALifetimeBoundaryExtender {
506
532
// / specified instruction in the original boundary down to any destroys that
507
533
// / appear later but which aren't separated from the original boundary by
508
534
// / "interesting" users.
509
- void extendBoundaryFromInstruction (SILInstruction *user,
510
- PrunedLivenessBoundary &boundary) {
535
+ // /
536
+ // / If the user is consuming, the boundary remains in place.
537
+ // /
538
+ // / If the user is a terminator, see extendBoundaryFromTerminator.
539
+ // /
540
+ // / If a destroy is found after the (non-consuming, non-terminator) \p user,
541
+ // / it becomes a last user. Otherwise, the boundary stays in place and \p
542
+ // / user remains a last user.
543
+ void extendBoundaryFromUser (SILInstruction *user,
544
+ PrunedLivenessBoundary &boundary) {
511
545
if (auto *dvi = dynCastToDestroyOf (user, currentDef)) {
512
546
auto *existingDestroy = findDestroyAtOrAfter (dvi, currentDef);
513
547
assert (existingDestroy && " couldn't find a destroy at or after one!?" );
@@ -523,11 +557,8 @@ class CanonicalizeOSSALifetimeBoundaryExtender {
523
557
return ;
524
558
case PrunedLiveness::IsInterestingUser::NonLifetimeEndingUse:
525
559
case PrunedLiveness::IsInterestingUser::NonUser:
526
- if (isa<TermInst>(user)) {
527
- auto *block = user->getParent ();
528
- for (auto *successor : block->getSuccessorBlocks ()) {
529
- extendBoundaryFromCFGEdge (successor, boundary);
530
- }
560
+ if (auto *terminator = dyn_cast<TermInst>(user)) {
561
+ extendBoundaryFromTerminator (terminator, boundary);
531
562
return ;
532
563
}
533
564
if (auto *existingDestroy = findDestroyAfter (user, currentDef)) {
@@ -537,18 +568,59 @@ class CanonicalizeOSSALifetimeBoundaryExtender {
537
568
boundary.lastUsers .push_back (user);
538
569
}
539
570
}
571
+
572
+ // / Compute the points on the extended boundary by walking into \p user's
573
+ // / parent's successors and looking for destroys.
574
+ // /
575
+ // / If any destroys are found, they become last users and all other successors
576
+ // / (which lack destroys) become boundary edges. If no destroys are found,
577
+ // / the boundary stays in place and \p user remains a last user.
578
+ void extendBoundaryFromTerminator (TermInst *user,
579
+ PrunedLivenessBoundary &boundary) {
580
+ auto *block = user->getParent ();
581
+ // Record the successors at the beginning of which we didn't find destroys.
582
+ // If we found a destroy at the beginning of any other successor, then all
583
+ // the other edges become boundary edges.
584
+ SmallVector<SILBasicBlock *, 4 > successorsWithoutDestroys;
585
+ bool foundDestroy = false ;
586
+ for (auto *successor : block->getSuccessorBlocks ()) {
587
+ // If multiple terminators were live and had the same successor, only
588
+ // record the boundary corresponding to that destination block once.
589
+ if (!seenMergePoints.insert (successor)) {
590
+ // Thanks to the lack of critical edges, having seen this successor
591
+ // before means it has multiple predecessors, so this must be \p block's
592
+ // unique successor.
593
+ assert (block->getSingleSuccessorBlock () == successor);
594
+ continue ;
595
+ }
596
+ if (auto *dvi = findDestroyFromBlockBegin (successor, currentDef)) {
597
+ boundary.lastUsers .push_back (dvi);
598
+ foundDestroy = true ;
599
+ } else {
600
+ successorsWithoutDestroys.push_back (successor);
601
+ }
602
+ }
603
+ if (foundDestroy) {
604
+ // If we found a destroy in any successor, then every block at the
605
+ // beginning of which we didn't find a destroy becomes a boundary edge.
606
+ for (auto *successor : successorsWithoutDestroys) {
607
+ boundary.boundaryEdges .push_back (successor);
608
+ }
609
+ } else {
610
+ boundary.lastUsers .push_back (user);
611
+ }
612
+ }
540
613
};
541
- } // namespace swift
614
+ } // anonymous namespace
542
615
543
616
void CanonicalizeOSSALifetime::findExtendedBoundary (
544
617
PrunedLivenessBoundary &boundary) {
545
618
PrunedLivenessBoundary originalBoundary;
546
619
liveness.computeBoundary (originalBoundary, consumingBlocks.getArrayRef ());
547
620
548
- CanonicalizeOSSALifetimeBoundaryExtender extender (liveness, originalBoundary,
549
- getCurrentDef ());
621
+ ExtendBoundaryToDestroys extender (liveness, originalBoundary,
622
+ getCurrentDef ());
550
623
extender.extend (boundary);
551
- assert (boundary.deadDefs .empty () && " dead defs in extended boundary!?" );
552
624
}
553
625
554
626
// ===----------------------------------------------------------------------===//
@@ -579,7 +651,8 @@ static void insertDestroyBeforeInstruction(SILInstruction *nextInstruction,
579
651
// / - The postdominating consumes cannot be within nested loops.
580
652
// / - Any blocks in nested loops are now marked LiveOut.
581
653
void CanonicalizeOSSALifetime::insertDestroysOnBoundary (
582
- PrunedLivenessBoundary &boundary) {
654
+ PrunedLivenessBoundary const &boundary) {
655
+ BasicBlockSet seenMergePoints (getCurrentDef ()->getFunction ());
583
656
for (auto *instruction : boundary.lastUsers ) {
584
657
if (auto *dvi = dynCastToDestroyOf (instruction, getCurrentDef ())) {
585
658
consumes.recordFinalConsume (dvi);
@@ -591,11 +664,23 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
591
664
continue ;
592
665
case PrunedLiveness::IsInterestingUser::NonLifetimeEndingUse:
593
666
case PrunedLiveness::IsInterestingUser::NonUser:
667
+ if (isa<TermInst>(instruction)) {
668
+ auto *block = instruction->getParent ();
669
+ for (auto *successor : block->getSuccessorBlocks ()) {
670
+ if (!seenMergePoints.insert (successor)) {
671
+ assert (block->getSingleSuccessorBlock () == successor);
672
+ continue ;
673
+ }
674
+ auto *insertionPoint = &*successor->begin ();
675
+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (),
676
+ consumes, getCallbacks ());
677
+ LLVM_DEBUG (llvm::dbgs ()
678
+ << " Destroy after terminator " << instruction
679
+ << " at beginning of " << successor << " \n " );
680
+ }
681
+ continue ;
682
+ }
594
683
auto *insertionPoint = instruction->getNextInstruction ();
595
- // If there were no next instruction, it would be a TermInst and we would
596
- // have added the successors as boundary edge destinations (or found
597
- // destroys in their bodies).
598
- assert (insertionPoint);
599
684
insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
600
685
getCallbacks ());
601
686
LLVM_DEBUG (llvm::dbgs ()
@@ -609,6 +694,23 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
609
694
getCallbacks ());
610
695
LLVM_DEBUG (llvm::dbgs () << " Destroy on edge " << edgeDestination << " \n " );
611
696
}
697
+ for (auto *def : boundary.deadDefs ) {
698
+ if (auto *arg = dyn_cast<SILArgument>(def)) {
699
+ auto *insertionPoint = &*arg->getParent ()->begin ();
700
+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
701
+ getCallbacks ());
702
+ LLVM_DEBUG (llvm::dbgs ()
703
+ << " Destroy after dead def arg " << arg << " \n " );
704
+ } else {
705
+ auto *instruction = cast<SILInstruction>(def);
706
+ auto *insertionPoint = instruction->getNextInstruction ();
707
+ assert (insertionPoint && " def instruction was a terminator?!" );
708
+ insertDestroyBeforeInstruction (insertionPoint, getCurrentDef (), consumes,
709
+ getCallbacks ());
710
+ LLVM_DEBUG (llvm::dbgs ()
711
+ << " Destroy after dead def inst " << instruction << " \n " );
712
+ }
713
+ }
612
714
}
613
715
614
716
// ===----------------------------------------------------------------------===//
0 commit comments