@@ -441,6 +441,7 @@ class HoistDestroys {
441441 SmallVectorImpl<LoadInst *> &loads,
442442 SmallVectorImpl<CopyAddrInst *> &copies,
443443 SmallPtrSetImpl<AccessPath::PathNode> &leaves,
444+ SmallPtrSetImpl<AccessPath::PathNode> &trivialLeaves,
444445 const AccessStorage &storage,
445446 const DeinitBarriers &deinitBarriers);
446447
@@ -568,6 +569,25 @@ bool HoistDestroys::foldBarrier(SILInstruction *barrier,
568569 // destroy_addr in order for folding to occur.
569570 llvm::SmallPtrSet<AccessPath::PathNode, 16 > leaves;
570571
572+ // The trivial storage leaves of the root storage. They needn't be destroyed
573+ // in the sequence prior to the destroy_addr, but their uses may obstruct
574+ // folding. For example, given an %object and %triv a trivial subobject
575+ //
576+ // load [copy] %object
577+ // load [trivial] %triv
578+ // destroy_addr %object
579+ //
580+ // it isn't legal to fold the destroy_addr into the load of %object like
581+ //
582+ // load [take] %object
583+ // load [trivial] %triv
584+ //
585+ // because the memory location %triv is no longer valid. In general, it would
586+ // be fine to support folding over accesses of trivial subobjects so long as
587+ // they occur prior to the access to some nontrivial subobject that contains
588+ // it.
589+ SmallPtrSet<AccessPath::PathNode, 16 > trivialLeaves;
590+
571591 visitProductLeafAccessPathNodes (storageRoot, typeExpansionContext, module ,
572592 [&](AccessPath::PathNode node, SILType ty) {
573593 if (ty.isTrivial (*function))
@@ -577,8 +597,8 @@ bool HoistDestroys::foldBarrier(SILInstruction *barrier,
577597
578598 for (auto *instruction = barrier; instruction != nullptr ;
579599 instruction = instruction->getPreviousInstruction ()) {
580- if (checkFoldingBarrier (instruction, loads, copies, leaves, storage ,
581- deinitBarriers))
600+ if (checkFoldingBarrier (instruction, loads, copies, leaves, trivialLeaves ,
601+ storage, deinitBarriers))
582602 return false ;
583603
584604 // If we have load [copy]s or copy_addrs of projections out of the root
@@ -672,8 +692,9 @@ bool HoistDestroys::foldBarrier(SILInstruction *barrier,
672692bool HoistDestroys::checkFoldingBarrier (
673693 SILInstruction *instruction, SmallVectorImpl<LoadInst *> &loads,
674694 SmallVectorImpl<CopyAddrInst *> &copies,
675- SmallPtrSetImpl<AccessPath::PathNode> &leaves, const AccessStorage &storage,
676- const DeinitBarriers &deinitBarriers) {
695+ SmallPtrSetImpl<AccessPath::PathNode> &leaves,
696+ SmallPtrSetImpl<AccessPath::PathNode> &trivialLeaves,
697+ const AccessStorage &storage, const DeinitBarriers &deinitBarriers) {
677698 // The address of a projection out of the root storage which would be
678699 // folded if folding is possible.
679700 //
@@ -720,14 +741,18 @@ bool HoistDestroys::checkFoldingBarrier(
720741 // Find its nontrivial product leaves and remove them from the set of
721742 // leaves of the root storage which we're wating to see.
722743 bool alreadySawLeaf = false ;
723- visitProductLeafAccessPathNodes (address, typeExpansionContext, module ,
724- [&](AccessPath::PathNode node, SILType ty) {
725- if (ty.isTrivial (*function))
726- return ;
727- bool erased = leaves.erase (node);
728- alreadySawLeaf =
729- alreadySawLeaf || !erased;
730- });
744+ bool alreadySawTrivialSubleaf = false ;
745+ visitProductLeafAccessPathNodes (
746+ address, typeExpansionContext, module ,
747+ [&](AccessPath::PathNode node, SILType ty) {
748+ if (ty.isTrivial (*function)) {
749+ bool inserted = !trivialLeaves.insert (node).second ;
750+ alreadySawTrivialSubleaf = alreadySawTrivialSubleaf || inserted;
751+ return ;
752+ }
753+ bool erased = leaves.erase (node);
754+ alreadySawLeaf = alreadySawLeaf || !erased;
755+ });
731756 if (alreadySawLeaf) {
732757 // We saw this non-trivial product leaf already. That means there are
733758 // multiple load [copy]s or copy_addrs of at least one product leaf
@@ -736,6 +761,11 @@ bool HoistDestroys::checkFoldingBarrier(
736761 // Give up on folding.
737762 return true ;
738763 }
764+ if (alreadySawTrivialSubleaf) {
765+ // We saw this trivial leaf already. That means there was some later
766+ // load [copy] or copy_addr of it. Give up on folding.
767+ return true ;
768+ }
739769 } else if (deinitBarriers.isBarrier (instruction)) {
740770 // We didn't find an instruction that was both
741771 // - relevant (i.e. a copy_addr or a load [take])
0 commit comments