@@ -754,6 +754,7 @@ void SSADestroyHoisting::run() {
754754 llvm::SmallVector<AllocStackInst *, 4 > asis;
755755 llvm::SmallVector<BeginAccessInst *, 4 > bais;
756756 llvm::SmallVector<StoreInst *, 4 > sis;
757+ llvm::SmallVector<CopyAddrInst *, 4 > cais;
757758
758759 // Collect the instructions that we'll be transforming.
759760 for (auto &block : *getFunction ()) {
@@ -768,6 +769,10 @@ void SSADestroyHoisting::run() {
768769 if (si->getOwnershipQualifier () == StoreOwnershipQualifier::Assign) {
769770 sis.push_back (si);
770771 }
772+ } else if (auto *cai = dyn_cast<CopyAddrInst>(&inst)) {
773+ if (cai->isInitializationOfDest () == IsNotInitialization) {
774+ cais.push_back (cai);
775+ }
771776 }
772777 }
773778 }
@@ -804,6 +809,32 @@ void SSADestroyHoisting::run() {
804809 remainingDestroyAddrs.insert (dai);
805810 ++splitDestroys;
806811 }
812+ // Similarly, also expand each
813+ //
814+ // copy_addr to
815+ //
816+ // instruction into
817+ //
818+ // destroy_addr
819+ // copy_addr to [initialization]
820+ //
821+ // sequences to create still more destroy_addrs to hoist.
822+ //
823+ // As above, record the newly created destroy_addrs and copy_addrs off of
824+ // which they were split. After hoisting, we'll merge them back together when
825+ // possible.
826+ llvm::SmallVector<std::pair<DestroyAddrInst *, CopyAddrInst *>, 8 >
827+ splitDestroysAndCopies;
828+ for (auto *cai : cais) {
829+ auto builder = SILBuilderWithScope (cai);
830+ auto *dai = builder.createDestroyAddr (
831+ RegularLocation::getAutoGeneratedLocation (cai->getLoc ()),
832+ cai->getOperand (1 ));
833+ cai->setIsInitializationOfDest (IsInitialization);
834+ splitDestroysAndCopies.push_back ({dai, cai});
835+ remainingDestroyAddrs.insert (dai);
836+ ++splitDestroys;
837+ }
807838
808839 // We assume that the function is in reverse post order so visiting the
809840 // blocks and pushing begin_access as we see them and then popping them off
@@ -840,17 +871,29 @@ void SSADestroyHoisting::run() {
840871 if (!remainingDestroyAddrs.contains (dai))
841872 continue ;
842873 auto *si = pair.second ;
843- if (dai->getNextInstruction () == si) {
844- // No stores should have been rewritten during hoisting. Their ownership
845- // qualifiers were set to [init] when splitting off the destroy_addrs.
846- assert (si->getOwnershipQualifier () == StoreOwnershipQualifier::Init);
847- // If a newly created destroy_addr has not been hoisted from its previous
848- // location, combine it back together with the store [init] which it was
849- // split off from.
850- deleter.forceDelete (dai);
851- si->setOwnershipQualifier (StoreOwnershipQualifier::Assign);
852- --splitDestroys;
853- }
874+ if (dai->getNextInstruction () != si)
875+ continue ;
876+ // No stores should have been rewritten during hoisting. Their ownership
877+ // qualifiers were set to [init] when splitting off the destroy_addrs.
878+ assert (si->getOwnershipQualifier () == StoreOwnershipQualifier::Init);
879+ // If a newly created destroy_addr has not been hoisted from its previous
880+ // location, combine it back together with the store [init] which it was
881+ // split off from.
882+ deleter.forceDelete (dai);
883+ si->setOwnershipQualifier (StoreOwnershipQualifier::Assign);
884+ --splitDestroys;
885+ }
886+ for (auto pair : splitDestroysAndCopies) {
887+ auto *dai = pair.first ;
888+ if (!remainingDestroyAddrs.contains (dai))
889+ continue ;
890+ auto *cai = pair.second ;
891+ if (dai->getNextInstruction () != cai)
892+ continue ;
893+ assert (cai->isInitializationOfDest () == IsInitialization);
894+ deleter.forceDelete (dai);
895+ cai->setIsInitializationOfDest (IsNotInitialization);
896+ --splitDestroys;
854897 }
855898 // If there were any destroy_addrs split off of stores and not recombined
856899 // with them, then the function has changed.
0 commit comments