@@ -489,8 +489,51 @@ bool PrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
489
489
llvm_unreachable (" instruction must be in its parent block" );
490
490
}
491
491
492
- static bool checkDeadEnd (SILInstruction *inst, DeadEndBlocks *deadEndBlocks) {
493
- return deadEndBlocks && deadEndBlocks->isDeadEnd (inst->getParent ());
492
+ // / Whether \p parent is a dead (reported to be dead by `liveBlocks`), dead-end
493
+ // / (such as an infinite loop) block within the availability boundary (where
494
+ // / the value has not been consumed).
495
+ static bool checkDeadEnd (SILBasicBlock *parent, DeadEndBlocks *deadEndBlocks,
496
+ PrunedLiveBlocks const &liveBlocks) {
497
+ if (!deadEndBlocks) {
498
+ return false ;
499
+ }
500
+ if (!deadEndBlocks->isDeadEnd (parent)) {
501
+ return false ;
502
+ }
503
+ if (liveBlocks.getBlockLiveness (parent) != PrunedLiveBlocks::Dead) {
504
+ return false ;
505
+ }
506
+ // Check whether the value is available in `parent` (i.e. not consumed on any
507
+ // path to it):
508
+ //
509
+ // Search backward until LiveOut or LiveWithin blocks are reached.
510
+ // (1) If ALL the reached blocks are LiveOut, then `parent` IS within the
511
+ // availability boundary.
512
+ // (2) If ANY reached block is LiveWithin, the value was consumed in that
513
+ // reached block, preventing the value from being available at `parent`,
514
+ // so `parent` is NOT within the availability boundary.
515
+ BasicBlockWorklist worklist (parent->getFunction ());
516
+ worklist.push (parent);
517
+ while (auto *block = worklist.pop ()) {
518
+ auto isLive = liveBlocks.getBlockLiveness (block);
519
+ switch (isLive) {
520
+ case PrunedLiveBlocks::Dead: {
521
+ // Availability is unchanged; continue the backwards walk.
522
+ for (auto *predecessor : block->getPredecessorBlocks ()) {
523
+ worklist.pushIfNotVisited (predecessor);
524
+ }
525
+ break ;
526
+ }
527
+ case PrunedLiveBlocks::LiveWithin:
528
+ // Availability ended in this block. Some path to `parent` consumed the
529
+ // value. Case (2) above.
530
+ return false ;
531
+ case PrunedLiveBlocks::LiveOut:
532
+ // Availability continued out of this block. Case (1) above.
533
+ continue ;
534
+ }
535
+ }
536
+ return true ;
494
537
}
495
538
496
539
template <typename LivenessWithDefs>
@@ -500,7 +543,8 @@ bool PrunedLiveRange<LivenessWithDefs>::areUsesWithinBoundary(
500
543
501
544
for (auto *use : uses) {
502
545
auto *user = use->getUser ();
503
- if (!asImpl ().isWithinBoundary (user) && !checkDeadEnd (user, deadEndBlocks))
546
+ if (!asImpl ().isWithinBoundary (user) &&
547
+ !checkDeadEnd (user->getParent (), deadEndBlocks, liveBlocks))
504
548
return false ;
505
549
}
506
550
return true ;
@@ -513,7 +557,8 @@ bool PrunedLiveRange<LivenessWithDefs>::areUsesOutsideBoundary(
513
557
514
558
for (auto *use : uses) {
515
559
auto *user = use->getUser ();
516
- if (asImpl ().isWithinBoundary (user) || checkDeadEnd (user, deadEndBlocks))
560
+ if (asImpl ().isWithinBoundary (user) ||
561
+ checkDeadEnd (user->getParent (), deadEndBlocks, liveBlocks))
517
562
return false ;
518
563
}
519
564
return true ;
0 commit comments