@@ -318,7 +318,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
318318 return . continueWalk
319319 }
320320 defer { useDefVisitor. deinitialize ( ) }
321- _ = useDefVisitor. walkUp ( valueOrAddress : value)
321+ _ = useDefVisitor. walkUp ( newLifetime : value)
322322 assert ( !introducers. isEmpty, " missing variable introducer " )
323323 return introducers
324324}
@@ -330,7 +330,7 @@ func gatherVariableIntroducers(for value: Value, _ context: Context)
330330/// Walk up lifetime dependencies to the first value associated with a variable declaration.
331331///
332332/// To start walking:
333- /// walkUp(valueOrAddress : Value) -> WalkResult
333+ /// walkUp(newLifetime : Value) -> WalkResult
334334///
335335/// This utility finds the value or address associated with the lvalue (variable declaration) that is passed as the
336336/// 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)
382382/// All of the dependent uses including `end_borrow %5` and `destroy_value %4` must be before the end of the dependence
383383/// scope: `destroy_value %parent`. In this case, the dependence parent is an owned value, so the scope is simply the
384384/// 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 {
389386 let context : Context
390387
391388 // 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 {
412409 visitedValues. deinitialize ( )
413410 }
414411
415- mutating func needWalk( for value: Value , _ owner: Value ? ) -> Bool {
416- visitedValues. insert ( value)
417- }
418-
419412 mutating func introducer( _ value: Value , _ owner: Value ? ) -> WalkResult {
420413 return visitorClosure ( value)
421414 }
422415
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)
428422 }
429- }
430423
431- // Helpers
432- extension VariableIntroducerUseDefWalker {
433424 mutating func walkUp( newLifetime: Value ) -> WalkResult {
425+ if newLifetime. type. isAddress {
426+ return walkUp ( address: newLifetime)
427+ }
434428 let newOwner = newLifetime. ownership == . owned ? newLifetime : nil
435429 return walkUp ( value: newLifetime, newOwner)
436430 }
437431
432+ /// Override to check for variable introducers: move_value, begin_value, before following
433+ /// OwnershipTransitionInstruction.
438434 mutating func walkUp( value: Value , _ owner: Value ? ) -> WalkResult {
439- // Check for variable introducers: move_value, begin_value, before following OwnershipTransitionInstruction.
440435 if let inst = value. definingInstruction, VariableScopeInstruction ( inst) != nil {
441436 return visitorClosure ( value)
442437 }
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)
457439 }
458440
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)
534448 }
535449 }
536- return introducer ( address, nil )
450+ return walkUpDefault ( address: address , access : access )
537451 }
538452}
539453
0 commit comments