@@ -318,7 +318,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
318
318
return . continueWalk
319
319
}
320
320
defer { useDefVisitor. deinitialize ( ) }
321
- _ = useDefVisitor. walkUp ( valueOrAddress : value)
321
+ _ = useDefVisitor. walkUp ( newLifetime : value)
322
322
assert ( !introducers. isEmpty, " missing variable introducer " )
323
323
return introducers
324
324
}
@@ -330,7 +330,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
330
330
/// Walk up lifetime dependencies to the first value associated with a variable declaration.
331
331
///
332
332
/// To start walking:
333
- /// walkUp(valueOrAddress : Value) -> WalkResult
333
+ /// walkUp(newLifetime : Value) -> WalkResult
334
334
///
335
335
/// This utility finds the value or address associated with the lvalue (variable declaration) that is passed as the
336
336
/// source of a lifetime dependent argument. If no lvalue is found, then it finds the "root" of the chain of temporary
@@ -382,10 +382,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
382
382
/// All of the dependent uses including `end_borrow %5` and `destroy_value %4` must be before the end of the dependence
383
383
/// scope: `destroy_value %parent`. In this case, the dependence parent is an owned value, so the scope is simply the
384
384
/// value's OSSA lifetime.
385
- struct VariableIntroducerUseDefWalker : ForwardingUseDefWalker {
386
- // The ForwardingUseDefWalker's context is the most recent lifetime owner.
387
- typealias PathContext = Value ?
388
-
385
+ struct VariableIntroducerUseDefWalker : LifetimeDependenceUseDefValueWalker , LifetimeDependenceUseDefAddressWalker {
389
386
let context : Context
390
387
391
388
// If the scoped value is trivial, then only the variable's lexical scope is relevant, and access scopes can be
@@ -412,128 +409,45 @@ struct VariableIntroducerUseDefWalker : ForwardingUseDefWalker {
412
409
visitedValues. deinitialize ( )
413
410
}
414
411
415
- mutating func needWalk( for value: Value , _ owner: Value ? ) -> Bool {
416
- visitedValues. insert ( value)
417
- }
418
-
419
412
mutating func introducer( _ value: Value , _ owner: Value ? ) -> WalkResult {
420
413
return visitorClosure ( value)
421
414
}
422
415
423
- mutating func walkUp( valueOrAddress: Value ) -> WalkResult {
424
- if valueOrAddress. type. isAddress {
425
- return walkUp ( address: valueOrAddress)
426
- }
427
- return walkUp ( newLifetime: valueOrAddress)
416
+ mutating func addressIntroducer( _ address: Value , access: AccessBaseAndScopes ) -> WalkResult {
417
+ return visitorClosure ( address)
418
+ }
419
+
420
+ mutating func needWalk( for value: Value , _ owner: Value ? ) -> Bool {
421
+ visitedValues. insert ( value)
428
422
}
429
- }
430
423
431
- // Helpers
432
- extension VariableIntroducerUseDefWalker {
433
424
mutating func walkUp( newLifetime: Value ) -> WalkResult {
425
+ if newLifetime. type. isAddress {
426
+ return walkUp ( address: newLifetime)
427
+ }
434
428
let newOwner = newLifetime. ownership == . owned ? newLifetime : nil
435
429
return walkUp ( value: newLifetime, newOwner)
436
430
}
437
431
432
+ /// Override to check for variable introducers: move_value, begin_value, before following
433
+ /// OwnershipTransitionInstruction.
438
434
mutating func walkUp( value: Value , _ owner: Value ? ) -> WalkResult {
439
- // Check for variable introducers: move_value, begin_value, before following OwnershipTransitionInstruction.
440
435
if let inst = value. definingInstruction, VariableScopeInstruction ( inst) != nil {
441
436
return visitorClosure ( value)
442
437
}
443
- switch value. definingInstruction {
444
- case let transition as OwnershipTransitionInstruction :
445
- return walkUp ( newLifetime: transition. operand. value)
446
- case let load as LoadInstruction :
447
- return walkUp ( address: load. address)
448
- default :
449
- break
450
- }
451
- // If the dependence chain has a phi, consider it a root. Dependence roots dominate all dependent values.
452
- if Phi ( value) != nil {
453
- return introducer ( value, owner)
454
- }
455
- // ForwardingUseDefWalker will callback to introducer() when it finds no forwarding instruction.
456
- return walkUpDefault ( forwarded: value, owner)
438
+ return walkUpDefault ( value: value, owner)
457
439
}
458
440
459
- // Handle temporary allocations and access scopes.
460
- mutating func walkUp( address: Value ) -> WalkResult {
461
- let accessBaseAndScopes = address. accessBaseWithScopes
462
- // Continue walking for some kinds of access base.
463
- switch accessBaseAndScopes. base {
464
- case . box, . global, . class, . tail, . pointer, . index, . unidentified:
465
- break
466
- case let . stack( allocStack) :
467
- if allocStack. varDecl == nil {
468
- // Ignore temporary stack locations. Their access scopes do not affect lifetime dependence.
469
- return walkUp ( stackInitializer: allocStack, at: address)
470
- }
471
- case let . argument( arg) :
472
- // Ignore access scopes for @in or @in_guaranteed arguments when all scopes are reads. Do not ignore a [read]
473
- // access of an inout argument or outer [modify]. Mutation later with the outer scope could invalidate the
474
- // borrowed state in this narrow scope. Do not ignore any mark_depedence on the address.
475
- if arg. convention. isIndirectIn && accessBaseAndScopes. isOnlyReadAccess {
476
- return introducer ( arg, nil )
477
- }
478
- // @inout arguments may be singly initialized (when no modification exists in this function), but this is not
479
- // relevant here because they require nested access scopes which can never be ignored.
480
- case let . yield( yieldedAddress) :
481
- // Ignore access scopes for @in or @in_guaranteed yields when all scopes are reads.
482
- let apply = yieldedAddress. definingInstruction as! FullApplySite
483
- if apply. convention ( of: yieldedAddress) . isIndirectIn && accessBaseAndScopes. isOnlyReadAccess {
484
- return introducer ( yieldedAddress, nil )
485
- }
486
- case . storeBorrow( let sb) :
487
- // Walk up through a store into a temporary.
488
- if accessBaseAndScopes. scopes. isEmpty,
489
- case . stack = sb. destinationOperand. value. accessBase {
490
- return walkUp ( newLifetime: sb. source)
491
- }
492
- }
493
- // Skip the access scope for unsafe[Mutable]Address. Treat it like a projection of 'self' rather than a separate
494
- // variable access.
495
- if case let . access( innerAccess) = accessBaseAndScopes. scopes. first,
496
- let addressorSelf = innerAccess. unsafeAddressorSelf {
497
- return walkUp ( valueOrAddress: addressorSelf)
498
- }
499
- // Ignore the acces scope for trivial values regardless of whether it is singly-initialized. Trivial values do not
500
- // need to be kept alive in memory and can be safely be overwritten in the same scope. Lifetime dependence only
501
- // cares that the loaded value is within the lexical scope of the trivial value's variable declaration. Rather than
502
- // skipping all access scopes, call 'walkUp' on each nested access in case one of them needs to redirect the walk,
503
- // as required for 'access.unsafeAddressorSelf'.
504
- if isTrivialScope {
505
- switch accessBaseAndScopes. scopes. first {
506
- case . none, . base:
507
- break
508
- case let . access( beginAccess) :
509
- return walkUp ( address: beginAccess. address)
510
- case let . dependence( markDep) :
511
- return walkUp ( address: markDep. value)
512
- }
513
- }
514
- return introducer ( accessBaseAndScopes. enclosingAccess. address ?? address, nil )
515
- }
516
-
517
- // Handle singly-initialized temporary stack locations.
518
- mutating func walkUp( stackInitializer allocStack: AllocStackInst , at address: Value ) -> WalkResult {
519
- guard let initializer = allocStack. accessBase. findSingleInitializer ( context) else {
520
- return introducer ( address, nil )
521
- }
522
- if case let . store( store, _) = initializer {
523
- switch store {
524
- case let store as StoringInstruction :
525
- return walkUp ( newLifetime: store. source)
526
- case let srcDestInst as SourceDestAddrInstruction :
527
- return walkUp ( address: srcDestInst. destination)
528
- case let apply as FullApplySite :
529
- if let f = apply. referencedFunction, f. isConvertPointerToPointerArgument {
530
- return walkUp ( address: apply. parameterOperands [ 0 ] . value)
531
- }
532
- default :
533
- break
441
+ /// Override to check for on-stack variables before following an initializer.
442
+ mutating func walkUp( address: Value , access: AccessBaseAndScopes ) -> WalkResult {
443
+ // Check for stack locations that correspond to an lvalue.
444
+ if case let . stack( allocStack) = access. base {
445
+ if allocStack. varDecl != nil {
446
+ // Report this variable's innermmost access scope.
447
+ return addressIntroducer ( access. enclosingAccess. address ?? address, access: access)
534
448
}
535
449
}
536
- return introducer ( address, nil )
450
+ return walkUpDefault ( address: address , access : access )
537
451
}
538
452
}
539
453
0 commit comments