@@ -489,17 +489,62 @@ bool PrunedLiveRange<LivenessWithDefs>::isWithinBoundary(
489489 llvm_unreachable (" instruction must be in its parent block" );
490490}
491491
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 ;
537+ }
538+
492539template <typename LivenessWithDefs>
493540bool PrunedLiveRange<LivenessWithDefs>::areUsesWithinBoundary(
494541 ArrayRef<Operand *> uses, DeadEndBlocks *deadEndBlocks) const {
495542 assert (asImpl ().isInitialized ());
496543
497- auto checkDeadEnd = [deadEndBlocks](SILInstruction *inst) {
498- return deadEndBlocks && deadEndBlocks->isDeadEnd (inst->getParent ());
499- };
500544 for (auto *use : uses) {
501545 auto *user = use->getUser ();
502- if (!asImpl ().isWithinBoundary (user) && !checkDeadEnd (user))
546+ if (!asImpl ().isWithinBoundary (user) &&
547+ !checkDeadEnd (user->getParent (), deadEndBlocks, liveBlocks))
503548 return false ;
504549 }
505550 return true ;
@@ -510,12 +555,10 @@ bool PrunedLiveRange<LivenessWithDefs>::areUsesOutsideBoundary(
510555 ArrayRef<Operand *> uses, DeadEndBlocks *deadEndBlocks) const {
511556 assert (asImpl ().isInitialized ());
512557
513- auto checkDeadEnd = [deadEndBlocks](SILInstruction *inst) {
514- return deadEndBlocks && deadEndBlocks->isDeadEnd (inst->getParent ());
515- };
516558 for (auto *use : uses) {
517559 auto *user = use->getUser ();
518- if (asImpl ().isWithinBoundary (user) || checkDeadEnd (user))
560+ if (asImpl ().isWithinBoundary (user) ||
561+ checkDeadEnd (user->getParent (), deadEndBlocks, liveBlocks))
519562 return false ;
520563 }
521564 return true ;
0 commit comments