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