Files
swift-mirror/test/SILOptimizer/inline_begin_apply.sil
Nate Chandler 182bd34427 [SILInliner] Borrow guaranteed yields.
When inlining a begin_apply, if one of the values is yielded by
guaranteed convention, if the yielded value is itself owned, borrow it
during inlining.

Doing so is necessary because users of the yielded value are expecting a
value with guaranteed ownership.  For example, it's valid to
store_borrow such a value but not an owned value.
2022-11-28 16:53:03 -08:00

620 lines
22 KiB
Plaintext

// RUN: %target-sil-opt -inline -verify %s | %FileCheck %s
// RUN: %target-sil-opt -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
%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
%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
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
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
br cont
no:
abort_apply %token
br cont
cont:
%ret = tuple ()
return %ret : $()
}
// 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
br cont
no:
end_apply %token
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: bb1:
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[USE:%.*]] = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
// CHECK-NEXT: apply [[USE]](undef) : $@convention(thin) (@in Builtin.Int8) -> ()
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK-NEXT: [[T0:%.*]] = tuple ()
// CHECK-NEXT: return [[T0]] : $()
// 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
%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
%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
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: dealloc_stack [[A32]] : $*Builtin.Int32
// CHECK: unreachable
// CHECK: bb2:
// CHECK: unreachable
// CHECK: bb3:
// 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
unreachable
bb2:
end_apply %token
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
%retval = tuple ()
return %retval : $()
bb_unwind:
end_borrow %borrow : $*SomeClass
dealloc_stack %addr : $*SomeClass
abort_apply %token
unwind
}