@@ -101,19 +101,22 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
101
101
Context.Diags .diagnose (loc, diag, std::forward<U>(args)...);
102
102
}
103
103
104
- static DestroyValueInst *dynCastToDestroyOf (SILInstruction *instruction,
105
- SILValue def) {
104
+ // / Is \p instruction a destroy_value whose operand is \p def, or its
105
+ // / transitive copy.
106
+ static bool isDestroyOfCopyOf (SILInstruction *instruction, SILValue def) {
106
107
auto *destroy = dyn_cast<DestroyValueInst>(instruction);
107
108
if (!destroy)
108
- return nullptr ;
109
- auto originalDestroyedDef = destroy->getOperand ();
110
- if (originalDestroyedDef == def)
111
- return destroy;
112
- auto underlyingDestroyedDef =
113
- CanonicalizeOSSALifetime::getCanonicalCopiedDef (originalDestroyedDef);
114
- if (underlyingDestroyedDef != def)
115
- return nullptr ;
116
- return destroy;
109
+ return false ;
110
+ auto destroyed = destroy->getOperand ();
111
+ while (true ) {
112
+ if (destroyed == def)
113
+ return true ;
114
+ auto *copy = dyn_cast<CopyValueInst>(destroyed);
115
+ if (!copy)
116
+ break ;
117
+ destroyed = copy->getOperand ();
118
+ }
119
+ return false ;
117
120
}
118
121
119
122
// ===----------------------------------------------------------------------===//
@@ -172,11 +175,18 @@ bool CanonicalizeOSSALifetime::computeCanonicalLiveness() {
172
175
liveness->updateForUse (user, /* lifetimeEnding*/ true );
173
176
break ;
174
177
case OperandOwnership::DestroyingConsume:
175
- if (isa<DestroyValueInst> (user)) {
178
+ if (isDestroyOfCopyOf (user, getCurrentDef () )) {
176
179
destroys.insert (user);
177
180
} else {
178
- // destroy_value does not force pruned liveness (but store etc. does).
179
- liveness->updateForUse (user, /* lifetimeEnding*/ true );
181
+ // destroy_value of a transitive copy of the currentDef does not
182
+ // force pruned liveness (but store etc. does).
183
+
184
+ // Even though this instruction is a DestroyingConsume of its operand,
185
+ // if it's a destroy_value whose operand is not a transitive copy of
186
+ // currentDef, then it's just ending an implicit borrow of currentDef,
187
+ // not consuming it.
188
+ auto lifetimeEnding = !isa<DestroyValueInst>(user);
189
+ liveness->updateForUse (user, lifetimeEnding);
180
190
}
181
191
recordConsumingUse (use);
182
192
break ;
@@ -511,7 +521,7 @@ void CanonicalizeOSSALifetime::extendUnconsumedLiveness(
511
521
// destroys.
512
522
BasicBlockWorklist worklist (currentDef->getFunction ());
513
523
for (auto *instruction : boundary.lastUsers ) {
514
- if (dynCastToDestroyOf (instruction, getCurrentDef () ))
524
+ if (destroys. contains (instruction))
515
525
continue ;
516
526
if (liveness->isInterestingUser (instruction)
517
527
!= PrunedLiveness::IsInterestingUser::LifetimeEndingUse)
@@ -576,17 +586,20 @@ namespace {
576
586
// / values with overlapping live ranges and failing to find a fixed point
577
587
// / because their destroys are repeatedly hoisted over one another.
578
588
class ExtendBoundaryToDestroys final {
589
+ using InstructionPredicate = llvm::function_ref<bool (SILInstruction *)>;
579
590
SSAPrunedLiveness &liveness;
580
591
PrunedLivenessBoundary const &originalBoundary;
581
592
SILValue currentDef;
582
593
BasicBlockSet seenMergePoints;
594
+ InstructionPredicate isDestroy;
583
595
584
596
public:
585
597
ExtendBoundaryToDestroys (SSAPrunedLiveness &liveness,
586
598
PrunedLivenessBoundary const &originalBoundary,
587
- SILValue currentDef)
599
+ SILValue currentDef, InstructionPredicate isDestroy )
588
600
: liveness(liveness), originalBoundary(originalBoundary),
589
- currentDef (currentDef), seenMergePoints(currentDef->getFunction ()){};
601
+ currentDef (currentDef), seenMergePoints(currentDef->getFunction ()),
602
+ isDestroy(isDestroy){};
590
603
ExtendBoundaryToDestroys (ExtendBoundaryToDestroys const &) = delete;
591
604
ExtendBoundaryToDestroys &
592
605
operator =(ExtendBoundaryToDestroys const &) = delete;
@@ -610,34 +623,37 @@ class ExtendBoundaryToDestroys final {
610
623
// / Look past ignoreable instructions to find the _last_ destroy after the
611
624
// / specified instruction that destroys \p def.
612
625
static DestroyValueInst *findDestroyAfter (SILInstruction *previous,
613
- SILValue def) {
626
+ SILValue def,
627
+ InstructionPredicate isDestroy) {
614
628
DestroyValueInst *retval = nullptr ;
615
629
for (auto *instruction = previous->getNextInstruction (); instruction;
616
630
instruction = instruction->getNextInstruction ()) {
617
631
if (!CanonicalizeOSSALifetime::ignoredByDestroyHoisting (
618
632
instruction->getKind ()))
619
633
break ;
620
- if (auto destroy = dynCastToDestroyOf (instruction, def ))
621
- retval = destroy ;
634
+ if (isDestroy (instruction))
635
+ retval = cast<DestroyValueInst>(instruction) ;
622
636
}
623
637
return retval;
624
638
}
625
639
626
640
// / Look past ignoreable instructions to find the _last_ destroy at or after
627
641
// / the specified instruction that destroys \p def.
628
- static DestroyValueInst *findDestroyAtOrAfter (SILInstruction *start,
629
- SILValue def) {
630
- if (auto *dvi = dynCastToDestroyOf (start, def))
631
- return dvi;
632
- return findDestroyAfter (start, def);
642
+ static DestroyValueInst *
643
+ findDestroyAtOrAfter (SILInstruction *start, SILValue def,
644
+ InstructionPredicate isDestroy) {
645
+ if (isDestroy (start))
646
+ return cast<DestroyValueInst>(start);
647
+ return findDestroyAfter (start, def, isDestroy);
633
648
}
634
649
635
650
// / Look past ignoreable instructions to find the _first_ destroy in \p
636
651
// / destination that destroys \p def and isn't separated from the beginning
637
652
// / by "interesting" instructions.
638
- static DestroyValueInst *findDestroyFromBlockBegin (SILBasicBlock *destination,
639
- SILValue def) {
640
- return findDestroyAtOrAfter (&*destination->begin (), def);
653
+ static DestroyValueInst *
654
+ findDestroyFromBlockBegin (SILBasicBlock *destination, SILValue def,
655
+ InstructionPredicate isDestroy) {
656
+ return findDestroyAtOrAfter (&*destination->begin (), def, isDestroy);
641
657
}
642
658
643
659
private:
@@ -651,12 +667,14 @@ class ExtendBoundaryToDestroys final {
651
667
// / stays in place and \p def remains a dead def.
652
668
void extendBoundaryFromDef (SILNode *def, PrunedLivenessBoundary &boundary) {
653
669
if (auto *arg = dyn_cast<SILArgument>(def)) {
654
- if (auto *dvi = findDestroyFromBlockBegin (arg->getParent (), currentDef)) {
670
+ if (auto *dvi = findDestroyFromBlockBegin (arg->getParent (), currentDef,
671
+ isDestroy)) {
655
672
boundary.lastUsers .push_back (dvi);
656
673
return ;
657
674
}
658
675
} else {
659
- if (auto *dvi = findDestroyAfter (cast<SILInstruction>(def), currentDef)) {
676
+ if (auto *dvi = findDestroyAfter (cast<SILInstruction>(def), currentDef,
677
+ isDestroy)) {
660
678
boundary.lastUsers .push_back (dvi);
661
679
return ;
662
680
}
@@ -673,7 +691,8 @@ class ExtendBoundaryToDestroys final {
673
691
// / stays in place and \p destination remains a boundary edge.
674
692
void extendBoundaryFromBoundaryEdge (SILBasicBlock *destination,
675
693
PrunedLivenessBoundary &boundary) {
676
- if (auto *dvi = findDestroyFromBlockBegin (destination, currentDef)) {
694
+ if (auto *dvi =
695
+ findDestroyFromBlockBegin (destination, currentDef, isDestroy)) {
677
696
boundary.lastUsers .push_back (dvi);
678
697
} else {
679
698
boundary.boundaryEdges .push_back (destination);
@@ -694,8 +713,9 @@ class ExtendBoundaryToDestroys final {
694
713
// / user remains a last user.
695
714
void extendBoundaryFromUser (SILInstruction *user,
696
715
PrunedLivenessBoundary &boundary) {
697
- if (auto *dvi = dynCastToDestroyOf (user, currentDef)) {
698
- auto *existingDestroy = findDestroyAtOrAfter (dvi, currentDef);
716
+ if (isDestroy (user)) {
717
+ auto *dvi = cast<DestroyValueInst>(user);
718
+ auto *existingDestroy = findDestroyAtOrAfter (dvi, currentDef, isDestroy);
699
719
assert (existingDestroy && " couldn't find a destroy at or after one!?" );
700
720
boundary.lastUsers .push_back (existingDestroy);
701
721
return ;
@@ -713,7 +733,8 @@ class ExtendBoundaryToDestroys final {
713
733
extendBoundaryFromTerminator (terminator, boundary);
714
734
return ;
715
735
}
716
- if (auto *existingDestroy = findDestroyAfter (user, currentDef)) {
736
+ if (auto *existingDestroy =
737
+ findDestroyAfter (user, currentDef, isDestroy)) {
717
738
boundary.lastUsers .push_back (existingDestroy);
718
739
return ;
719
740
}
@@ -745,7 +766,8 @@ class ExtendBoundaryToDestroys final {
745
766
assert (block->getSingleSuccessorBlock () == successor);
746
767
continue ;
747
768
}
748
- if (auto *dvi = findDestroyFromBlockBegin (successor, currentDef)) {
769
+ if (auto *dvi =
770
+ findDestroyFromBlockBegin (successor, currentDef, isDestroy)) {
749
771
boundary.lastUsers .push_back (dvi);
750
772
foundDestroy = true ;
751
773
} else {
@@ -770,8 +792,9 @@ void CanonicalizeOSSALifetime::findExtendedBoundary(
770
792
PrunedLivenessBoundary &boundary) {
771
793
assert (boundary.lastUsers .size () == 0 && boundary.boundaryEdges .size () == 0 &&
772
794
boundary.deadDefs .size () == 0 );
795
+ auto isDestroy = [&](auto *inst) { return destroys.contains (inst); };
773
796
ExtendBoundaryToDestroys extender (*liveness, originalBoundary,
774
- getCurrentDef ());
797
+ getCurrentDef (), isDestroy );
775
798
extender.extend (boundary);
776
799
}
777
800
@@ -806,8 +829,8 @@ void CanonicalizeOSSALifetime::insertDestroysOnBoundary(
806
829
PrunedLivenessBoundary const &boundary) {
807
830
BasicBlockSet seenMergePoints (getCurrentDef ()->getFunction ());
808
831
for (auto *instruction : boundary.lastUsers ) {
809
- if (auto *dvi = dynCastToDestroyOf (instruction, getCurrentDef () )) {
810
- consumes.recordFinalConsume (dvi );
832
+ if (destroys. contains (instruction)) {
833
+ consumes.recordFinalConsume (instruction );
811
834
continue ;
812
835
}
813
836
switch (liveness->isInterestingUser (instruction)) {
@@ -905,7 +928,8 @@ void CanonicalizeOSSALifetime::rewriteCopies() {
905
928
defUseWorklist.insert (copy);
906
929
return true ;
907
930
}
908
- if (auto *destroy = dynCastToDestroyOf (user, getCurrentDef ())) {
931
+ if (destroys.contains (user)) {
932
+ auto *destroy = cast<DestroyValueInst>(user);
909
933
// If this destroy was marked as a final destroy, ignore it; otherwise,
910
934
// delete it.
911
935
if (!consumes.claimConsume (destroy)) {
0 commit comments