blob: dca8cadcaee2f821fde63989fc9d5fb4347c21ee [file] [log] [blame]
// 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
}
// 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 : $()
}
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 : $()
}