@@ -104,6 +104,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
104
104
/// A lifetime dependence identifies its parent value, the kind of
105
105
/// scope that the parent value represents, and a dependent value.
106
106
struct LifetimeDependence : CustomStringConvertible {
107
+ // TODO: handle trivial values based on variable binding
107
108
enum Scope : CustomStringConvertible {
108
109
/// A guaranteed or inout argument whose scope is provided by the caller
109
110
/// and covers the entire function and any dependent results or yields.
@@ -115,7 +116,7 @@ struct LifetimeDependence : CustomStringConvertible {
115
116
/// An owned value whose OSSA lifetime encloses nonescapable values
116
117
case owned( Value )
117
118
/// An borrowed value whose OSSA lifetime encloses nonescapable values
118
- case borrowed( Value )
119
+ case borrowed( BeginBorrowValue )
119
120
/// Singly-initialized addressable storage (likely for an
120
121
/// immutable address-only value). The lifetime extends until the
121
122
/// memory is destroyed. e.g. A value produced by an @in
@@ -127,7 +128,8 @@ struct LifetimeDependence : CustomStringConvertible {
127
128
/// If `initializingStore` is nil, then the `initialAddress` is
128
129
/// initialized on function entry.
129
130
case initialized( initialAddress: Value , initializingStore: Instruction ? )
130
- // TODO: make .unknown a SIL Verification error
131
+ // TODO: Add SIL verification that no mark_depedence [unresolved] has an unknown LifetimeDependence.
132
+ // This currently requires stack allocations to be singly initialized.
131
133
case unknown( Value )
132
134
133
135
var parentValue : Value {
@@ -136,7 +138,7 @@ struct LifetimeDependence : CustomStringConvertible {
136
138
case let . access( beginAccess) : return beginAccess
137
139
case let . yield( value) : return value
138
140
case let . owned( value) : return value
139
- case let . borrowed( value ) : return value
141
+ case let . borrowed( beginBorrow ) : return beginBorrow . value
140
142
case let . initialized( initialAddress, _) : return initialAddress
141
143
case let . unknown( value) : return value
142
144
}
@@ -152,8 +154,8 @@ struct LifetimeDependence : CustomStringConvertible {
152
154
precondition ( value. definingInstruction is BeginApplyInst )
153
155
case let . owned( value) :
154
156
precondition ( value. ownership == . owned)
155
- case let . borrowed( value ) :
156
- precondition ( value. ownership == . guaranteed)
157
+ case let . borrowed( beginBorrow ) :
158
+ precondition ( beginBorrow . value. ownership == . guaranteed)
157
159
case let . initialized( initialAddress, initializingStore) :
158
160
precondition ( initialAddress. type. isAddress, " expected an address " )
159
161
precondition ( initialAddress is AllocStackInst
@@ -236,8 +238,7 @@ extension LifetimeDependence {
236
238
/// For any LifetimeDependence constructed from a mark_dependence, its `dependentValue` will be the result of the
237
239
/// mark_dependence.
238
240
///
239
- /// TODO: Add SIL verification that all mark_depedence [unresolved]
240
- /// have a valid LifetimeDependence.
241
+ /// Returns 'nil' for dependence on a trivial value.
241
242
init ? ( _ markDep: MarkDependenceInst , _ context: some Context ) {
242
243
switch markDep. dependenceKind {
243
244
case . Unresolved, . NonEscaping:
@@ -286,16 +287,15 @@ private extension Value {
286
287
}
287
288
288
289
extension LifetimeDependence . Scope {
289
- /// Construct a lifetime dependence scope from the base value that
290
- /// other values depend on. This derives the kind of dependence
291
- /// scope and its parentValue from `base`.
290
+ /// Construct a lifetime dependence scope from the base value that other values depend on. This derives the kind of
291
+ /// dependence scope and its parentValue from `base`.
292
292
///
293
- /// `base` represents the OSSA lifetime that the dependent value
294
- /// must be used within . If `base` is owned , then it directly
295
- /// defines the parent lifetime. If `base` is guaranteed, then it
296
- /// must have a single borrow introducer, which defines the parent
297
- /// lifetime. `base` must not be derived from a guaranteed phi or
298
- /// forwarded (via struct/tuple) from multiple guaranteed values .
293
+ /// `base` represents the OSSA lifetime that the dependent value must be used within. If `base` is owned, then it
294
+ /// directly defines the parent lifetime . If `base` is guaranteed , then it must have a single borrow introducer, which
295
+ /// defines the parent lifetime. `base` must not be derived from a guaranteed phi or forwarded (via struct/tuple) from
296
+ /// multiple guaranteed values.
297
+ ///
298
+ /// Returns 'nil' for dependence on a trivial value .
299
299
init ? ( base: Value , _ context: some Context ) {
300
300
if base. type. isAddress {
301
301
guard let scope = Self ( address: base, context) else {
@@ -321,6 +321,7 @@ extension LifetimeDependence.Scope {
321
321
}
322
322
}
323
323
324
+ /// Returns 'nil' for dependence on a trivial value.
324
325
private init ? ( address: Value , _ context: some Context ) {
325
326
switch address. enclosingAccessScope {
326
327
case let . scope( access) :
@@ -333,6 +334,7 @@ extension LifetimeDependence.Scope {
333
334
}
334
335
}
335
336
337
+ /// Returns 'nil' for dependence on a trivial value.
336
338
init ? ( accessBase: AccessBase , address: Value , _ context: some Context ) {
337
339
switch accessBase {
338
340
case let . box( projectBox) :
@@ -342,10 +344,7 @@ extension LifetimeDependence.Scope {
342
344
}
343
345
self = scope
344
346
case let . stack( allocStack) :
345
- guard let scope = Self ( allocation: allocStack, context) else {
346
- return nil
347
- }
348
- self = scope
347
+ self = Self ( allocation: allocStack, context)
349
348
case . global:
350
349
self = . unknown( address)
351
350
case . class, . tail:
@@ -378,6 +377,7 @@ extension LifetimeDependence.Scope {
378
377
}
379
378
}
380
379
380
+ /// Returns 'nil' for dependence on a trivial value.
381
381
private init ? ( guaranteed base: Value , _ context: some Context ) {
382
382
// If introducers is empty, then the dependence is on a trivial value, so
383
383
// there is no dependence scope.
@@ -390,7 +390,7 @@ extension LifetimeDependence.Scope {
390
390
" guaranteed phis not allowed when diagnosing lifetime dependence " )
391
391
switch beginBorrow {
392
392
case . beginBorrow, . loadBorrow:
393
- self = . borrowed( beginBorrow. value )
393
+ self = . borrowed( beginBorrow)
394
394
case let . beginApply( value) :
395
395
self = . yield( value)
396
396
case let . functionArgument( arg) :
@@ -410,12 +410,33 @@ extension LifetimeDependence.Scope {
410
410
self = . yield( result)
411
411
}
412
412
413
- private init ? ( allocation: AllocStackInst , _ context: Context ) {
413
+ private init ( allocation: AllocStackInst , _ context: Context ) {
414
414
if let initializer = allocation. accessBase. findSingleInitializer ( context) {
415
415
self = . initialized( initialAddress: initializer. initialAddress,
416
416
initializingStore: initializer. initializingStore)
417
+ return
418
+ }
419
+ self = . unknown( allocation)
420
+ }
421
+ }
422
+
423
+ extension LifetimeDependence . Scope {
424
+ /// Ignore "irrelevent" borrow scopes: load_borrow or begin_borrow without [var_decl]
425
+ func ignoreBorrowScope( _ context: some Context ) -> LifetimeDependence . Scope ? {
426
+ guard case let . borrowed( beginBorrowVal) = self else {
427
+ return self
428
+ }
429
+ switch beginBorrowVal {
430
+ case let . beginBorrow( bb) :
431
+ if bb. isFromVarDecl {
432
+ return self
433
+ }
434
+ return LifetimeDependence . Scope ( base: bb. borrowedValue, context) ? . ignoreBorrowScope ( context)
435
+ case let . loadBorrow( lb) :
436
+ return LifetimeDependence . Scope ( base: lb. address, context)
437
+ default :
438
+ fatalError ( " Scope.borrowed must begin begin_borrow or load_borrow " )
417
439
}
418
- return nil
419
440
}
420
441
}
421
442
@@ -448,8 +469,8 @@ extension LifetimeDependence.Scope {
448
469
// how would we ensure that the borrowed mark_dependence value
449
470
// is within this value's OSSA lifetime?
450
471
return computeLinearLiveness ( for: value, context)
451
- case let . borrowed( value ) :
452
- return computeLinearLiveness ( for: value, context)
472
+ case let . borrowed( beginBorrow ) :
473
+ return computeLinearLiveness ( for: beginBorrow . value, context)
453
474
case let . initialized( initialAddress, initializingStore) :
454
475
return LifetimeDependence . Scope. computeInitializedRange (
455
476
initialAddress: initialAddress, initializingStore: initializingStore,
0 commit comments