@@ -393,8 +393,9 @@ enum BeginBorrowValue {
393
393
/// %field = ref_element_addr %first // (none)
394
394
/// %load = load_borrow %field : $*C // %load
395
395
func gatherBorrowIntroducers( for value: Value ,
396
- in borrowIntroducers: inout Stack < Value > ,
396
+ in borrowIntroducers: inout Stack < BeginBorrowValue > ,
397
397
_ context: Context ) {
398
+ assert ( value. ownership == . guaranteed)
398
399
399
400
// Cache introducers across multiple instances of BorrowIntroducers.
400
401
var cache = BorrowIntroducers . Cache ( context)
@@ -404,7 +405,7 @@ func gatherBorrowIntroducers(for value: Value,
404
405
}
405
406
406
407
private struct BorrowIntroducers {
407
- typealias CachedIntroducers = SingleInlineArray < Value >
408
+ typealias CachedIntroducers = SingleInlineArray < BeginBorrowValue >
408
409
struct Cache {
409
410
// Cache the introducers already found for each SILValue.
410
411
var valueIntroducers : Dictionary < HashableValue , CachedIntroducers >
@@ -430,21 +431,21 @@ private struct BorrowIntroducers {
430
431
// introducer set to avoid adding duplicates.
431
432
var visitedIntroducers : Set < HashableValue > = Set ( )
432
433
433
- static func gather( for value: Value , in introducers: inout Stack < Value > ,
434
+ static func gather( for value: Value , in introducers: inout Stack < BeginBorrowValue > ,
434
435
_ cache: inout Cache , _ context: Context ) {
435
436
var borrowIntroducers = BorrowIntroducers ( context: context)
436
437
borrowIntroducers. gather ( for: value, in: & introducers, & cache)
437
438
}
438
439
439
- private mutating func push( _ introducer : Value ,
440
- in introducers: inout Stack < Value > ) {
441
- if visitedIntroducers. insert ( introducer . hashable) . inserted {
442
- introducers. push ( introducer )
440
+ private mutating func push( _ beginBorrow : BeginBorrowValue ,
441
+ in introducers: inout Stack < BeginBorrowValue > ) {
442
+ if visitedIntroducers. insert ( beginBorrow . value . hashable) . inserted {
443
+ introducers. push ( beginBorrow )
443
444
}
444
445
}
445
446
446
447
private mutating func push< S: Sequence > ( contentsOf other: S ,
447
- in introducers: inout Stack < Value > ) where S. Element == Value {
448
+ in introducers: inout Stack < BeginBorrowValue > ) where S. Element == BeginBorrowValue {
448
449
for elem in other {
449
450
push ( elem, in: & introducers)
450
451
}
@@ -457,8 +458,9 @@ private struct BorrowIntroducers {
457
458
//
458
459
// Otherwise recurse up the use-def chain to find all introducers.
459
460
private mutating func gather( for value: Value ,
460
- in introducers: inout Stack < Value > ,
461
+ in introducers: inout Stack < BeginBorrowValue > ,
461
462
_ cache: inout Cache ) {
463
+ assert ( value. ownership == . guaranteed)
462
464
// Check if this value's introducers have already been added to
463
465
// 'introducers' to avoid duplicates and avoid exponential
464
466
// recursion on aggregates.
@@ -478,23 +480,12 @@ private struct BorrowIntroducers {
478
480
}
479
481
480
482
private mutating func gatherUncached( for value: Value ,
481
- in introducers: inout Stack < Value > ,
483
+ in introducers: inout Stack < BeginBorrowValue > ,
482
484
_ cache: inout Cache ) {
483
- switch value. ownership {
484
- case . none, . unowned:
485
- return
486
-
487
- case . owned:
488
- push ( value, in: & introducers) ;
489
- return
490
-
491
- case . guaranteed:
492
- break
493
- }
494
485
// BeginBorrowedValue handles the initial scope introducers: begin_borrow,
495
486
// load_borrow, & reborrow.
496
- if BeginBorrowValue ( value) != nil {
497
- push ( value , in: & introducers)
487
+ if let beginBorrow = BeginBorrowValue ( value) {
488
+ push ( beginBorrow , in: & introducers)
498
489
return
499
490
}
500
491
// Handle guaranteed forwarding phis
@@ -543,27 +534,35 @@ private struct BorrowIntroducers {
543
534
// %reborrow_2 is returned.
544
535
//
545
536
private mutating func gather( forPhi phi: Phi ,
546
- in introducers: inout Stack < Value > ,
537
+ in introducers: inout Stack < BeginBorrowValue > ,
547
538
_ cache: inout Cache ) {
548
539
// Phi cycles are skipped. They cannot contribute any new introducer.
549
540
if !cache. pendingPhis. insert ( phi. value) {
550
541
return
551
542
}
552
543
for (pred, value) in zip ( phi. predecessors, phi. incomingValues) {
544
+ switch value. ownership {
545
+ case . none:
546
+ continue
547
+ case . owned, . unowned:
548
+ fatalError ( " unexpected ownership for a guaranteed phi operand " )
549
+ case . guaranteed:
550
+ break
551
+ }
553
552
// Each phi operand requires a new introducer list and visited
554
553
// values set. These values will be remapped to successor phis
555
554
// before adding them to the caller's introducer list. It may be
556
555
// necessary to revisit a value that was already visited by the
557
556
// caller before remapping to phis.
558
- var incomingIntroducers = Stack < Value > ( context)
557
+ var incomingIntroducers = Stack < BeginBorrowValue > ( context)
559
558
defer {
560
559
incomingIntroducers. deinitialize ( )
561
560
}
562
561
BorrowIntroducers . gather ( for: value, in: & incomingIntroducers,
563
562
& cache, context)
564
563
// Map the incoming introducers to an outer-adjacent phi if one exists.
565
- push ( contentsOf: mapToPhi ( predecessor: pred,
566
- incomingValues : incomingIntroducers) ,
564
+ push ( contentsOf: mapToGuaranteedPhi ( predecessor: pred,
565
+ incomingBorrows : incomingIntroducers) ,
567
566
in: & introducers)
568
567
}
569
568
// Remove this phi from the pending set. This phi may be visited
@@ -574,13 +573,35 @@ private struct BorrowIntroducers {
574
573
}
575
574
}
576
575
577
- // Given incoming values on a predecessor path, return the
578
- // corresponding values on the successor block. Each incoming value is
576
+ // Given incoming borrows on a predecessor path, return the
577
+ // corresponding borrows on the successor block. Each incoming borrow is
579
578
// either used by a phi in the successor block, or it must dominate
580
579
// the successor block.
580
+ private func mapToGuaranteedPhi< PredecessorSequence: Sequence < BeginBorrowValue > > (
581
+ predecessor: BasicBlock , incomingBorrows: PredecessorSequence )
582
+ -> LazyMapSequence < PredecessorSequence , BeginBorrowValue > {
583
+
584
+ let branch = predecessor. terminator as! BranchInst
585
+ // Gather the new introducers for the successor block.
586
+ return incomingBorrows. lazy. map { incomingBorrow in
587
+ // Find an outer adjacent phi in the successor block.
588
+ let incomingValue = incomingBorrow. value
589
+ if let incomingOp = branch. operands. first ( where: { $0. value == incomingValue } ) {
590
+ return BeginBorrowValue ( branch. getArgument ( for: incomingOp) ) !
591
+ }
592
+ // No candidates phi are outer-adjacent phis. The incoming
593
+ // `predDef` must dominate the current guaranteed phi.
594
+ return incomingBorrow
595
+ }
596
+ }
597
+
598
+ // Given incoming values on a predecessor path, return the corresponding values on the successor block. Each incoming
599
+ // value is either used by a phi in the successor block, or it must dominate the successor block.
600
+ //
601
+ // This is Logically the same as mapToGuaranteedPhi but more efficient to simply duplicate the code.
581
602
private func mapToPhi< PredecessorSequence: Sequence < Value > > (
582
603
predecessor: BasicBlock , incomingValues: PredecessorSequence )
583
- -> LazyMapSequence < PredecessorSequence , Value > {
604
+ -> LazyMapSequence < PredecessorSequence , Value > {
584
605
585
606
let branch = predecessor. terminator as! BranchInst
586
607
// Gather the new introducers for the successor block.
@@ -612,7 +633,7 @@ private func mapToPhi<PredecessorSequence: Sequence<Value>> (
612
633
/// introducers of the outer enclosing borrow scope that contains this
613
634
/// inner scope.
614
635
///
615
- /// If `value` is a `begin_borrow`, then this returns its operand.
636
+ /// If `value` is a `begin_borrow`, then this returns its owned operand, or the introducers of its guaranteed operand.
616
637
///
617
638
/// If `value` is an owned value, a function argument, or a
618
639
/// load_borrow, then this is an empty set.
@@ -725,9 +746,18 @@ private struct EnclosingValues {
725
746
if let beginBorrow = BeginBorrowValue ( value) {
726
747
switch beginBorrow {
727
748
case let . beginBorrow( bbi) :
749
+ let outerValue = bbi. operand. value
750
+ switch outerValue. ownership {
751
+ case . none, . unowned:
752
+ return
753
+ case . owned:
754
+ push ( outerValue, in: & enclosingValues) ;
755
+ return
756
+ case . guaranteed:
757
+ break
758
+ }
728
759
// Gather the outer enclosing borrow scope.
729
- BorrowIntroducers . gather ( for: bbi. operand. value, in: & enclosingValues,
730
- & cache. borrowIntroducerCache, context)
760
+ gatherBorrows ( for: outerValue, in: & enclosingValues, & cache)
731
761
case . loadBorrow, . beginApply, . functionArgument:
732
762
// There is no enclosing value on this path.
733
763
break
@@ -736,11 +766,19 @@ private struct EnclosingValues {
736
766
}
737
767
} else {
738
768
// Handle forwarded guaranteed values.
739
- BorrowIntroducers . gather ( for: value, in: & enclosingValues,
740
- & cache. borrowIntroducerCache, context)
769
+ gatherBorrows ( for: value, in: & enclosingValues, & cache)
741
770
}
742
771
}
743
-
772
+
773
+ mutating func gatherBorrows( for value: Value , in enclosingValues: inout Stack < Value > , _ cache: inout Cache ) {
774
+ var introducers = Stack < BeginBorrowValue > ( context)
775
+ defer { introducers. deinitialize ( ) }
776
+ BorrowIntroducers . gather ( for: value, in: & introducers, & cache. borrowIntroducerCache, context)
777
+ for beginBorrow in introducers {
778
+ enclosingValues. push ( beginBorrow. value)
779
+ }
780
+ }
781
+
744
782
// Given a reborrow, find the enclosing values. Each enclosing value
745
783
// is represented by one of the following cases, which refer to the
746
784
// example below:
@@ -841,12 +879,12 @@ let borrowIntroducersTest = FunctionTest("borrow_introducers") {
841
879
let value = arguments. takeValue ( )
842
880
print ( function)
843
881
print ( " Borrow introducers for: \( value) " )
844
- var introducers = Stack < Value > ( context)
882
+ var introducers = Stack < BeginBorrowValue > ( context)
845
883
defer {
846
884
introducers. deinitialize ( )
847
885
}
848
886
gatherBorrowIntroducers ( for: value, in: & introducers, context)
849
- introducers. forEach { print ( $0) }
887
+ introducers. forEach { print ( $0. value ) }
850
888
}
851
889
852
890
let enclosingValuesTest = FunctionTest ( " enclosing_values " ) {
0 commit comments