@@ -613,11 +613,9 @@ func gatherEnclosingValues(for value: Value,
613613 in enclosingValues: inout Stack < Value > ,
614614 _ context: some Context ) {
615615
616- var gatherValues = EnclosingValues ( context)
617- defer { gatherValues. deinitialize ( ) }
618- var cache = BorrowIntroducers . Cache ( context)
616+ var cache = EnclosingValues . Cache ( context)
619617 defer { cache. deinitialize ( ) }
620- gatherValues . gather ( for: value, in: & enclosingValues, & cache)
618+ EnclosingValues . gather ( for: value, in: & enclosingValues, & cache, context )
621619}
622620
623621/// Find inner adjacent phis in the same block as `enclosingPhi`.
@@ -637,21 +635,61 @@ func gatherInnerAdjacentPhis(for enclosingPhi: Phi,
637635
638636// Find the enclosing values for any value, including reborrows.
639637private struct EnclosingValues {
638+ typealias CachedEnclosingValues = SingleInlineArray < Value >
639+ struct Cache {
640+ // Cache the enclosing values already found for each Reborrow.
641+ var reborrowToEnclosingValues : Dictionary < HashableValue ,
642+ CachedEnclosingValues >
643+ // Record recursively followed reborrows to avoid infinite cycles.
644+ // Reborrows are removed from this set when they are cached.
645+ var pendingReborrows : ValueSet
646+
647+ var borrowIntroducerCache : BorrowIntroducers . Cache
648+
649+ init ( _ context: Context ) {
650+ reborrowToEnclosingValues =
651+ Dictionary < HashableValue , CachedEnclosingValues > ( )
652+ pendingReborrows = ValueSet ( context)
653+ borrowIntroducerCache = BorrowIntroducers . Cache ( context)
654+ }
655+
656+ mutating func deinitialize( ) {
657+ pendingReborrows. deinitialize ( )
658+ borrowIntroducerCache. deinitialize ( )
659+ }
660+ }
661+
640662 var context : Context
641- var visitedReborrows : ValueSet
663+ // EnclosingValues instances are recursively nested in order to
664+ // find outer adjacent phis. Each instance populates a separate
665+ // 'enclosingValeus' set. The same value may occur in 'enclosingValues' at
666+ // multiple levels. Each instance, therefore, needs a separate
667+ // visited set to avoid adding duplicates.
668+ var visitedEnclosingValues : Set < HashableValue > = Set ( )
669+
670+ static func gather( for value: Value , in enclosingValues: inout Stack < Value > ,
671+ _ cache: inout Cache , _ context: Context ) {
672+ var gatherValues = EnclosingValues ( context: context)
673+ gatherValues. gather ( for: value, in: & enclosingValues, & cache)
674+ }
642675
643- init ( _ context: Context ) {
644- self . context = context
645- self . visitedReborrows = ValueSet ( context)
676+ private mutating func push( _ enclosingValue: Value ,
677+ in enclosingValues: inout Stack < Value > ) {
678+ if visitedEnclosingValues. insert ( enclosingValue. hashable) . inserted {
679+ enclosingValues. push ( enclosingValue)
680+ }
646681 }
647682
648- mutating func deinitialize( ) {
649- visitedReborrows. deinitialize ( )
683+ private mutating func push< S: Sequence > ( contentsOf other: S ,
684+ in enclosingValues: inout Stack < Value > ) where S. Element == Value {
685+ for elem in other {
686+ push ( elem, in: & enclosingValues)
687+ }
650688 }
651689
652690 mutating func gather( for value: Value ,
653691 in enclosingValues: inout Stack < Value > ,
654- _ cache: inout BorrowIntroducers . Cache ) {
692+ _ cache: inout Cache ) {
655693 if value is Undef || value. ownership != . guaranteed {
656694 return
657695 }
@@ -660,7 +698,7 @@ private struct EnclosingValues {
660698 case let . beginBorrow( bbi) :
661699 // Gather the outer enclosing borrow scope.
662700 BorrowIntroducers . gather ( for: bbi. operand. value, in: & enclosingValues,
663- & cache, context)
701+ & cache. borrowIntroducerCache , context)
664702 case . loadBorrow, . beginApply, . functionArgument:
665703 // There is no enclosing value on this path.
666704 break
@@ -670,7 +708,7 @@ private struct EnclosingValues {
670708 } else {
671709 // Handle forwarded guaranteed values.
672710 BorrowIntroducers . gather ( for: value, in: & enclosingValues,
673- & cache, context)
711+ & cache. borrowIntroducerCache , context)
674712 }
675713 }
676714
@@ -724,16 +762,25 @@ private struct EnclosingValues {
724762 //
725763 // gather(forReborrow: %reborrow) finds (%outerReborrow, %outerBorrowB).
726764 //
765+ // This implementation mirrors BorrowIntroducers.gather(forPhi:in:).
766+ // The difference is that this performs use-def recursion over
767+ // reborrows rather, and at each step, it finds the enclosing values
768+ // of the reborrow operands rather than the borrow introducers of
769+ // the guaranteed phi.
727770 private mutating func gather( forReborrow reborrow: Phi ,
728771 in enclosingValues: inout Stack < Value > ,
729- _ cache: inout BorrowIntroducers . Cache ) {
772+ _ cache: inout Cache ) {
730773
731- guard visitedReborrows. insert ( reborrow. value) else {
774+ // Phi cycles are skipped. They cannot contribute any new introducer.
775+ if !cache. pendingReborrows. insert ( reborrow. value) {
776+ return
777+ }
778+ if let cachedEnclosingValues =
779+ cache. reborrowToEnclosingValues [ reborrow. value. hashable] {
780+ push ( contentsOf: cachedEnclosingValues, in: & enclosingValues)
732781 return
733782 }
734- // avoid duplicates in the enclosingValues set.
735- var pushedEnclosingValues = ValueSet ( context)
736- defer { pushedEnclosingValues. deinitialize ( ) }
783+ assert ( enclosingValues. isEmpty)
737784
738785 // Find the enclosing introducer for each reborrow operand, and
739786 // remap it to the enclosing introducer for the successor block.
@@ -743,14 +790,20 @@ private struct EnclosingValues {
743790 defer {
744791 incomingEnclosingValues. deinitialize ( )
745792 }
746- gather ( for: incomingValue, in: & incomingEnclosingValues, & cache)
747- mapToPhi ( predecessor: pred,
748- incomingValues: incomingEnclosingValues) . forEach {
749- if pushedEnclosingValues. insert ( $0) {
750- enclosingValues. append ( $0)
751- }
752- }
793+ EnclosingValues . gather ( for: incomingValue, in: & incomingEnclosingValues,
794+ & cache, context)
795+ push ( contentsOf: mapToPhi ( predecessor: pred,
796+ incomingValues: incomingEnclosingValues) ,
797+ in: & enclosingValues)
753798 }
799+ { cachedIntroducers in
800+ enclosingValues. forEach { cachedIntroducers. push ( $0) }
801+ } ( & cache. reborrowToEnclosingValues [ reborrow. value. hashable,
802+ default: CachedEnclosingValues ( ) ] )
803+
804+ // Remove this reborrow from the pending set. It may be visited
805+ // again at a different level of recursion.
806+ cache. pendingReborrows. erase ( reborrow. value)
754807 }
755808}
756809
0 commit comments