@@ -17,9 +17,12 @@ import SIL
17
17
/// If this instruction produces a borrowed value, then
18
18
/// BeginBorrowValue(resultOf: self) != nil.
19
19
///
20
- /// This does not include instructions like Apply and TryApply that
20
+ /// This does not include instructions like `apply` and `try_apply` that
21
21
/// instantaneously borrow a value from the caller.
22
22
///
23
+ /// This does not include `load_borrow` because it borrows a memory
24
+ /// location, not the value of its operand.
25
+ ///
23
26
/// Note: This must handle all instructions with a .borrow operand ownership.
24
27
///
25
28
/// TODO: replace BorrowIntroducingInstruction
@@ -57,11 +60,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable {
57
60
}
58
61
}
59
62
60
- typealias ScopeEndingOperands =
61
- LazyMapSequence < LazyFilterSequence < LazyMapSequence < UseList , Operand ? > > ,
62
- Operand >
63
-
64
- /// The operands that end the local borrow scope.
63
+ /// Visit the operands that end the local borrow scope.
65
64
///
66
65
/// Note: When this instruction's result is BeginBorrowValue the
67
66
/// scopeEndingOperand may include reborrows. To find all uses that
@@ -76,28 +75,42 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable {
76
75
/// that scope ending instructions exist on all paths. These
77
76
/// instructions should be complete after SILGen and never cloned to
78
77
/// produce phis.
79
- var scopeEndingOperands : ScopeEndingOperands {
80
- if let value = instruction as? SingleValueInstruction ,
81
- BeginBorrowValue ( value ) != nil {
82
- return value . uses . lazy . compactMap { $0 . endsLifetime ? $0 : nil }
83
- }
84
- switch instruction {
85
- case let sbi as StoreBorrowInst :
86
- return sbi . uses . lazy . compactMap {
87
- $0 . instruction is EndBorrowInst ? $0 : nil
78
+ func visitScopeEndingOperands ( _ context : Context ,
79
+ visitor : @escaping ( Operand ) -> WalkResult )
80
+ -> WalkResult {
81
+ switch self {
82
+ case . beginBorrow , . storeBorrow :
83
+ let svi = instruction as! SingleValueInstruction
84
+ return svi . uses . walk {
85
+ if $0 . instruction is EndBorrowInst { return visitor ( $0 ) }
86
+ return . continueWalk
88
87
}
89
- case let bai as BeginApplyInst :
90
- return bai. token. uses. lazy. compactMap { $0 }
91
- case let builtin as BuiltinInst :
92
- return builtin. uses. lazy. compactMap {
88
+ case . beginApply( let bai) :
89
+ return bai. token. uses. walk { return visitor ( $0) }
90
+ case . partialApply( let pai) :
91
+ return visitForwardedUses ( introducer: pai, context) {
92
+ switch $0 {
93
+ case let . operand( operand) :
94
+ if operand. endsLifetime {
95
+ return visitor ( operand)
96
+ }
97
+ return . continueWalk
98
+ case let . deadValue( _, operand) :
99
+ if let operand = operand {
100
+ assert ( !operand. endsLifetime,
101
+ " a dead forwarding instruction cannot end a lifetime " )
102
+ }
103
+ return . continueWalk
104
+ }
105
+ }
106
+ case . startAsyncLet( let builtin) :
107
+ return builtin. uses. walk {
93
108
if let builtinUser = $0. instruction as? BuiltinInst ,
94
109
builtinUser. id == . EndAsyncLetLifetime {
95
- return $0
110
+ return visitor ( $0 )
96
111
}
97
- return nil
112
+ return . continueWalk
98
113
}
99
- default :
100
- fatalError ( " unknown BorrowingInstruction " )
101
114
}
102
115
}
103
116
@@ -176,17 +189,25 @@ enum BeginBorrowValue {
176
189
}
177
190
178
191
var hasLocalScope : Bool {
179
- return !( value is FunctionArgument )
192
+ switch self {
193
+ case . beginBorrow, . loadBorrow, . beginApply, . reborrow:
194
+ return true
195
+ case . functionArgument:
196
+ return false
197
+ }
180
198
}
181
199
182
- // non-nil if hasLocalScope is true
200
+ // Return the value borrowed by begin_borrow or address borrowed by
201
+ // load_borrow.
202
+ //
203
+ // Return nil for begin_apply and reborrow, which need special handling.
183
204
var baseOperand : Operand ? {
184
- switch value {
185
- case let beginBorrow as BeginBorrowInst :
186
- return beginBorrow. operand
187
- case let loadBorrow as LoadBorrowInst :
205
+ switch self {
206
+ case let . beginBorrow( beginBorrow ) :
207
+ return beginBorrow. operand
208
+ case let . loadBorrow( loadBorrow ) :
188
209
return loadBorrow. operand
189
- default :
210
+ case . beginApply , . functionArgument , . reborrow :
190
211
return nil
191
212
}
192
213
}
@@ -203,9 +224,9 @@ enum BeginBorrowValue {
203
224
}
204
225
}
205
226
206
- /// Find the enclosing borrow introducers for `value`. This gives you
207
- /// a set of OSSA lifetimes that directly include `value`. If `value`
208
- /// is owned, or introduces a borrow scope, then `value` is the single
227
+ /// Find the borrow introducers for `value`. This gives you a set of
228
+ /// OSSA lifetimes that directly include `value`. If `value` is owned,
229
+ /// or introduces a borrow scope, then `value` is the single
209
230
/// introducer for itself.
210
231
///
211
232
/// Example: // introducers:
@@ -217,14 +238,15 @@ enum BeginBorrowValue {
217
238
/// %first = struct_extract %pair // %borrow0, %1
218
239
/// %field = ref_element_addr %first // (none)
219
240
/// %load = load_borrow %field : $*C // %load
220
- func gather( borrowIntroducers: inout Stack < Value > , for value: Value ,
221
- _ context: Context ) {
241
+ func gatherBorrowIntroducers( for value: Value ,
242
+ in borrowIntroducers: inout Stack < Value > ,
243
+ _ context: Context ) {
222
244
223
245
// Cache introducers across multiple instances of BorrowIntroducers.
224
246
var cache = BorrowIntroducers . Cache ( context)
225
247
defer { cache. deinitialize ( ) }
226
- BorrowIntroducers . gather ( introducers : & borrowIntroducers,
227
- forValue : value , & cache, context)
248
+ BorrowIntroducers . gather ( for : value , in : & borrowIntroducers,
249
+ & cache, context)
228
250
}
229
251
230
252
private struct BorrowIntroducers {
@@ -254,10 +276,10 @@ private struct BorrowIntroducers {
254
276
// introducer set to avoid adding duplicates.
255
277
var visitedIntroducers : Set < HashableValue > = Set ( )
256
278
257
- static func gather( introducers : inout Stack < Value > , forValue value : Value ,
258
- _ cache: inout Cache , _ context: Context ) {
279
+ static func gather( for value : Value , in introducers : inout Stack < Value > ,
280
+ _ cache: inout Cache , _ context: Context ) {
259
281
var borrowIntroducers = BorrowIntroducers ( context: context)
260
- borrowIntroducers. gather ( introducers : & introducers , forValue : value , & cache)
282
+ borrowIntroducers. gather ( for : value , in : & introducers , & cache)
261
283
}
262
284
263
285
private mutating func push( _ introducer: Value ,
@@ -280,8 +302,9 @@ private struct BorrowIntroducers {
280
302
// - `value` introduces a borrow scope (begin_borrow, load_borrow, reborrow)
281
303
//
282
304
// Otherwise recurse up the use-def chain to find all introducers.
283
- private mutating func gather( introducers: inout Stack < Value > ,
284
- forValue value: Value , _ cache: inout Cache ) {
305
+ private mutating func gather( for value: Value ,
306
+ in introducers: inout Stack < Value > ,
307
+ _ cache: inout Cache ) {
285
308
// Check if this value's introducers have already been added to
286
309
// 'introducers' to avoid duplicates and avoid exponential
287
310
// recursion on aggregates.
@@ -291,7 +314,7 @@ private struct BorrowIntroducers {
291
314
}
292
315
introducers. withMarker (
293
316
pushElements: { introducers in
294
- gatherUncached ( introducers : & introducers , forValue : value , & cache)
317
+ gatherUncached ( for : value , in : & introducers , & cache)
295
318
} ,
296
319
withNewElements: { newIntroducers in
297
320
{ cachedIntroducers in
@@ -300,8 +323,9 @@ private struct BorrowIntroducers {
300
323
} )
301
324
}
302
325
303
- private mutating func gatherUncached( introducers: inout Stack < Value > ,
304
- forValue value: Value , _ cache: inout Cache ) {
326
+ private mutating func gatherUncached( for value: Value ,
327
+ in introducers: inout Stack < Value > ,
328
+ _ cache: inout Cache ) {
305
329
switch value. ownership {
306
330
case . none, . unowned:
307
331
return
@@ -321,7 +345,7 @@ private struct BorrowIntroducers {
321
345
}
322
346
// Handle guaranteed forwarding phis
323
347
if let phi = Phi ( value) {
324
- gather ( introducers : & introducers , forPhi : phi , & cache)
348
+ gather ( forPhi : phi , in : & introducers , & cache)
325
349
return
326
350
}
327
351
// Recurse through guaranteed forwarding non-phi instructions.
@@ -330,7 +354,7 @@ private struct BorrowIntroducers {
330
354
}
331
355
for operand in forwardingInst. forwardedOperands {
332
356
if operand. value. ownership == . guaranteed {
333
- gather ( introducers : & introducers , forValue : operand . value , & cache) ;
357
+ gather ( for : operand . value , in : & introducers , & cache) ;
334
358
}
335
359
}
336
360
}
@@ -351,7 +375,7 @@ private struct BorrowIntroducers {
351
375
// two(%reborrow_2 : @guaranteed, %forward_2 : @guaranteed)
352
376
// end_borrow %reborrow_2
353
377
//
354
- // Calling `recursivelyFindForwardingPhiIntroducers( %forward_2)`
378
+ // Calling `gatherPhiIntroducers(for: %forward_2)`
355
379
// recursively computes these introducers:
356
380
//
357
381
// %field is the only value incoming to %forward_2.
@@ -364,8 +388,9 @@ private struct BorrowIntroducers {
364
388
//
365
389
// %reborrow_2 is returned.
366
390
//
367
- private mutating func gather( introducers: inout Stack < Value > , forPhi phi: Phi ,
368
- _ cache: inout Cache ) {
391
+ private mutating func gather( forPhi phi: Phi ,
392
+ in introducers: inout Stack < Value > ,
393
+ _ cache: inout Cache ) {
369
394
// Phi cycles are skipped. They cannot contribute any new introducer.
370
395
if !cache. pendingPhis. insert ( phi. value) {
371
396
return
@@ -380,8 +405,8 @@ private struct BorrowIntroducers {
380
405
defer {
381
406
incomingIntroducers. deinitialize ( )
382
407
}
383
- BorrowIntroducers . gather ( introducers : & incomingIntroducers,
384
- forValue : value , & cache, context)
408
+ BorrowIntroducers . gather ( for : value , in : & incomingIntroducers,
409
+ & cache, context)
385
410
// Map the incoming introducers to an outer-adjacent phi if one exists.
386
411
push ( contentsOf: mapToPhi ( predecessor: pred,
387
412
incomingValues: incomingIntroducers) ,
@@ -450,25 +475,26 @@ private func mapToPhi<PredecessorSequence: Sequence<Value>> (
450
475
/// bb1(%outerReborrow : @guaranteed, // %0
451
476
/// %innerReborrow : @guaranteed) // %outerReborrow
452
477
///
453
- func gather( enclosingValues: inout Stack < Value > ,
454
- for value: Value , _ context: some Context ) {
478
+ func gatherEnclosingValues( for value: Value ,
479
+ in enclosingValues: inout Stack < Value > ,
480
+ _ context: some Context ) {
455
481
456
482
var gatherValues = EnclosingValues ( context)
457
483
defer { gatherValues. deinitialize ( ) }
458
484
var cache = BorrowIntroducers . Cache ( context)
459
485
defer { cache. deinitialize ( ) }
460
- gatherValues. gather ( enclosingValues: & enclosingValues, forValue: value,
461
- & cache)
486
+ gatherValues. gather ( for: value, in: & enclosingValues, & cache)
462
487
}
463
488
464
489
/// Find inner adjacent phis in the same block as `enclosingPhi`.
465
490
/// These keep the enclosing (outer adjacent) phi alive.
466
- func gather( innerAdjacentPhis: inout Stack < Phi > , for enclosingPhi: Phi ,
467
- _ context: Context ) {
491
+ func gatherInnerAdjacentPhis( for enclosingPhi: Phi ,
492
+ in innerAdjacentPhis: inout Stack < Phi > ,
493
+ _ context: Context ) {
468
494
for candidatePhi in enclosingPhi. successor. arguments {
469
495
var enclosingValues = Stack < Value > ( context)
470
496
defer { enclosingValues. deinitialize ( ) }
471
- gather ( enclosingValues : & enclosingValues , for : candidatePhi , context)
497
+ gatherEnclosingValues ( for : candidatePhi , in : & enclosingValues , context)
472
498
if enclosingValues. contains ( where: { $0 == enclosingPhi. value} ) {
473
499
innerAdjacentPhis. push ( Phi ( candidatePhi) !)
474
500
}
@@ -489,28 +515,28 @@ private struct EnclosingValues {
489
515
visitedReborrows. deinitialize ( )
490
516
}
491
517
492
- mutating func gather( enclosingValues: inout Stack < Value > ,
493
- forValue value: Value , _ cache: inout BorrowIntroducers . Cache ) {
518
+ mutating func gather( for value: Value ,
519
+ in enclosingValues: inout Stack < Value > ,
520
+ _ cache: inout BorrowIntroducers . Cache ) {
494
521
if value is Undef || value. ownership != . guaranteed {
495
522
return
496
523
}
497
- if BeginBorrowValue ( value) != nil {
498
- switch value {
499
- case let beginBorrow as BeginBorrowInst :
524
+ if let beginBorrow = BeginBorrowValue ( value) {
525
+ switch beginBorrow {
526
+ case let . beginBorrow( bbi ) :
500
527
// Gather the outer enclosing borrow scope.
501
- BorrowIntroducers . gather ( introducers : & enclosingValues,
502
- forValue : beginBorrow . operand . value , & cache, context)
503
- case is LoadBorrowInst , is FunctionArgument :
528
+ BorrowIntroducers . gather ( for : bbi . operand . value , in : & enclosingValues,
529
+ & cache, context)
530
+ case . loadBorrow , . beginApply , . functionArgument :
504
531
// There is no enclosing value on this path.
505
532
break
506
- default :
507
- gather ( enclosingValues: & enclosingValues, forReborrow: Phi ( value) !,
508
- & cache)
533
+ case let . reborrow( reborrow) :
534
+ gather ( forReborrow: reborrow, in: & enclosingValues, & cache)
509
535
}
510
536
} else {
511
537
// Handle forwarded guaranteed values.
512
- BorrowIntroducers . gather ( introducers : & enclosingValues , forValue : value ,
513
- & cache, context)
538
+ BorrowIntroducers . gather ( for : value , in : & enclosingValues ,
539
+ & cache, context)
514
540
}
515
541
}
516
542
@@ -545,8 +571,9 @@ private struct EnclosingValues {
545
571
// end_borrow %reborrow_3
546
572
// destroy_value %phi_3
547
573
//
548
- // gather(%reborrow_3) finds %phi_3 by computing enclosing defs in this order
549
- // (inner -> outer):
574
+ // gather(forReborrow: %reborrow_3) finds %phi_3 by computing
575
+ // enclosing defs in this order
576
+ // (inner -> outer):
550
577
//
551
578
// %reborrow_1 -> %value
552
579
// %reborrow_2 -> %phi_2
@@ -561,10 +588,11 @@ private struct EnclosingValues {
561
588
// br one(%outerBorrowA, %borrow)
562
589
// one(%outerReborrow : @guaranteed, %reborrow : @guaranteed)
563
590
//
564
- // gather(%reborrow) finds (%outerReborrow, %outerBorrowB).
591
+ // gather(forReborrow: %reborrow) finds (%outerReborrow, %outerBorrowB).
565
592
//
566
- private mutating func gather( enclosingValues: inout Stack < Value > ,
567
- forReborrow reborrow: Phi , _ cache: inout BorrowIntroducers . Cache ) {
593
+ private mutating func gather( forReborrow reborrow: Phi ,
594
+ in enclosingValues: inout Stack < Value > ,
595
+ _ cache: inout BorrowIntroducers . Cache ) {
568
596
569
597
guard visitedReborrows. insert ( reborrow. value) else { return }
570
598
@@ -580,8 +608,8 @@ private struct EnclosingValues {
580
608
defer {
581
609
incomingEnclosingValues. deinitialize ( )
582
610
}
583
- gather ( enclosingValues : & incomingEnclosingValues , forValue : incomingValue ,
584
- & cache)
611
+ gatherEnclosingValues ( for : incomingValue , in : & incomingEnclosingValues ,
612
+ & cache)
585
613
mapToPhi ( predecessor: pred,
586
614
incomingValues: incomingEnclosingValues) . forEach {
587
615
if pushedEnclosingValues. insert ( $0) {
@@ -601,7 +629,7 @@ let borrowIntroducersTest = FunctionTest("borrow_introducers") {
601
629
defer {
602
630
introducers. deinitialize ( )
603
631
}
604
- gather ( borrowIntroducers : & introducers , for : value , context)
632
+ gatherBorrowIntroducers ( for : value , in : & introducers , context)
605
633
introducers. forEach { print ( $0) }
606
634
}
607
635
@@ -614,6 +642,6 @@ let enclosingValuesTest = FunctionTest("enclosing_values") {
614
642
defer {
615
643
enclosing. deinitialize ( )
616
644
}
617
- gather ( enclosingValues : & enclosing , for : value , context)
645
+ gatherEnclosingValues ( for : value , in : & enclosing , context)
618
646
enclosing. forEach { print ( $0) }
619
647
}
0 commit comments