Files
swift-mirror/test/SILOptimizer/inline_begin_apply.sil
Erik Eckstein 18063707b5 Optimizer: enable complete OSSA lifetimes throughout the pass pipeline
This new OSSA invariant simplifies many optimizations because they don't have to take care of the corner case of incomplete lifetimes in dead-end blocks.

The implementation basically consists of these changes:
* add the lifetime completion utility
* add a flag in SILFunction which tells optimization that they need to run the lifetime completion utility
* let all optimizations complete lifetimes if necessary
* enable the ownership verifier to check complete lifetimes
2026-01-22 17:41:48 +01:00

871 lines
31 KiB
Plaintext

// RUN: %target-sil-opt -sil-print-types -inline -verify %s | %FileCheck %s
// RUN: %target-sil-opt -sil-print-types -mandatory-inlining -verify %s | %FileCheck %s
import Builtin
import Swift
sil @marker : $(Builtin.Int32) -> ()
class SomeClass {}
sil_vtable SomeClass {}
class SomeSubclass : SomeClass {}
sil_vtable SomeSubclass {}
// This is designed to be formally indirect.
struct Indirect<T: AnyObject> {
var x: Any
var y: T
}
sil @make_indirect : $<T: SomeClass> () -> (@out Indirect<T>)
sil [transparent] [ossa] @test_one_yield : $@yield_once <C: SomeClass> () -> (@yields @in Indirect<C>) {
entry:
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%1000 = integer_literal $Builtin.Int32, 1000
apply %marker(%1000) : $@convention(thin) (Builtin.Int32) -> ()
%temp = alloc_stack $Indirect<C>
%make = function_ref @make_indirect : $@convention(thin) <T: SomeClass> () -> (@out Indirect<T>)
apply %make<C>(%temp) : $@convention(thin) <T: SomeClass> () -> (@out Indirect<T>)
yield %temp : $*Indirect<C>, resume resume, unwind unwind
resume:
%2000 = integer_literal $Builtin.Int32, 2000
apply %marker(%2000) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %temp : $*Indirect<C>
%ret = tuple ()
return %ret : $()
unwind:
%3000 = integer_literal $Builtin.Int32, 3000
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %temp : $*Indirect<C>
unwind
}
sil [ossa] @getSomeClass : $@convention(thin) () -> @owned SomeClass
sil [transparent] [ossa] @yield_owned_as_guaranteed : $@yield_once @convention(thin) () -> @yields @guaranteed SomeClass {
%getSomeClass = function_ref @getSomeClass : $@convention(thin) () -> @owned SomeClass
%SomeClass = apply %getSomeClass() : $@convention(thin) () -> @owned SomeClass
yield %SomeClass : $SomeClass, resume bb1, unwind bb2
bb1:
destroy_value %SomeClass : $SomeClass
%retval = tuple ()
return %retval : $()
bb2:
destroy_value %SomeClass : $SomeClass
unwind
}
sil [transparent] [ossa] @test_unreachable : $@yield_once <C: SomeClass> () -> (@yields @in Indirect<C>) {
entry:
unreachable
}
// CHECK-LABEL: sil @test_simple_call
// CHECK: bb0(%0 : $Builtin.Int1):
// CHECK: [[MARKER:%.*]] = function_ref @marker
// CHECK: [[MARKER2:%.*]] = function_ref @marker
// CHECK: [[I:%.*]] = integer_literal $Builtin.Int32, 1000
// CHECK: apply [[MARKER2]]([[I]]) : $@convention(thin) (Builtin.Int32) -> ()
// CHECK: [[TEMP:%.*]] = alloc_stack $Indirect<SomeSubclass>
// CHECK: [[MK_IND:%.*]] = function_ref @make_indirect
// CHECK: apply [[MK_IND]]<SomeSubclass>([[TEMP]])
// CHECK: destroy_addr [[TEMP]] : $*Indirect<SomeSubclass>
// CHECK: cond_br %0, bb1, bb2
// CHECK: bb1:
// CHECK: [[I4:%.*]] = integer_literal $Builtin.Int32, 10
// CHECK: apply [[MARKER]]([[I4]])
// CHECK: [[I2:%.*]] = integer_literal $Builtin.Int32, 2000
// CHECK: apply [[MARKER2]]([[I2]])
// CHECK: dealloc_stack [[TEMP]] : $*Indirect<SomeSubclass>
// CHECK: [[I5:%.*]] = integer_literal $Builtin.Int32, 20
// CHECK: apply [[MARKER]]([[I5]])
// CHECK: br bb3
// CHECK: bb2:
// CHECK: [[I6:%.*]] = integer_literal $Builtin.Int32, 11
// CHECK: apply [[MARKER]]([[I6]])
// CHECK: [[I3:%.*]] = integer_literal $Builtin.Int32, 3000
// CHECK: apply [[MARKER2]]([[I3]])
// CHECK: dealloc_stack [[TEMP]] : $*Indirect<SomeSubclass>
// CHECK: [[I7:%.*]] = integer_literal $Builtin.Int32, 21
// CHECK: [[MARKER]]([[I7]])
// CHECK: br bb3
// CHECK:bb3:
// CHECK: return
// CHECK:}
sil @test_simple_call : $(Builtin.Int1) -> () {
entry(%flag : $Builtin.Int1):
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%0 = function_ref @test_one_yield : $@convention(thin) @yield_once <T: SomeClass> () -> (@yields @in Indirect<T>)
(%value, %token) = begin_apply %0<SomeSubclass>() : $@convention(thin) @yield_once <T: SomeClass> () -> (@yields @in Indirect<T>)
destroy_addr %value : $*Indirect<SomeSubclass>
cond_br %flag, yes, no
yes:
%10 = integer_literal $Builtin.Int32, 10
apply %marker(%10) : $@convention(thin) (Builtin.Int32) -> ()
end_apply %token as $()
%20 = integer_literal $Builtin.Int32, 20
apply %marker(%20) : $@convention(thin) (Builtin.Int32) -> ()
br cont
no:
%11 = integer_literal $Builtin.Int32, 11
apply %marker(%11) : $@convention(thin) (Builtin.Int32) -> ()
abort_apply %token
%21 = integer_literal $Builtin.Int32, 21
apply %marker(%21) : $@convention(thin) (Builtin.Int32) -> ()
br cont
cont:
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil @test_unreachable_call :
// CHECK: bb0(%0 : $Builtin.Int1):
// CHECK: [[MARKER:%.*]] = function_ref @marker
// CHECK: unreachable
// CHECK: } // end sil function 'test_unreachable_call'
sil @test_unreachable_call : $(Builtin.Int1) -> () {
entry(%flag : $Builtin.Int1):
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%0 = function_ref @test_unreachable : $@convention(thin) @yield_once <T: SomeClass> () -> (@yields @in Indirect<T>)
(%value, %token) = begin_apply %0<SomeSubclass>() : $@convention(thin) @yield_once <T: SomeClass> () -> (@yields @in Indirect<T>)
destroy_addr %value : $*Indirect<SomeSubclass>
cond_br %flag, yes, no
yes:
%10 = integer_literal $Builtin.Int32, 10
apply %marker(%10) : $@convention(thin) (Builtin.Int32) -> ()
end_apply %token as $()
%20 = integer_literal $Builtin.Int32, 20
apply %marker(%20) : $@convention(thin) (Builtin.Int32) -> ()
br cont
no:
%11 = integer_literal $Builtin.Int32, 11
apply %marker(%11) : $@convention(thin) (Builtin.Int32) -> ()
abort_apply %token
%21 = integer_literal $Builtin.Int32, 21
apply %marker(%21) : $@convention(thin) (Builtin.Int32) -> ()
br cont
cont:
%ret = tuple ()
return %ret : $()
}
sil [transparent] [ossa] @test_two_yield : $@yield_once <C: SomeClass> (Builtin.Int1) -> (@yields @in Indirect<C>, @yields Builtin.Int64) {
entry(%0 : $Builtin.Int1):
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%1000 = integer_literal $Builtin.Int32, 1000
apply %marker(%1000) : $@convention(thin) (Builtin.Int32) -> ()
%temp = alloc_stack $Indirect<C>
%make = function_ref @make_indirect : $@convention(thin) <T: SomeClass> () -> (@out Indirect<T>)
cond_br %0, yield1, yield2
yield1:
apply %make<C>(%temp) : $@convention(thin) <T: SomeClass> () -> (@out Indirect<T>)
%res = integer_literal $Builtin.Int64, 31
yield (%temp : $*Indirect<C>, %res: $Builtin.Int64), resume resume1, unwind unwind1
yield2:
apply %make<C>(%temp) : $@convention(thin) <T: SomeClass> () -> (@out Indirect<T>)
%res2 = integer_literal $Builtin.Int64, 32
yield (%temp : $*Indirect<C>, %res2: $Builtin.Int64), resume resume2, unwind unwind2
resume1:
br resume
resume2:
br resume
resume:
%2000 = integer_literal $Builtin.Int32, 2000
apply %marker(%2000) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %temp : $*Indirect<C>
%ret = tuple ()
return %ret : $()
unwind1:
br unwind
unwind2:
br unwind
unwind:
%3000 = integer_literal $Builtin.Int32, 3000
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %temp : $*Indirect<C>
unwind
}
// We don't support inlining functions with multiple yields yet.
// CHECK-LABEL: sil @test_simple_call_two_yields : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () {
// CHECK: bb0(%0 : $Builtin.Int1, %1 : $Builtin.Int1):
// CHECK: begin_apply
// CHECK: return
sil @test_simple_call_two_yields : $(Builtin.Int1, Builtin.Int1) -> () {
entry(%flag : $Builtin.Int1, %flag2 : $Builtin.Int1):
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%0 = function_ref @test_two_yield : $@convention(thin) @yield_once <T: SomeClass> (Builtin.Int1) -> (@yields @in Indirect<T>, @yields Builtin.Int64)
(%value, %value2, %token) = begin_apply %0<SomeSubclass>(%flag) : $@convention(thin) @yield_once <T: SomeClass> (Builtin.Int1) -> (@yields @in Indirect<T>, @yields Builtin.Int64)
destroy_addr %value : $*Indirect<SomeSubclass>
cond_br %flag2, yes, no
yes:
end_apply %token as $()
br cont
no:
abort_apply %token
br cont
cont:
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil [ossa] @test_simple_call_yield_owned : $@convention(thin) (Builtin.Int1, @owned SomeClass) -> () {
// CHECK: bb0(%0 : $Builtin.Int1, %1 : @owned $SomeClass):
// CHECK-NEXT: // function_ref
// CHECK-NEXT: %2 = function_ref @marker
// CHECK-NEXT: %3 = integer_literal $Builtin.Int32, 1000
// CHECK-NEXT: %4 = apply %2(%3)
// CHECK-NEXT: destroy_value %1
// CHECK-NEXT: cond_br %0, bb1, bb2
// CHECK: bb1:
// CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Int32, 2000
// CHECK-NEXT: apply %2([[T0]])
// CHECK-NEXT: tuple ()
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: [[T1:%.*]] = integer_literal $Builtin.Int32, 3000
// CHECK-NEXT: apply %2([[T1]])
// CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK-NEXT: [[T0:%.*]] = tuple ()
// CHECK-NEXT: return [[T0]] : $()
sil [transparent] [ossa] @yield_owned : $@yield_once(@owned SomeClass) -> (@yields @owned SomeClass) {
entry(%0 : @owned $SomeClass):
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%1000 = integer_literal $Builtin.Int32, 1000
apply %marker(%1000) : $@convention(thin) (Builtin.Int32) -> ()
yield %0 : $SomeClass, resume resume, unwind unwind
resume:
%2000 = integer_literal $Builtin.Int32, 2000
apply %marker(%2000) : $@convention(thin) (Builtin.Int32) -> ()
%ret = tuple ()
return %ret : $()
unwind:
%3000 = integer_literal $Builtin.Int32, 3000
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
unwind
}
sil [ossa] @test_simple_call_yield_owned : $(Builtin.Int1, @owned SomeClass) -> () {
entry(%flag : $Builtin.Int1, %c: @owned $SomeClass):
%0 = function_ref @yield_owned : $@convention(thin) @yield_once(@owned SomeClass) -> (@yields @owned SomeClass)
(%value, %token) = begin_apply %0(%c) : $@convention(thin) @yield_once(@owned SomeClass) -> (@yields @owned SomeClass)
destroy_value %value : $SomeClass
cond_br %flag, yes, no
yes:
end_apply %token as $()
br cont
no:
abort_apply %token
br cont
cont:
%ret = tuple ()
return %ret : $()
}
sil @use : $@convention(thin) (@in Builtin.Int8) -> ()
sil [transparent] [ossa] [ossa] @yield_inout : $@yield_once() -> (@yields @inout Builtin.Int8) {
entry:
%addr = alloc_stack $Builtin.Int8
%8 = integer_literal $Builtin.Int8, 8
store %8 to [trivial] %addr : $*Builtin.Int8
yield %addr : $*Builtin.Int8, resume resume, unwind unwind
resume:
%use = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
apply %use(%addr) : $@convention(thin) (@in Builtin.Int8) -> ()
dealloc_stack %addr: $*Builtin.Int8
%ret = tuple ()
return %ret : $()
unwind:
%3000 = integer_literal $Builtin.Int32, 3000
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %addr: $*Builtin.Int8
unwind
}
// CHECK-LABEL: sil [ossa] @test_simple_call_yield_inout : $@convention(thin) (Builtin.Int1) -> () {
// CHECK: bb0(%0 : $Builtin.Int1):
// CHECK-NEXT: %1 = alloc_stack $Builtin.Int8
// CHECK-NEXT: %2 = integer_literal $Builtin.Int8, 8
// CHECK-NEXT: store %2 to [trivial] %1 : $*Builtin.Int8
// CHECK-NEXT: cond_br %0, bb1, bb2
// CHECK: bb1:
// CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Int8, 8
// CHECK-NEXT: store [[T0]] to [trivial] %1 : $*Builtin.Int8
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[USE:%.*]] = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
// CHECK-NEXT: apply [[USE]](%1) : $@convention(thin) (@in Builtin.Int8) -> ()
// CHECK-NEXT: dealloc_stack %1 : $*Builtin.Int8
// CHECK-NEXT: tuple ()
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Int32, 3000
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[MARKER:%.*]] = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-NEXT: apply [[MARKER]]([[T0]]) : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-NEXT: dealloc_stack %1 : $*Builtin.Int8
// CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK-NEXT: [[T0:%.*]] = tuple ()
// CHECK-NEXT: return [[T0]] : $()
// CHECK: }
sil [ossa] @test_simple_call_yield_inout : $(Builtin.Int1) -> () {
entry(%flag : $Builtin.Int1):
%0 = function_ref @yield_inout : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
(%addr, %token) = begin_apply %0() : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
cond_br %flag, yes, no
yes:
%8 = integer_literal $Builtin.Int8, 8
store %8 to [trivial] %addr : $*Builtin.Int8
end_apply %token as $()
br cont
no:
abort_apply %token
br cont
cont:
%ret = tuple ()
return %ret : $()
}
sil [transparent] [ossa] [ossa] @yield_inout_result : $@yield_once() -> (@yields @inout Builtin.Int8, Builtin.Int32) {
entry:
%addr = alloc_stack $Builtin.Int8
%8 = integer_literal $Builtin.Int8, 8
store %8 to [trivial] %addr : $*Builtin.Int8
yield %addr : $*Builtin.Int8, resume resume, unwind unwind
resume:
%use = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
apply %use(%addr) : $@convention(thin) (@in Builtin.Int8) -> ()
dealloc_stack %addr: $*Builtin.Int8
%42 = integer_literal $Builtin.Int32, 42
return %42 : $Builtin.Int32
unwind:
%3000 = integer_literal $Builtin.Int32, 3000
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %addr: $*Builtin.Int8
unwind
}
sil [ossa] @test_simple_call_yield_inout_result : $(Builtin.Int1) -> Builtin.Int32 {
entry(%flag : $Builtin.Int1):
%0 = function_ref @yield_inout_result : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8, Builtin.Int32)
(%addr, %token) = begin_apply %0() : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8, Builtin.Int32)
cond_br %flag, yes, no
yes:
%8 = integer_literal $Builtin.Int8, 8
store %8 to [trivial] %addr : $*Builtin.Int8
%42 = end_apply %token as $Builtin.Int32
br cont(%42 : $Builtin.Int32)
no:
abort_apply %token
%0val = integer_literal $Builtin.Int32, 0
br cont(%0val : $Builtin.Int32)
cont(%ret : $Builtin.Int32):
return %ret : $Builtin.Int32
}
// CHECK-LABEL: sil [ossa] @test_simple_call_yield_inout_result : $@convention(thin) (Builtin.Int1) -> Builtin.Int32 {
// CHECK: bb0(%0 : $Builtin.Int1):
// CHECK-NEXT: %1 = alloc_stack $Builtin.Int8
// CHECK-NEXT: %2 = integer_literal $Builtin.Int8, 8
// CHECK-NEXT: store %2 to [trivial] %1 : $*Builtin.Int8
// CHECK-NEXT: cond_br %0, bb1, bb2
// CHECK: bb1:
// CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Int8, 8
// CHECK-NEXT: store [[T0]] to [trivial] %1 : $*Builtin.Int8
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[USE:%.*]] = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
// CHECK-NEXT: apply [[USE]](%1) : $@convention(thin) (@in Builtin.Int8) -> ()
// CHECK-NEXT: dealloc_stack %1 : $*Builtin.Int8
// CHECK-NEXT: [[NORMAL_RES:%.*]] = integer_literal $Builtin.Int32, 42
// CHECK-NEXT: br bb3([[NORMAL_RES]] : $Builtin.Int32)
// CHECK: bb2:
// CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Int32, 3000
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[MARKER:%.*]] = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-NEXT: apply [[MARKER]]([[T0]]) : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-NEXT: dealloc_stack %1 : $*Builtin.Int8
// CHECK-NEXT: [[UNWIND_RES:%.*]] = integer_literal $Builtin.Int32, 0
// CHECK-NEXT: br bb3([[UNWIND_RES]] : $Builtin.Int32)
// CHECK: bb3([[RES:%.*]] : $Builtin.Int32):
// CHECK-NEXT: return [[RES]] : $Builtin.Int32
// CHECK: }
// We can't inline yet if there are multiple ends.
// CHECK-LABEL: sil [ossa] @test_multi_end_yield_inout : $@convention(thin) (Builtin.Int1) -> () {
// CHECK: [[T0:%.*]] = function_ref @yield_inout
// CHECK: begin_apply [[T0]]
sil [ossa] @test_multi_end_yield_inout : $(Builtin.Int1) -> () {
entry(%flag : $Builtin.Int1):
%0 = function_ref @yield_inout : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
(%addr, %token) = begin_apply %0() : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
cond_br %flag, yes, no
yes:
end_apply %token as $()
br cont
no:
end_apply %token as $()
br cont
cont:
%ret = tuple ()
return %ret : $()
}
// We can't inline yet if there are multiple aborts.
// CHECK-LABEL: sil [ossa] @test_multi_abort_yield_inout : $@convention(thin) (Builtin.Int1) -> () {
// CHECK: [[T0:%.*]] = function_ref @yield_inout
// CHECK: begin_apply [[T0]]
sil [ossa] @test_multi_abort_yield_inout : $(Builtin.Int1) -> () {
entry(%flag : $Builtin.Int1):
%0 = function_ref @yield_inout : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
(%addr, %token) = begin_apply %0() : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
cond_br %flag, yes, no
yes:
abort_apply %token
br cont
no:
abort_apply %token
br cont
cont:
%ret = tuple ()
return %ret : $()
}
sil [transparent] [ossa] @no_yields : $@yield_once () -> (@yields @inout Builtin.Int8) {
entry:
%3000 = integer_literal $Builtin.Int32, 3000
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
unreachable
}
// CHECK-LABEL: sil [ossa] @test_simple_call_no_yields : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK-NEXT: [[T0:%.*]] = integer_literal $Builtin.Int32, 3000
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[MARKER:%.*]] = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-NEXT: apply [[MARKER]]([[T0]]) : $@convention(thin) (Builtin.Int32) -> ()
// CHECK-NEXT: unreachable
// CHECK: }
sil [ossa] @test_simple_call_no_yields : $() -> () {
entry:
%0 = function_ref @no_yields : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int8)
(%addr, %token) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int8)
%use = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
apply %use(%addr) : $@convention(thin) (@in Builtin.Int8) -> ()
end_apply %token as $()
%ret = tuple ()
return %ret : $()
}
sil [transparent] [ossa] @stack_overlap : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int32) {
entry:
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
%temp = alloc_stack $Builtin.Int32
%1000 = integer_literal $Builtin.Int32, 1000
store %1000 to [trivial] %temp : $*Builtin.Int32
%2000 = integer_literal $Builtin.Int32, 2000
apply %marker(%2000) : $@convention(thin) (Builtin.Int32) -> ()
yield %temp : $*Builtin.Int32, resume resume, unwind unwind
resume:
%3000 = integer_literal $Builtin.Int32, 3000
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %temp : $*Builtin.Int32
%4000 = integer_literal $Builtin.Int32, 4000
apply %marker(%4000) : $@convention(thin) (Builtin.Int32) -> ()
%ret = tuple ()
return %ret : $()
unwind:
dealloc_stack %temp : $*Builtin.Int32
unwind
}
// CHECK-LABEL: sil [ossa] @test_stack_overlap_dealloc
// CHECK: bb0:
// CHECK-NEXT: [[A16:%.*]] = alloc_stack $Builtin.Int16
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[MARKER:%.*]] = function_ref @marker
// CHECK-NEXT: [[A32:%.*]] = alloc_stack $Builtin.Int32
// CHECK-NEXT: [[I1000:%.*]] = integer_literal $Builtin.Int32, 1000
// CHECK-NEXT: store [[I1000]] to [trivial] [[A32]]
// CHECK-NEXT: [[I2000:%.*]] = integer_literal $Builtin.Int32, 2000
// CHECK-NEXT: apply [[MARKER]]([[I2000]])
// CHECK-NEXT: [[I3000:%.*]] = integer_literal $Builtin.Int32, 3000
// CHECK-NEXT: apply [[MARKER]]([[I3000]])
// CHECK-NEXT: dealloc_stack [[A32]] : $*Builtin.Int32
// Note that this has been delayed to follow stack discipline.
// CHECK-NEXT: dealloc_stack [[A16]] : $*Builtin.Int16
// CHECK-NEXT: [[I4000:%.*]] = integer_literal $Builtin.Int32, 4000
// CHECK-NEXT: apply [[MARKER]]([[I4000]])
// CHECK-NEXT: tuple ()
// CHECK-NEXT: [[RET:%.*]] = tuple ()
// CHECK-NEXT: return [[RET]] : $()
// CHECK-LABEL: // end sil function 'test_stack_overlap_dealloc'
sil [ossa] @test_stack_overlap_dealloc : $() -> () {
bb0:
%stack = alloc_stack $Builtin.Int16
%0 = function_ref @stack_overlap : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int32)
(%value, %token) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int32)
dealloc_stack %stack : $*Builtin.Int16
end_apply %token as $()
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil [ossa] @test_stack_overlap_alloc
// CHECK: bb0:
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[MARKER:%.*]] = function_ref @marker
// CHECK-NEXT: [[A32:%.*]] = alloc_stack $Builtin.Int32
// CHECK-NEXT: [[I1000:%.*]] = integer_literal $Builtin.Int32, 1000
// CHECK-NEXT: store [[I1000]] to [trivial] [[A32]]
// CHECK-NEXT: [[I2000:%.*]] = integer_literal $Builtin.Int32, 2000
// CHECK-NEXT: apply [[MARKER]]([[I2000]])
// CHECK-NEXT: [[A16:%.*]] = alloc_stack $Builtin.Int16
// CHECK-NEXT: [[I3000:%.*]] = integer_literal $Builtin.Int32, 3000
// CHECK-NEXT: apply [[MARKER]]([[I3000]])
// CHECK-NEXT: [[I4000:%.*]] = integer_literal $Builtin.Int32, 4000
// CHECK-NEXT: apply [[MARKER]]([[I4000]])
// CHECK-NEXT: tuple ()
// CHECK-NEXT: dealloc_stack [[A16]] : $*Builtin.Int16
// Note that this has been delayed to follow stack discipline.
// CHECK-NEXT: dealloc_stack [[A32]] : $*Builtin.Int32
// CHECK-NEXT: [[RET:%.*]] = tuple ()
// CHECK-NEXT: return [[RET]] : $()
// CHECK-LABEL: // end sil function 'test_stack_overlap_alloc'
sil [ossa] @test_stack_overlap_alloc : $() -> () {
bb0:
%0 = function_ref @stack_overlap : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int32)
(%value, %token) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int32)
%stack = alloc_stack $Builtin.Int16
end_apply %token as $()
dealloc_stack %stack : $*Builtin.Int16
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil [ossa] @test_stack_overlap_unreachable
// CHECK: bb0:
// CHECK: [[A16:%.*]] = alloc_stack $Builtin.Int16
// CHECK: [[A32:%.*]] = alloc_stack $Builtin.Int32
// CHECK: bb1:
// CHECK: unreachable
// CHECK: bb2:
// CHECK: dealloc_stack [[A32]] : $*Builtin.Int32
// CHECK: dealloc_stack [[A16]] : $*Builtin.Int16
// CHECK: return
// CHECK-LABEL: // end sil function 'test_stack_overlap_unreachable'
sil [ossa] @test_stack_overlap_unreachable : $() -> () {
bb0:
%stack = alloc_stack $Builtin.Int16
%0 = function_ref @stack_overlap : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int32)
(%value, %token) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields @inout Builtin.Int32)
cond_br undef, bb1, bb2
bb1:
dealloc_stack %stack : $*Builtin.Int16
end_borrow %token
unreachable
bb2:
end_apply %token as $()
dealloc_stack %stack : $*Builtin.Int16
%ret = tuple ()
return %ret : $()
}
// CHECK-LABEL: sil [ossa] @test_store_borrow_owned_as_guaranteed_yield : {{.*}} {
// CHECK: {{bb[0-9]+}}:
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $SomeClass
// CHECK: [[INSTANCE:%[^,]+]] = apply
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
// CHECK: [[BORROW:%[^,]+]] = store_borrow [[LIFETIME]] to [[ADDR]]
// CHECK: yield [[BORROW]] {{.*}}, resume [[BB_RESUME:bb[0-9]+]], unwind [[BB_UNWIND:bb[0-9]+]]
// CHECK: [[BB_RESUME]]:
// CHECK: end_borrow [[BORROW]]
// CHECK: dealloc_stack [[ADDR]]
// CHECK: end_borrow [[LIFETIME]]
// CHECK: destroy_value [[INSTANCE]]
// CHECK: tuple ()
// CHECK: [[RETVAL:%[^,]+]] = tuple ()
// CHECK: return [[RETVAL]]
// CHECK: [[BB_UNWIND]]:
// CHECK: end_borrow [[BORROW]]
// CHECK: dealloc_stack [[ADDR]]
// CHECK: end_borrow [[LIFETIME]]
// CHECK: destroy_value [[INSTANCE]]
// CHECK: unwind
// CHECK-LABEL: } // end sil function 'test_store_borrow_owned_as_guaranteed_yield'
sil [ossa] @test_store_borrow_owned_as_guaranteed_yield : $@yield_once @convention(thin) @substituted <T> () -> @yields @in_guaranteed T for <SomeClass> {
entry:
%addr = alloc_stack $SomeClass
%callee = function_ref @yield_owned_as_guaranteed : $@yield_once @convention(thin) () -> @yields @guaranteed SomeClass
(%instance, %token) = begin_apply %callee() : $@yield_once @convention(thin) () -> @yields @guaranteed SomeClass
%borrow = store_borrow %instance to %addr : $*SomeClass
yield %borrow : $*SomeClass, resume bb_resume, unwind bb_unwind
bb_resume:
end_borrow %borrow : $*SomeClass
dealloc_stack %addr : $*SomeClass
end_apply %token as $()
%retval = tuple ()
return %retval : $()
bb_unwind:
end_borrow %borrow : $*SomeClass
dealloc_stack %addr : $*SomeClass
abort_apply %token
unwind
}
sil [ossa] [transparent] @simplest_in_guaranteed : $@yield_once @convention(thin) () -> @yields @in_guaranteed () {
entry:
%tuple = tuple ()
%addr = alloc_stack $()
store %tuple to [trivial] %addr : $*()
yield %addr : $*(), resume resume_block, unwind unwind_block
resume_block:
dealloc_stack %addr : $*()
%retval = tuple ()
return %retval : $()
unwind_block:
dealloc_stack %addr : $*()
unwind
}
// CHECK-LABEL: sil [ossa] @ends_1 : {{.*}} {
// CHECK: [[VOID:%[^,]+]] = tuple ()
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $()
// CHECK: store [[VOID]] to [trivial] [[ADDR]]
// CHECK: cond_br undef, [[GOOD:bb[0-9]+]], [[BAD:bb[0-9]+]]
// CHECK: [[GOOD]]:
// CHECK: dealloc_stack [[ADDR]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[BAD]]:
// CHECK: cond_br undef, [[NORMAL_BAD:bb[0-9]+]], [[REALLY_BAD:bb[0-9]+]]
// CHECK: [[NORMAL_BAD]]:
// CHECK: dealloc_stack [[ADDR]]
// CHECK: br [[EXIT]]
// CHECK: [[REALLY_BAD]]:
// CHECK: unreachable
// CHECK: [[EXIT]]:
// CHECK-LABEL: } // end sil function 'ends_1'
sil [ossa] @ends_1 : $@convention(thin) () -> () {
entry:
%simplest = function_ref @simplest_in_guaranteed : $@yield_once @convention(thin) () -> @yields @in_guaranteed ()
(%_, %token) = begin_apply %simplest() : $@yield_once @convention(thin) () -> @yields @in_guaranteed ()
cond_br undef, good, bad
good:
end_apply %token as $()
br exit
bad:
cond_br undef, normal_bad, really_bad
normal_bad:
abort_apply %token
br exit
really_bad:
end_borrow %token : $Builtin.SILToken
unreachable
exit:
%retval = tuple ()
return %retval : $()
}
// Test handling for multiple end_borrows of a token.
// CHECK-LABEL: sil [ossa] @ends_2 : {{.*}} {
// CHECK: [[VOID:%[^,]+]] = tuple ()
// CHECK: [[ADDR:%[^,]+]] = alloc_stack $()
// CHECK: store [[VOID]] to [trivial] [[ADDR]] : $*()
// CHECK: cond_br undef, [[GOOD:bb[0-9]+]], [[BAD:bb[0-9]+]]
// CHECK: [[GOOD]]:
// CHECK: dealloc_stack [[ADDR]]
// CHECK: br [[EXIT:bb[0-9]+]]
// CHECK: [[BAD]]:
// CHECK: cond_br undef, [[NORMAL_BAD:bb[0-9]+]], [[REALLY_BAD:bb[0-9]+]]
// CHECK: [[NORMAL_BAD]]:
// CHECK: dealloc_stack [[ADDR]]
// CHECK: br [[EXIT]]
// CHECK: [[REALLY_BAD]]:
// CHECK: cond_br undef, [[BAD_NEWS_BUNNIES:bb[0-9]+]], [[BAD_NEWS_BEARS:bb[0-9]+]]
// CHECK: [[BAD_NEWS_BUNNIES]]:
// CHECK: unreachable
// CHECK: [[BAD_NEWS_BEARS]]:
// CHECK: unreachable
// CHECK: [[EXIT]]:
// CHECK-LABEL: } // end sil function 'ends_2'
sil [ossa] @ends_2 : $@convention(thin) () -> () {
entry:
%simplest = function_ref @simplest_in_guaranteed : $@yield_once @convention(thin) () -> @yields @in_guaranteed ()
(%_, %token) = begin_apply %simplest() : $@yield_once @convention(thin) () -> @yields @in_guaranteed ()
cond_br undef, good, bad
good:
end_apply %token as $()
br exit
bad:
cond_br undef, normal_bad, really_bad
normal_bad:
abort_apply %token
br exit
really_bad:
cond_br undef, bad_news_bunnies, bad_news_bears
bad_news_bunnies:
end_borrow %token : $Builtin.SILToken
unreachable
bad_news_bears:
end_borrow %token : $Builtin.SILToken
unreachable
exit:
%retval = tuple ()
return %retval : $()
}
sil [transparent] [ossa] @simplest_yield_once_2 : $@yield_once_2 @convention(thin) () -> @yields @in_guaranteed () {
%addr = alloc_stack $()
yield %addr : $*(), resume resume_block, unwind unwind_block
unwind_block:
dealloc_stack %addr : $*()
unwind
resume_block:
dealloc_stack %addr : $*()
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @simplest_begin_apply_yield_once_2 : {{.*}} {
// CHECK-NOT: begin_apply
// CHECK-LABEL: } // end sil function 'simplest_begin_apply_yield_once_2'
sil [ossa] @simplest_begin_apply_yield_once_2 : $@convention(thin) () -> () {
%callee = function_ref @simplest_yield_once_2 : $@yield_once_2 @convention(thin) () -> @yields @in_guaranteed ()
(%addr, %token, %allocation) = begin_apply %callee() : $@yield_once_2 @convention(thin) () -> @yields @in_guaranteed ()
end_apply %token as $()
dealloc_stack %allocation : $*Builtin.SILToken
%retval = tuple ()
return %retval : $()
}
// Just make sure that inlining doesn't produce invalid SIL
// CHECK-LABEL: sil [ossa] @co_routine_lifetime_completion :
// CHECK: function_ref @co_routine :
// CHECK: } // end sil function 'co_routine_lifetime_completion'
sil [ossa] @co_routine_lifetime_completion : $@convention(thin) (@owned String, @in_guaranteed String) -> @owned String {
bb0(%0 : @owned $String, %1 : $*String):
%2 = function_ref @call_co_routine : $@yield_once @convention(thin) (@guaranteed String, @guaranteed String) -> @yields @inout Optional<Int>
%3 = load_borrow %1
(%4, %5) = begin_apply %2(%0, %3) : $@yield_once @convention(thin) (@guaranteed String, @guaranteed String) -> @yields @inout Optional<Int>
%6 = load [trivial] %4
switch_enum %6, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb1
bb1:
end_borrow %5
end_borrow %3
destroy_value [dead_end] %0
unreachable
bb2(%12 : $Int):
%13 = end_apply %5 as $()
end_borrow %3
return %0
}
sil @co_routine : $@yield_once @convention(thin) (@guaranteed String) -> @yields @inout Optional<Int>
sil [ossa] [transparent] @call_co_routine : $@yield_once @convention(thin) (@guaranteed String, @guaranteed String) -> @yields @inout Optional<Int> {
bb0(%0 : @guaranteed $String, %1 : @guaranteed $String):
%2 = function_ref @co_routine : $@yield_once @convention(thin) (@guaranteed String) -> @yields @inout Optional<Int>
%3 = alloc_ref $SomeClass
(%4, %5) = begin_apply %2(%0) : $@yield_once @convention(thin) (@guaranteed String) -> @yields @inout Optional<Int>
yield %4, resume bb1, unwind bb2
bb1:
%7 = end_apply %5 as $()
destroy_value %3
%9 = tuple ()
return %9
bb2:
%11 = end_apply %5 as $()
destroy_value %3
unwind
}