@@ -442,32 +442,68 @@ template class PrunedLiveRange<MultiDefPrunedLiveness>;
442
442
// SSAPrunedLiveness
443
443
// ===----------------------------------------------------------------------===//
444
444
445
- void SSAPrunedLiveness::findBoundariesInBlock (
446
- SILBasicBlock *block, bool isLiveOut,
447
- PrunedLivenessBoundary &boundary) const {
448
- assert (isInitialized ());
449
-
450
- // For SSA, a live-out block cannot have a boundary.
451
- if (isLiveOut)
452
- return ;
445
+ // / Given live-within (non-live-out) \p block, find the last user.
446
+ void findBoundaryInNonDefBlock (SILBasicBlock *block,
447
+ PrunedLivenessBoundary &boundary,
448
+ const PrunedLiveness &liveness) {
449
+ assert (liveness.getBlockLiveness (block) == PrunedLiveBlocks::LiveWithin);
453
450
454
- bool isDefBlockState = isDefBlock (block);
455
451
for (SILInstruction &inst : llvm::reverse (*block)) {
456
- if (isDefBlockState && isDef (&inst)) {
452
+ if (liveness.isInterestingUser (&inst)) {
453
+ boundary.lastUsers .push_back (&inst);
454
+ return ;
455
+ }
456
+ }
457
+ llvm_unreachable (" live-within block must contain an interesting use" );
458
+ }
459
+
460
+ // / Given a live-within \p block that contains an SSA definition, and knowledge
461
+ // / that all live uses are dominated by that single definition, find either the
462
+ // / last user or a dead def.
463
+ // /
464
+ // / A live range with a single definition cannot have any uses above that
465
+ // / definition in the same block. This even holds for unreachable self-loops.
466
+ void findBoundaryInSSADefBlock (SILNode *ssaDef,
467
+ PrunedLivenessBoundary &boundary,
468
+ const PrunedLiveness &liveness) {
469
+ // defInst is null for argument defs.
470
+ SILInstruction *defInst = dyn_cast<SILInstruction>(ssaDef);
471
+ for (SILInstruction &inst : llvm::reverse (*ssaDef->getParentBlock ())) {
472
+ if (&inst == defInst) {
457
473
boundary.deadDefs .push_back (cast<SILNode>(&inst));
458
474
return ;
459
475
}
460
- if (isInterestingUser (&inst)) {
476
+ if (liveness. isInterestingUser (&inst)) {
461
477
boundary.lastUsers .push_back (&inst);
462
478
return ;
463
479
}
464
480
}
465
- auto *deadArg = dyn_cast<SILArgument>(def );
466
- assert (deadArg && deadArg-> getParent () == block
481
+ auto *deadArg = dyn_cast<SILArgument>(ssaDef );
482
+ assert (deadArg
467
483
&& " findBoundariesInBlock must be called on a live block" );
468
484
boundary.deadDefs .push_back (deadArg);
469
485
}
470
486
487
+ void SSAPrunedLiveness::findBoundariesInBlock (
488
+ SILBasicBlock *block, bool isLiveOut,
489
+ PrunedLivenessBoundary &boundary) const {
490
+ assert (isInitialized ());
491
+
492
+ // For SSA, a live-out block cannot have a boundary.
493
+ if (isLiveOut)
494
+ return ;
495
+
496
+ // Handle live-within block
497
+ if (!isDefBlock (block)) {
498
+ findBoundaryInNonDefBlock (block, boundary, *this );
499
+ return ;
500
+ }
501
+ // Find either the last user or a dead def
502
+ auto *defInst = def->getDefiningInstruction ();
503
+ SILNode *defNode = defInst ? cast<SILNode>(defInst) : cast<SILArgument>(def);
504
+ findBoundaryInSSADefBlock (defNode, boundary, *this );
505
+ }
506
+
471
507
// ===----------------------------------------------------------------------===//
472
508
// MultiDefPrunedLiveness
473
509
// ===----------------------------------------------------------------------===//
@@ -476,25 +512,45 @@ void MultiDefPrunedLiveness::findBoundariesInBlock(
476
512
SILBasicBlock *block, bool isLiveOut,
477
513
PrunedLivenessBoundary &boundary) const {
478
514
assert (isInitialized ());
479
- unsigned prevCount = boundary.deadDefs .size () + boundary.lastUsers .size ();
480
515
516
+ if (!isDefBlock (block)) {
517
+ // A live-out block with no defs cannot have a boundary.
518
+ if (!isLiveOut) {
519
+ findBoundaryInNonDefBlock (block, boundary, *this );
520
+ }
521
+ return ;
522
+ }
523
+ // Handle def blocks...
524
+ //
525
+ // First, check for an SSA live range
526
+ if (++defs.begin () == defs.end ()) {
527
+ // For SSA, a live-out block cannot have a boundary.
528
+ if (!isLiveOut) {
529
+ findBoundaryInSSADefBlock (*defs.begin (), boundary, *this );
530
+ }
531
+ return ;
532
+ }
533
+ // Handle a live-out or live-within block with potentially multiple defs
534
+ unsigned prevCount = boundary.deadDefs .size () + boundary.lastUsers .size ();
481
535
bool isLive = isLiveOut;
482
- bool isDefBlockState = isDefBlock (block);
483
536
for (auto &inst : llvm::reverse (*block)) {
484
537
// Check if the instruction is a def before checking whether it is a
485
538
// use. The same instruction can be both a dead def and boundary use.
486
- if (isDefBlockState && isDef (&inst)) {
539
+ if (isDef (&inst)) {
487
540
if (!isLive) {
488
541
boundary.deadDefs .push_back (cast<SILNode>(&inst));
489
542
}
490
543
isLive = false ;
491
544
}
545
+ // Note: the same instruction could potentially be both a dead def and last
546
+ // user. The liveness boundary supports this, although it won't happen in
547
+ // any context where we care about inserting code on the boundary.
492
548
if (!isLive && isInterestingUser (&inst)) {
493
549
boundary.lastUsers .push_back (&inst);
494
550
isLive = true ;
495
551
}
496
552
}
497
- if (!isLive && isDefBlockState ) {
553
+ if (!isLive) {
498
554
for (SILArgument *deadArg : block->getArguments ()) {
499
555
if (defs.contains (deadArg)) {
500
556
boundary.deadDefs .push_back (deadArg);
0 commit comments