@@ -365,59 +365,70 @@ extension ScopeExtension {
365365private struct ExtendableScope {
366366 enum Introducer {
367367 case scoped( ScopedInstruction )
368+ case stack( Instruction )
368369 case owned( Value )
369370 }
370371
372+ // scope.allocStackInstruction is always valid for Introducer.allocStack and is valid for Introducer.scoped when
373+ // ScopedInstruction is a store_borrow.
371374 let scope : LifetimeDependence . Scope
372375 let introducer : Introducer
373376
374377 var firstInstruction : Instruction {
375378 switch introducer {
376379 case let . scoped( scopedInst) :
377380 return scopedInst. instruction
381+ case let . stack( initializingStore) :
382+ return initializingStore
378383 case let . owned( value) :
379384 if let definingInst = value. definingInstructionOrTerminator {
380385 return definingInst
381386 }
382387 return value. parentBlock. instructions. first!
383388 }
384389 }
390+
385391 var endInstructions : LazyMapSequence < LazyFilterSequence < UseList > , Instruction > {
386392 switch introducer {
387393 case let . scoped( scopedInst) :
388394 return scopedInst. endOperands. users
395+ case . stack:
396+ // For alloc_stack without a store-borrow scope, include the deallocs in its scope to ensure that we never shorten
397+ // the original allocation. It's possible that some other use depends on the address.
398+ //
399+ // Same as 'AllocStackInst.deallocations' but as an Instruction list...
400+ return scope. allocStackInstruction!. uses. lazy. filter
401+ { $0. instruction is DeallocStackInst } . lazy. map { $0. instruction }
402+
389403 case let . owned( value) :
390404 return value. uses. endingLifetime. users
391405 }
392406 }
393407
394408 var deallocs : LazyMapSequence < LazyFilterSequence < UseList > , DeallocStackInst > ? {
395- switch self . scope {
396- case let . initialized( initializer) :
397- switch initializer {
398- case let . store( initializingStore: store, initialAddress: _) :
399- if let sb = store as? StoreBorrowInst {
400- return sb. allocStack. uses. filterUsers ( ofType: DeallocStackInst . self)
401- }
402- default :
403- break
404- }
405- default :
406- break
409+ guard let allocStack = scope. allocStackInstruction else {
410+ return nil
407411 }
408- return nil
412+ return allocStack . uses . users ( ofType : DeallocStackInst . self )
409413 }
410414
411- // Allow scope extension as long as `beginInst` is scoped instruction and does not define a variable scope.
415+ // Allow scope extension as long as `beginInst` does not define a variable scope and is either a scoped instruction or
416+ // a store to a singly-initialized temporary.
412417 init ? ( _ scope: LifetimeDependence . Scope , beginInst: Instruction ? ) {
413418 self . scope = scope
414419 guard let beginInst = beginInst, VariableScopeInstruction ( beginInst) == nil else {
415420 return nil
416421 }
417- guard let scopedInst = beginInst as? ScopedInstruction else {
418- return nil
422+ // Check for "scoped" store_borrow extension before checking allocStackInstruction.
423+ if let scopedInst = beginInst as? ScopedInstruction {
424+ self . introducer = . scoped( scopedInst)
425+ return
419426 }
420- self . introducer = . scoped( scopedInst)
427+ if scope. allocStackInstruction != nil {
428+ self . introducer = . stack( beginInst)
429+ return
430+ }
431+ return nil
421432 }
422433
423434 // Allow extension of owned temporaries that
@@ -484,11 +495,14 @@ extension ScopeExtension {
484495 switch initializer {
485496 case let . store( initializingStore: store, initialAddress: _) :
486497 if let sb = store as? StoreBorrowInst {
487- // Follow the source for nested scopes .
498+ // Follow the stored value since the owner of the borrowed value needs to cover this allocation .
488499 gatherExtensions ( valueOrAddress: sb. source)
489- scopes. push ( ExtendableScope ( scope, beginInst: sb) !)
500+ }
501+ if scope. allocStackInstruction != nil {
502+ scopes. push ( ExtendableScope ( scope, beginInst: store) !)
490503 return
491504 }
505+ break
492506 case . argument, . yield:
493507 // TODO: extend indirectly yielded scopes.
494508 break
@@ -816,13 +830,10 @@ extension ExtendableScope {
816830 switch initializer {
817831 case . argument, . yield:
818832 // A yield is already considered nested within the coroutine.
819- break
820- case let . store( initializingStore, _) :
821- if initializingStore is StoreBorrowInst {
822- return true
823- }
833+ return true
834+ case . store:
835+ return self . scope. allocStackInstruction != nil
824836 }
825- return true
826837 default :
827838 // non-yield scopes can always be ended at any point.
828839 return true
@@ -868,6 +879,9 @@ extension ExtendableScope {
868879 var endsToErase = [ Instruction] ( )
869880 if let deallocs = self . deallocs {
870881 endsToErase. append ( contentsOf: deallocs. map { $0 } )
882+ for dealloc in deallocs {
883+ unreusedEnds. erase ( dealloc)
884+ }
871885 }
872886
873887 for end in range. ends {
@@ -920,10 +934,12 @@ extension ExtendableScope {
920934 case let . initialized( initializer) :
921935 switch initializer {
922936 case let . store( initializingStore: store, initialAddress: _) :
937+ var endInsts = SingleInlineArray < Instruction > ( )
923938 if let sb = store as? StoreBorrowInst {
924- var endInsts = SingleInlineArray < Instruction > ( )
925939 endInsts. append ( builder. createEndBorrow ( of: sb) )
926- endInsts. append ( builder. createDeallocStack ( sb. allocStack) )
940+ }
941+ if let allocStack = self . scope. allocStackInstruction {
942+ endInsts. append ( builder. createDeallocStack ( allocStack) )
927943 return endInsts
928944 }
929945 break
@@ -932,14 +948,14 @@ extension ExtendableScope {
932948 break
933949 }
934950 case let . owned( value) :
935- return builder. createDestroyValue ( operand: value)
951+ return SingleInlineArray ( element : builder. createDestroyValue ( operand: value) )
936952 case let . local( varInst) :
937953 switch varInst {
938954 case let . beginBorrow( beginBorrow) :
939955 // FIXME: we may need to rewrite the dealloc_stack.
940- return builder. createEndBorrow ( of: beginBorrow)
956+ return SingleInlineArray ( element : builder. createEndBorrow ( of: beginBorrow) )
941957 case let . moveValue( moveValue) :
942- return builder. createDestroyValue ( operand: moveValue)
958+ return SingleInlineArray ( element : builder. createDestroyValue ( operand: moveValue) )
943959 }
944960 default :
945961 break
0 commit comments