// 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 { var x: Any var y: T } sil @make_indirect : $ () -> (@out Indirect) sil [transparent] [ossa] @test_one_yield : $@yield_once () -> (@yields @in Indirect) { 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 %make = function_ref @make_indirect : $@convention(thin) () -> (@out Indirect) apply %make(%temp) : $@convention(thin) () -> (@out Indirect) yield %temp : $*Indirect, resume resume, unwind unwind resume: %2000 = integer_literal $Builtin.Int32, 2000 apply %marker(%2000) : $@convention(thin) (Builtin.Int32) -> () dealloc_stack %temp : $*Indirect %ret = tuple () return %ret : $() unwind: %3000 = integer_literal $Builtin.Int32, 3000 apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> () dealloc_stack %temp : $*Indirect 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 () -> (@yields @in Indirect) { 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 // CHECK: [[MK_IND:%.*]] = function_ref @make_indirect // CHECK: apply [[MK_IND]]([[TEMP]]) // CHECK: destroy_addr [[TEMP]] : $*Indirect // 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 // 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 // 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 () -> (@yields @in Indirect) (%value, %token) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields @in Indirect) destroy_addr %value : $*Indirect 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 () -> (@yields @in Indirect) (%value, %token) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields @in Indirect) destroy_addr %value : $*Indirect 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 (Builtin.Int1) -> (@yields @in Indirect, @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 %make = function_ref @make_indirect : $@convention(thin) () -> (@out Indirect) cond_br %0, yield1, yield2 yield1: apply %make(%temp) : $@convention(thin) () -> (@out Indirect) %res = integer_literal $Builtin.Int64, 31 yield (%temp : $*Indirect, %res: $Builtin.Int64), resume resume1, unwind unwind1 yield2: apply %make(%temp) : $@convention(thin) () -> (@out Indirect) %res2 = integer_literal $Builtin.Int64, 32 yield (%temp : $*Indirect, %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 %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 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 (Builtin.Int1) -> (@yields @in Indirect, @yields Builtin.Int64) (%value, %value2, %token) = begin_apply %0(%flag) : $@convention(thin) @yield_once (Builtin.Int1) -> (@yields @in Indirect, @yields Builtin.Int64) destroy_addr %value : $*Indirect 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 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 () -> @yields @in_guaranteed T for { 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 : $() }