@@ -494,6 +494,7 @@ bool DeinitBarriers::DestroyReachability::checkReachablePhiBarrier(
494
494
class HoistDestroys {
495
495
SILValue storageRoot;
496
496
bool ignoreDeinitBarriers;
497
+ SmallPtrSetImpl<SILInstruction *> &remainingDestroyAddrs;
497
498
InstructionDeleter &deleter;
498
499
499
500
// Book-keeping for the rewriting stage.
@@ -503,9 +504,11 @@ class HoistDestroys {
503
504
504
505
public:
505
506
HoistDestroys (SILValue storageRoot, bool ignoreDeinitBarriers,
507
+ SmallPtrSetImpl<SILInstruction *> &remainingDestroyAddrs,
506
508
InstructionDeleter &deleter)
507
509
: storageRoot(storageRoot), ignoreDeinitBarriers(ignoreDeinitBarriers),
508
- deleter (deleter), destroyMergeBlocks(getFunction()) {}
510
+ remainingDestroyAddrs (remainingDestroyAddrs), deleter(deleter),
511
+ destroyMergeBlocks(getFunction()) {}
509
512
510
513
bool perform ();
511
514
@@ -593,6 +596,7 @@ bool HoistDestroys::rewriteDestroys(const KnownStorageUses &knownUses,
593
596
if (reusedDestroys.contains (destroyInst))
594
597
continue ;
595
598
599
+ remainingDestroyAddrs.erase (destroyInst);
596
600
deleter.forceDelete (destroyInst);
597
601
}
598
602
deleter.cleanupDeadInstructions ();
@@ -697,6 +701,7 @@ void HoistDestroys::mergeDestroys(SILBasicBlock *mergeBlock) {
697
701
createDestroy (&mergeBlock->front (), deadDestroys[0 ]->getDebugScope ());
698
702
699
703
for (auto *deadDestroy : deadDestroys) {
704
+ remainingDestroyAddrs.erase (deadDestroy);
700
705
deleter.forceDelete (deadDestroy);
701
706
}
702
707
}
@@ -706,6 +711,7 @@ void HoistDestroys::mergeDestroys(SILBasicBlock *mergeBlock) {
706
711
// =============================================================================
707
712
708
713
bool hoistDestroys (SILValue root, bool ignoreDeinitBarriers,
714
+ SmallPtrSetImpl<SILInstruction *> &remainingDestroyAddrs,
709
715
InstructionDeleter &deleter) {
710
716
LLVM_DEBUG (llvm::dbgs () << " Performing destroy hoisting on " << root);
711
717
@@ -716,7 +722,9 @@ bool hoistDestroys(SILValue root, bool ignoreDeinitBarriers,
716
722
// The algorithm assumes no critical edges.
717
723
assert (function->hasOwnership () && " requires OSSA" );
718
724
719
- return HoistDestroys (root, ignoreDeinitBarriers, deleter).perform ();
725
+ return HoistDestroys (root, ignoreDeinitBarriers, remainingDestroyAddrs,
726
+ deleter)
727
+ .perform ();
720
728
}
721
729
722
730
// =============================================================================
@@ -770,24 +778,41 @@ void SSADestroyHoisting::run() {
770
778
// store [init]
771
779
//
772
780
// sequences to create more destroy_addrs to hoist.
781
+ //
782
+ // Record the newly created destroy_addrs and the stores they were split off
783
+ // of. After hoisting, if they have not been hoisted away from the store
784
+ // instruction, we will merge them back together.
785
+ llvm::SmallVector<std::pair<DestroyAddrInst *, StoreInst *>, 8 >
786
+ splitDestroysAndStores;
787
+ // The destroy_addrs that were created that have not been deleted. Items are
788
+ // erased from the set as the destroy_addrs are deleted.
789
+ SmallPtrSet<SILInstruction *, 8 > remainingDestroyAddrs;
790
+ // The number of destroys that were split off of store [init]s and not
791
+ // recombined.
792
+ int splitDestroys = 0 ;
773
793
for (auto *si : sis) {
774
794
auto builder = SILBuilderWithScope (si);
775
- builder.createDestroyAddr (
795
+ auto *dai = builder.createDestroyAddr (
776
796
RegularLocation::getAutoGeneratedLocation (si->getLoc ()),
777
797
si->getOperand (1 ));
778
798
si->setOwnershipQualifier (StoreOwnershipQualifier::Init);
799
+ splitDestroysAndStores.push_back ({dai, si});
800
+ remainingDestroyAddrs.insert (dai);
801
+ ++splitDestroys;
779
802
}
780
803
781
804
// We assume that the function is in reverse post order so visiting the
782
805
// blocks and pushing begin_access as we see them and then popping them off
783
806
// the end will result in hoisting inner begin_access' destroy_addrs first.
784
807
while (!bais.empty ()) {
785
808
auto *bai = bais.pop_back_val ();
786
- changed |= hoistDestroys (bai, /* ignoreDeinitBarriers=*/ true , deleter);
809
+ changed |= hoistDestroys (bai, /* ignoreDeinitBarriers=*/ true ,
810
+ remainingDestroyAddrs, deleter);
787
811
}
788
812
// Alloc stacks always enclose their accesses.
789
813
for (auto *asi : asis) {
790
- changed |= hoistDestroys (asi, /* ignoreDeinitBarriers=*/ false , deleter);
814
+ changed |= hoistDestroys (asi, /* ignoreDeinitBarriers=*/ false ,
815
+ remainingDestroyAddrs, deleter);
791
816
}
792
817
// Arguments enclose everything.
793
818
for (auto *arg : getFunction ()->getArguments ()) {
@@ -796,9 +821,30 @@ void SSADestroyHoisting::run() {
796
821
->getArgumentConvention ()
797
822
.isInoutConvention ();
798
823
changed |= hoistDestroys (arg, /* ignoreDeinitBarriers=*/
799
- isInout, deleter);
824
+ isInout, remainingDestroyAddrs, deleter);
825
+ }
826
+ }
827
+
828
+ for (auto pair : splitDestroysAndStores) {
829
+ auto *dai = pair.first ;
830
+ if (!remainingDestroyAddrs.contains (dai))
831
+ continue ;
832
+ auto *si = pair.second ;
833
+ if (dai->getNextInstruction () == si) {
834
+ // No stores should have been rewritten during hoisting. Their ownership
835
+ // qualifiers were set to [init] when splitting off the destroy_addrs.
836
+ assert (si->getOwnershipQualifier () == StoreOwnershipQualifier::Init);
837
+ // If a newly created destroy_addr has not been hoisted from its previous
838
+ // location, combine it back together with the store [init] which it was
839
+ // split off from.
840
+ deleter.forceDelete (dai);
841
+ si->setOwnershipQualifier (StoreOwnershipQualifier::Assign);
842
+ --splitDestroys;
800
843
}
801
844
}
845
+ // If there were any destroy_addrs split off of stores and not recombined
846
+ // with them, then the function has changed.
847
+ changed |= splitDestroys > 0 ;
802
848
803
849
if (changed) {
804
850
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
0 commit comments