@@ -612,11 +612,9 @@ func gatherEnclosingValues(for value: Value,
612
612
in enclosingValues: inout Stack < Value > ,
613
613
_ context: some Context ) {
614
614
615
- var gatherValues = EnclosingValues ( context)
616
- defer { gatherValues. deinitialize ( ) }
617
- var cache = BorrowIntroducers . Cache ( context)
615
+ var cache = EnclosingValues . Cache ( context)
618
616
defer { cache. deinitialize ( ) }
619
- gatherValues . gather ( for: value, in: & enclosingValues, & cache)
617
+ EnclosingValues . gather ( for: value, in: & enclosingValues, & cache, context )
620
618
}
621
619
622
620
/// Find inner adjacent phis in the same block as `enclosingPhi`.
@@ -636,21 +634,61 @@ func gatherInnerAdjacentPhis(for enclosingPhi: Phi,
636
634
637
635
// Find the enclosing values for any value, including reborrows.
638
636
private struct EnclosingValues {
637
+ typealias CachedEnclosingValues = SingleInlineArray < Value >
638
+ struct Cache {
639
+ // Cache the enclosing values already found for each Reborrow.
640
+ var reborrowToEnclosingValues : Dictionary < HashableValue ,
641
+ CachedEnclosingValues >
642
+ // Record recursively followed reborrows to avoid infinite cycles.
643
+ // Reborrows are removed from this set when they are cached.
644
+ var pendingReborrows : ValueSet
645
+
646
+ var borrowIntroducerCache : BorrowIntroducers . Cache
647
+
648
+ init ( _ context: Context ) {
649
+ reborrowToEnclosingValues =
650
+ Dictionary < HashableValue , CachedEnclosingValues > ( )
651
+ pendingReborrows = ValueSet ( context)
652
+ borrowIntroducerCache = BorrowIntroducers . Cache ( context)
653
+ }
654
+
655
+ mutating func deinitialize( ) {
656
+ pendingReborrows. deinitialize ( )
657
+ borrowIntroducerCache. deinitialize ( )
658
+ }
659
+ }
660
+
639
661
var context : Context
640
- var visitedReborrows : ValueSet
662
+ // EnclosingValues instances are recursively nested in order to
663
+ // find outer adjacent phis. Each instance populates a separate
664
+ // 'enclosingValeus' set. The same value may occur in 'enclosingValues' at
665
+ // multiple levels. Each instance, therefore, needs a separate
666
+ // visited set to avoid adding duplicates.
667
+ var visitedEnclosingValues : Set < HashableValue > = Set ( )
668
+
669
+ static func gather( for value: Value , in enclosingValues: inout Stack < Value > ,
670
+ _ cache: inout Cache , _ context: Context ) {
671
+ var gatherValues = EnclosingValues ( context: context)
672
+ gatherValues. gather ( for: value, in: & enclosingValues, & cache)
673
+ }
641
674
642
- init ( _ context: Context ) {
643
- self . context = context
644
- self . visitedReborrows = ValueSet ( context)
675
+ private mutating func push( _ enclosingValue: Value ,
676
+ in enclosingValues: inout Stack < Value > ) {
677
+ if visitedEnclosingValues. insert ( enclosingValue. hashable) . inserted {
678
+ enclosingValues. push ( enclosingValue)
679
+ }
645
680
}
646
681
647
- mutating func deinitialize( ) {
648
- visitedReborrows. deinitialize ( )
682
+ private mutating func push< S: Sequence > ( contentsOf other: S ,
683
+ in enclosingValues: inout Stack < Value > ) where S. Element == Value {
684
+ for elem in other {
685
+ push ( elem, in: & enclosingValues)
686
+ }
649
687
}
650
688
651
689
mutating func gather( for value: Value ,
652
690
in enclosingValues: inout Stack < Value > ,
653
- _ cache: inout BorrowIntroducers . Cache ) {
691
+ _ cache: inout Cache ) {
654
692
if value is Undef || value. ownership != . guaranteed {
655
693
return
656
694
}
@@ -659,7 +697,7 @@ private struct EnclosingValues {
659
697
case let . beginBorrow( bbi) :
660
698
// Gather the outer enclosing borrow scope.
661
699
BorrowIntroducers . gather ( for: bbi. operand. value, in: & enclosingValues,
662
- & cache, context)
700
+ & cache. borrowIntroducerCache , context)
663
701
case . loadBorrow, . beginApply, . functionArgument:
664
702
// There is no enclosing value on this path.
665
703
break
@@ -669,7 +707,7 @@ private struct EnclosingValues {
669
707
} else {
670
708
// Handle forwarded guaranteed values.
671
709
BorrowIntroducers . gather ( for: value, in: & enclosingValues,
672
- & cache, context)
710
+ & cache. borrowIntroducerCache , context)
673
711
}
674
712
}
675
713
@@ -723,16 +761,25 @@ private struct EnclosingValues {
723
761
//
724
762
// gather(forReborrow: %reborrow) finds (%outerReborrow, %outerBorrowB).
725
763
//
764
+ // This implementation mirrors BorrowIntroducers.gather(forPhi:in:).
765
+ // The difference is that this performs use-def recursion over
766
+ // reborrows rather, and at each step, it finds the enclosing values
767
+ // of the reborrow operands rather than the borrow introducers of
768
+ // the guaranteed phi.
726
769
private mutating func gather( forReborrow reborrow: Phi ,
727
770
in enclosingValues: inout Stack < Value > ,
728
- _ cache: inout BorrowIntroducers . Cache ) {
771
+ _ cache: inout Cache ) {
729
772
730
- guard visitedReborrows. insert ( reborrow. value) else {
773
+ // Phi cycles are skipped. They cannot contribute any new introducer.
774
+ if !cache. pendingReborrows. insert ( reborrow. value) {
775
+ return
776
+ }
777
+ if let cachedEnclosingValues =
778
+ cache. reborrowToEnclosingValues [ reborrow. value. hashable] {
779
+ push ( contentsOf: cachedEnclosingValues, in: & enclosingValues)
731
780
return
732
781
}
733
- // avoid duplicates in the enclosingValues set.
734
- var pushedEnclosingValues = ValueSet ( context)
735
- defer { pushedEnclosingValues. deinitialize ( ) }
782
+ assert ( enclosingValues. isEmpty)
736
783
737
784
// Find the enclosing introducer for each reborrow operand, and
738
785
// remap it to the enclosing introducer for the successor block.
@@ -742,14 +789,20 @@ private struct EnclosingValues {
742
789
defer {
743
790
incomingEnclosingValues. deinitialize ( )
744
791
}
745
- gather ( for: incomingValue, in: & incomingEnclosingValues, & cache)
746
- mapToPhi ( predecessor: pred,
747
- incomingValues: incomingEnclosingValues) . forEach {
748
- if pushedEnclosingValues. insert ( $0) {
749
- enclosingValues. append ( $0)
750
- }
751
- }
792
+ EnclosingValues . gather ( for: incomingValue, in: & incomingEnclosingValues,
793
+ & cache, context)
794
+ push ( contentsOf: mapToPhi ( predecessor: pred,
795
+ incomingValues: incomingEnclosingValues) ,
796
+ in: & enclosingValues)
752
797
}
798
+ { cachedIntroducers in
799
+ enclosingValues. forEach { cachedIntroducers. push ( $0) }
800
+ } ( & cache. reborrowToEnclosingValues [ reborrow. value. hashable,
801
+ default: CachedEnclosingValues ( ) ] )
802
+
803
+ // Remove this reborrow from the pending set. It may be visited
804
+ // again at a different level of recursion.
805
+ cache. pendingReborrows. erase ( reborrow. value)
753
806
}
754
807
}
755
808
0 commit comments