@@ -365,59 +365,70 @@ extension ScopeExtension {
365
365
private struct ExtendableScope {
366
366
enum Introducer {
367
367
case scoped( ScopedInstruction )
368
+ case stack( Instruction )
368
369
case owned( Value )
369
370
}
370
371
372
+ // scope.allocStackInstruction is always valid for Introducer.allocStack and is valid for Introducer.scoped when
373
+ // ScopedInstruction is a store_borrow.
371
374
let scope : LifetimeDependence . Scope
372
375
let introducer : Introducer
373
376
374
377
var firstInstruction : Instruction {
375
378
switch introducer {
376
379
case let . scoped( scopedInst) :
377
380
return scopedInst
381
+ case let . stack( initializingStore) :
382
+ return initializingStore
378
383
case let . owned( value) :
379
384
if let definingInst = value. definingInstructionOrTerminator {
380
385
return definingInst
381
386
}
382
387
return value. parentBlock. instructions. first!
383
388
}
384
389
}
390
+
385
391
var endInstructions : LazyMapSequence < LazyFilterSequence < UseList > , Instruction > {
386
392
switch introducer {
387
393
case let . scoped( scopedInst) :
388
394
return scopedInst. scopeEndingOperands. 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
+
389
403
case let . owned( value) :
390
404
return value. uses. endingLifetime. users
391
405
}
392
406
}
393
407
394
408
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
407
411
}
408
- return nil
412
+ return allocStack . deallocations
409
413
}
410
414
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.
412
417
init ? ( _ scope: LifetimeDependence . Scope , beginInst: Instruction ? ) {
413
418
self . scope = scope
414
419
guard let beginInst = beginInst, VariableScopeInstruction ( beginInst) == nil else {
415
420
return nil
416
421
}
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
419
426
}
420
- self . introducer = . scoped( scopedInst)
427
+ if scope. allocStackInstruction != nil {
428
+ self . introducer = . stack( beginInst)
429
+ return
430
+ }
431
+ return nil
421
432
}
422
433
423
434
// Allow extension of owned temporaries that
@@ -484,11 +495,14 @@ extension ScopeExtension {
484
495
switch initializer {
485
496
case let . store( initializingStore: store, initialAddress: _) :
486
497
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 .
488
499
gatherExtensions ( valueOrAddress: sb. source)
489
- scopes. push ( ExtendableScope ( scope, beginInst: sb) !)
500
+ }
501
+ if scope. allocStackInstruction != nil {
502
+ scopes. push ( ExtendableScope ( scope, beginInst: store) !)
490
503
return
491
504
}
505
+ break
492
506
case . argument, . yield:
493
507
// TODO: extend indirectly yielded scopes.
494
508
break
@@ -816,13 +830,10 @@ extension ExtendableScope {
816
830
switch initializer {
817
831
case . argument, . yield:
818
832
// 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
824
836
}
825
- return true
826
837
default :
827
838
// non-yield scopes can always be ended at any point.
828
839
return true
@@ -868,6 +879,9 @@ extension ExtendableScope {
868
879
var endsToErase = [ Instruction] ( )
869
880
if let deallocs = self . deallocs {
870
881
endsToErase. append ( contentsOf: deallocs. map { $0 } )
882
+ for dealloc in deallocs {
883
+ unreusedEnds. erase ( dealloc)
884
+ }
871
885
}
872
886
873
887
for end in range. ends {
@@ -920,10 +934,12 @@ extension ExtendableScope {
920
934
case let . initialized( initializer) :
921
935
switch initializer {
922
936
case let . store( initializingStore: store, initialAddress: _) :
937
+ var endInsts = SingleInlineArray < Instruction > ( )
923
938
if let sb = store as? StoreBorrowInst {
924
- var endInsts = SingleInlineArray < Instruction > ( )
925
939
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) )
927
943
return endInsts
928
944
}
929
945
break
0 commit comments