| // RUN: %target-sil-opt -enable-sil-verify-all %s -capture-promotion -enable-sil-ownership | %FileCheck %s |
| |
| // Check to make sure that the process of promoting closure captures results in |
| // a correctly cloned and modified closure function body. This test |
| // intentionally only includes one promotable closure so that there is minimal |
| // ordering dependence in the checked output. |
| |
| sil_stage raw |
| |
| import Builtin |
| |
| struct Int { |
| var value : Builtin.Int64 |
| } |
| |
| class Foo { |
| func foo() -> Int |
| } |
| |
| class Bar { |
| } |
| |
| struct Baz { |
| var bar: Bar |
| var x: Int |
| } |
| |
| sil @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int |
| sil @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo |
| sil @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| sil @dummy_func : $@convention(thin) (Int, Int, Int) -> Int |
| sil @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> () |
| |
| // CHECK-LABEL: sil @test_capture_promotion |
| sil @test_capture_promotion : $@convention(thin) () -> @owned @callee_owned () -> (Int, Builtin.Int64) { |
| bb0: |
| // CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Foo> |
| // CHECK: [[MARKED_BOX1:%.*]] = mark_uninitialized [var] [[BOX1]] |
| %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Foo> |
| %1ab = mark_uninitialized [var] %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| %1a = project_box %1ab : $<τ_0_0> { var τ_0_0 } <Foo>, 0 |
| %2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo |
| %3 = metatype $@thick Foo.Type |
| %4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo |
| store %4 to [init] %1a : $*Foo |
| |
| // CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %6 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %6a = project_box %6 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %7 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| %8 = metatype $@thin Baz.Type |
| %9 = apply %7(%8) : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| store %9 to [init] %6a : $*Baz |
| |
| // CHECK: [[BOX3:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int> |
| %11 = alloc_box $<τ_0_0> { var τ_0_0 } <Int> |
| %11a = project_box %11 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| %12 = function_ref @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int |
| %13 = metatype $@thin Int.Type |
| %14 = integer_literal $Builtin.Word, 3 |
| %15 = apply %12(%14, %13) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int |
| store %15 to [trivial] %11a : $*Int |
| |
| // CHECK: [[BOX1_COPY:%.*]] = copy_value [[MARKED_BOX1]] |
| // CHECK: [[BOX1_COPY_PB:%.*]] = project_box [[BOX1_COPY]] |
| // CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]] |
| // CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]] |
| // CHECK: [[BOX3_COPY:%.*]] = copy_value [[BOX3]] |
| // CHECK: [[BOX3_COPY_PB:%.*]] = project_box [[BOX3_COPY]] |
| |
| // CHECK-NOT: function_ref @closure0 : |
| // CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @$S8closure0Tf2iii_n |
| // CHECK-NOT: function_ref @closure0 : |
| |
| // The Foo variable is loaded from and retained, because it is a reference type |
| // CHECK-NEXT: [[LOADFOO:%.*]] = load [copy] [[BOX1_COPY_PB]] : $*Foo |
| // CHECK-NEXT: destroy_value [[BOX1_COPY]] |
| // |
| // The Baz variable is loaded and copied, because it is a non-trivial |
| // aggregate type |
| // CHECK-NEXT: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz |
| // CHECK-NEXT: destroy_value [[BOX2_COPY]] |
| |
| // The Int variable is loaded only, because it is trivial |
| // CHECK-NEXT: [[LOADINT:%.*]] = load [trivial] [[BOX3_COPY_PB]] : $*Int |
| // CHECK-NEXT: destroy_value [[BOX3_COPY]] |
| |
| // The partial apply has one value argument for each pair of arguments that was |
| // previously used to capture and pass the variable by reference |
| // CHECK-NEXT: {{.*}} = partial_apply [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]]) |
| |
| %17 = function_ref @closure0 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> (Int, Builtin.Int64) |
| %18 = copy_value %1ab : $<τ_0_0> { var τ_0_0 } <Foo> |
| %19 = copy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| %20 = copy_value %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| %21 = partial_apply %17(%18, %19, %20) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> (Int, Builtin.Int64) |
| |
| destroy_value %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| destroy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| destroy_value %1ab : $<τ_0_0> { var τ_0_0 } <Foo> |
| |
| return %21 : $@callee_owned () -> (Int, Builtin.Int64) |
| } |
| |
| // CHECK-LABEL: sil @test_capture_promotion_indirect |
| sil @test_capture_promotion_indirect : $@convention(thin) () -> @owned @callee_owned () -> @out Int { |
| bb0: |
| // CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Foo> |
| %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Foo> |
| %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Foo>, 0 |
| %2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo |
| %3 = metatype $@thick Foo.Type |
| %4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo |
| store %4 to [init] %1a : $*Foo |
| |
| // CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %6 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %6a = project_box %6 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %7 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| %8 = metatype $@thin Baz.Type |
| %9 = apply %7(%8) : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| store %9 to [init] %6a : $*Baz |
| |
| // CHECK: [[BOX3:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Int> |
| %11 = alloc_box $<τ_0_0> { var τ_0_0 } <Int> |
| %11a = project_box %11 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| %12 = function_ref @convert_from_integer_literal : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int |
| %13 = metatype $@thin Int.Type |
| %14 = integer_literal $Builtin.Word, 3 |
| %15 = apply %12(%14, %13) : $@convention(thin) (Builtin.Word, @thin Int.Type) -> Int |
| store %15 to [trivial] %11a : $*Int |
| |
| // CHECK: [[BOX1_COPY:%.*]] = copy_value [[BOX1]] |
| // CHECK: [[BOX1_COPY_PB:%.*]] = project_box [[BOX1_COPY]] |
| // CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]] |
| // CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]] |
| // CHECK: [[BOX3_COPY:%.*]] = copy_value [[BOX3]] |
| // CHECK: [[BOX3_COPY_PB:%.*]] = project_box [[BOX3_COPY]] |
| |
| // CHECK-NOT: function_ref @closure_indirect_result : |
| // CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @$S23closure_indirect_resultTf2niii_n |
| // CHECK-NOT: function_ref @closure_indirect_result : |
| %17 = function_ref @closure_indirect_result : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> @out Int |
| |
| // CHECK-NEXT: [[LOADFOO:%.*]] = load [copy] [[BOX1_COPY_PB]] : $*Foo |
| // CHECK-NEXT: destroy_value [[BOX1_COPY]] |
| // CHECK-NEXT: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz |
| // CHECK-NEXT: destroy_value [[BOX2_COPY]] |
| // CHECK-NEXT: [[LOADINT:%.*]] = load [trivial] [[BOX3_COPY_PB]] : $*Int |
| // CHECK-NEXT: destroy_value [[BOX3_COPY]] |
| %18 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| %19 = copy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| %20 = copy_value %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| |
| // The partial apply has one value argument for each pair of arguments that was |
| // previously used to capture and pass the variable by reference |
| // CHECK-NEXT: {{.*}} = partial_apply [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]]) |
| %21 = partial_apply %17(%18, %19, %20) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> @out Int |
| |
| destroy_value %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| destroy_value %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| |
| return %21 : $@callee_owned () -> @out Int |
| } |
| |
| // CHECK-LABEL: sil private @$S8closure0Tf2iii_n : $@convention(thin) (@owned Foo, @owned Baz, Int) -> (Int, Builtin.Int64) { |
| // CHECK: bb0([[ORIGINAL_ARG0:%.*]] : @owned $Foo, [[ORIGINAL_ARG1:%.*]] : @owned $Baz, [[ARG2:%.*]] : @trivial $Int): |
| // CHECK: [[ARG0:%.*]] = begin_borrow [[ORIGINAL_ARG0]] |
| // CHECK: [[ARG1:%.*]] = begin_borrow [[ORIGINAL_ARG1]] |
| // CHECK: [[DUMMY_FUNC:%.*]] = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int |
| |
| // CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]] |
| // CHECK: [[METHOD_FOO:%.*]] = class_method [[ARG0_COPY]] : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| // CHECK: [[BORROWED_ARG0_COPY:%.*]] = begin_borrow [[ARG0_COPY]] |
| // CHECK: [[APPLY_FOO:%.*]] = apply [[METHOD_FOO]]([[BORROWED_ARG0_COPY]]) : $@convention(method) (@guaranteed Foo) -> Int |
| // CHECK: end_borrow [[BORROWED_ARG0_COPY]] from [[ARG0_COPY]] |
| // CHECK: destroy_value [[ARG0_COPY]] |
| |
| // CHECK: [[EXTRACT_BAZ_X:%.*]] = struct_extract [[ARG1]] : $Baz, #Baz.x |
| // CHECK: [[EXTRACT_INT_VALUE:%.*]] = struct_extract [[ARG2]] : $Int, #Int.value |
| // CHECK: [[RETVAL:%.*]] = apply [[DUMMY_FUNC]]([[APPLY_FOO]], [[EXTRACT_BAZ_X]], {{.*}}) : $@convention(thin) (Int, Int, Int) -> Int |
| |
| // The release of %4 is removed because the Int type is trivial |
| |
| // The release of %2 is replaced by a release_value of the Baz argument, since |
| // it is a non-trivial aggregate |
| // CHECK: end_borrow [[ARG1]] from [[ORIGINAL_ARG1]] |
| // CHECK: destroy_value [[ORIGINAL_ARG1]] : $Baz |
| |
| // The release of %0 is replaced by a strong_release of the Foo argument, since |
| // it is a reference type |
| // CHECK: end_borrow [[ARG0]] from [[ORIGINAL_ARG0]] |
| // CHECK: destroy_value [[ORIGINAL_ARG0]] |
| // CHECK: [[RESULT:%.*]] = tuple ([[RETVAL]] : $Int, [[EXTRACT_INT_VALUE]] : $Builtin.Int64) |
| // CHECK: return [[RESULT]] : $(Int, Builtin.Int64) |
| // CHECK: } // end sil function '$S8closure0Tf2iii_n' |
| |
| sil private @closure0 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> (Int, Builtin.Int64) { |
| bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Foo>, %2 : @owned $<τ_0_0> { var τ_0_0 } <Baz>, %4 : @owned $<τ_0_0> { var τ_0_0 } <Int>): |
| %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Foo>, 0 |
| %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %5 = project_box %4 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| %6 = tuple () |
| // function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int |
| %7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int |
| %8 = load [copy] %1 : $*Foo |
| %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| %9 = begin_borrow %8 : $Foo |
| %11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int |
| end_borrow %9 from %8 : $Foo, $Foo |
| destroy_value %8 : $Foo |
| %12 = struct_element_addr %3 : $*Baz, #Baz.x |
| %13 = load [trivial] %12 : $*Int |
| %14 = load [trivial] %5 : $*Int |
| %15 = struct_element_addr %5 : $*Int, #Int.value |
| %16 = load [trivial] %15 : $*Builtin.Int64 |
| %17 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int |
| destroy_value %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Baz> |
| destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Foo> |
| %18 = tuple(%17 : $Int, %16 : $Builtin.Int64) |
| return %18 : $(Int, Builtin.Int64) |
| } |
| |
| // The closure in this function is not promotable because it mutates its argument |
| |
| // CHECK-LABEL: sil @test_unpromotable |
| sil @test_unpromotable : $@convention(thin) () -> @owned @callee_owned () -> Int { |
| bb0: |
| %0 = tuple () |
| %1 = alloc_box $<τ_0_0> { var τ_0_0 } <Foo> |
| %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Foo>, 0 |
| %2 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo |
| %3 = metatype $@thick Foo.Type |
| %4 = apply %2(%3) : $@convention(thin) (@thick Foo.Type) -> @owned Foo |
| store %4 to [init] %1a : $*Foo |
| %17 = function_ref @closure1 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>) -> Int |
| %18 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| // CHECK: partial_apply {{%.*}}({{%.*}}) |
| %21 = partial_apply %17(%18) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>) -> Int |
| destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| return %21 : $@callee_owned () -> Int |
| } |
| |
| sil @mutate_foo : $@convention(thin) (@inout Foo) -> () |
| |
| sil private @closure1 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>) -> Int { |
| bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Foo>): |
| %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Foo>, 0 |
| %6 = tuple () |
| // function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int |
| %7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int |
| %8 = load [copy] %1 : $*Foo |
| %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| %9 = begin_borrow %8 : $Foo |
| %11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int |
| end_borrow %9 from %8 : $Foo, $Foo |
| destroy_value %8 : $Foo |
| %12 = function_ref @mutate_foo : $@convention(thin) (@inout Foo) -> () |
| %13 = apply %12(%1) : $@convention(thin) (@inout Foo) -> () |
| destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Foo> |
| return %11 : $Int |
| } |
| |
| sil @apply : $@convention(thin) (@owned @callee_owned () -> ()) -> () |
| |
| // CHECK-LABEL: sil @captureWithinGeneric |
| sil @captureWithinGeneric : $@convention(thin) <T> (@inout Int, @inout Int) -> () { |
| // CHECK: bb0 |
| bb0(%0 : @trivial $*Int, %1 : @trivial $*Int): |
| %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int> |
| %2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| copy_addr %0 to [initialization] %2a : $*Int |
| %4 = alloc_box $<τ_0_0> { var τ_0_0 } <Int> |
| %4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| copy_addr %1 to [initialization] %4a : $*Int |
| %6 = function_ref @apply : $@convention(thin) (@owned @callee_owned () -> ()) -> () |
| // CHECK: [[PROMOTED:%[0-9a-zA-Z]+]] = function_ref @$S27closureWithGenericSignatureTf2ni_n : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <Int>, Int) -> () |
| %7 = function_ref @closureWithGenericSignature : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <Int>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> () |
| %8 = copy_value %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| %9 = copy_value %2 : $<τ_0_0> { var τ_0_0 } <Int> |
| // CHECK: partial_apply [[PROMOTED]]<{{[^>]+}}>( |
| %10 = partial_apply %7<T>(%8, %9) : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <Int>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> () |
| %11 = apply %6(%10) : $@convention(thin) (@owned @callee_owned () -> ()) -> () |
| copy_addr %4a to %1 : $*Int |
| destroy_value %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| copy_addr %2a to %0 : $*Int |
| destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int> |
| %16 = tuple () |
| return %16 : $() |
| } |
| |
| // CHECK: sil @$S27closureWithGenericSignatureTf2ni_n : $@convention(thin) <{{[^>]+}}> (@owned <τ_0_0> { var τ_0_0 } <Int>, Int) -> () |
| sil @closureWithGenericSignature : $@convention(thin) <T> (@owned <τ_0_0> { var τ_0_0 } <Int>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> () { |
| bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Int>, %2 : @owned $<τ_0_0> { var τ_0_0 } <Int>): |
| %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| %4 = function_ref @$Ss1poiyS2i_SitF : $@convention(thin) (Int, Int) -> Int |
| %5 = load [trivial] %3 : $*Int |
| %6 = load [trivial] %3 : $*Int |
| %7 = apply %4(%5, %6) : $@convention(thin) (Int, Int) -> Int |
| assign %7 to %1 : $*Int |
| destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int> |
| destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Int> |
| %11 = tuple () |
| return %11 : $() |
| } |
| |
| sil [transparent] [serialized] @$Ss1poiyS2i_SitF : $@convention(thin) (Int, Int) -> Int |
| |
| sil private @closure_indirect_result : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> @out Int { |
| bb0(%0: @trivial $*Int, %1 : @owned $<τ_0_0> { var τ_0_0 } <Foo>, %2 : @owned $<τ_0_0> { var τ_0_0 } <Baz>, %4 : @owned $<τ_0_0> { var τ_0_0 } <Int>): |
| %17 = project_box %1 : $<τ_0_0> { var τ_0_0 } <Foo>, 0 |
| %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %5 = project_box %4 : $<τ_0_0> { var τ_0_0 } <Int>, 0 |
| // function_ref test14.plus (a : Swift.Int, b : Swift.Int, c : Swift.Int) -> Swift.Int |
| %7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int |
| %8 = load [copy] %17 : $*Foo |
| %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| %9 = begin_borrow %8 : $Foo |
| %11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int |
| end_borrow %9 from %8 : $Foo, $Foo |
| destroy_value %8 : $Foo |
| %12 = struct_element_addr %3 : $*Baz, #Baz.x |
| %13 = load [trivial] %12 : $*Int |
| %14 = load [trivial] %5 : $*Int |
| %15 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int |
| destroy_value %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Baz> |
| destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| store %15 to [trivial] %0 : $*Int |
| %16 = tuple() |
| return %16 : $() |
| } |
| |
| // This test makes sure that we properly handle non load uses of |
| // struct_element_addr that always have load users with the load occurring before |
| // and after the element in the use list. |
| |
| sil @mutate_int : $@convention(thin) (@inout Int) -> () |
| |
| // CHECK-LABEL: sil @test_closure_multiple_uses_of_struct_element_addr : $@convention(thin) () -> @owned @callee_owned () -> () { |
| // CHECK: [[FUNC:%.*]] = function_ref @closure_multiple_uses_of_struct_element_addr : $@convention(thin) |
| // CHECK: partial_apply [[FUNC]]( |
| // CHECK: } // end sil function 'test_closure_multiple_uses_of_struct_element_addr' |
| sil @test_closure_multiple_uses_of_struct_element_addr : $@convention(thin) () -> @owned @callee_owned () -> () { |
| bb0: |
| %0 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| %1 = metatype $@thin Baz.Type |
| |
| %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %4 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| store %4 to [init] %3 : $*Baz |
| |
| %5 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %6 = project_box %5 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %7 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| store %7 to [init] %6 : $*Baz |
| |
| %8 = function_ref @closure_multiple_uses_of_struct_element_addr : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Baz>) -> () |
| %9 = partial_apply %8(%2, %5) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Baz>) -> () |
| |
| return %9 : $@callee_owned () -> () |
| } |
| |
| sil @closure_multiple_uses_of_struct_element_addr : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Baz>) -> () { |
| bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Baz>, %1 : @owned $<τ_0_0> { var τ_0_0 } <Baz>): |
| %2 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %3 = struct_element_addr %2 : $*Baz, #Baz.x |
| %4 = load [trivial] %3 : $*Int |
| %5 = function_ref @mutate_int : $@convention(thin) (@inout Int) -> () |
| apply %5(%3) : $@convention(thin) (@inout Int) -> () |
| |
| %6 = project_box %1 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %7 = struct_element_addr %6 : $*Baz, #Baz.x |
| apply %5(%7) : $@convention(thin) (@inout Int) -> () |
| %8 = load [trivial] %7 : $*Int |
| |
| destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Baz> |
| destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Baz> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @test_capture_projection_test : $@convention(thin) () -> @owned @callee_owned () -> () { |
| sil @test_capture_projection_test : $@convention(thin) () -> @owned @callee_owned () -> () { |
| bb0: |
| %0 = function_ref @baz_init : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| %1 = metatype $@thin Baz.Type |
| |
| // CHECK: [[BOX1:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %2 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %3 = project_box %2 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %4 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| store %4 to [init] %3 : $*Baz |
| |
| // CHECK: [[BOX2:%.*]] = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %5 = alloc_box $<τ_0_0> { var τ_0_0 } <Baz> |
| %6 = project_box %5 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %7 = apply %0(%1) : $@convention(thin) (@thin Baz.Type) -> @owned Baz |
| store %7 to [init] %6 : $*Baz |
| |
| // CHECK: [[BOX1_COPY:%.*]] = copy_value [[BOX1]] |
| // CHECK: [[BOX2_COPY:%.*]] = copy_value [[BOX2]] |
| // CHECK: [[BOX2_COPY_PB:%.*]] = project_box [[BOX2_COPY]] |
| // CHECK-NOT: function_ref @closure_indirect_result : |
| // CHECK: [[SPECIALIZED_FUNC:%.*]] = function_ref @$S23closure_projection_testTf2ni_n : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned Baz) -> () |
| // CHECK-NOT: function_ref @closure_projection_test : |
| // CHECK: [[LOADBAZ:%.*]] = load [copy] [[BOX2_COPY_PB]] : $*Baz |
| // CHECK: destroy_value [[BOX2_COPY]] |
| %19 = copy_value %2 : $<τ_0_0> { var τ_0_0 } <Baz> |
| %20 = copy_value %5 : $<τ_0_0> { var τ_0_0 } <Baz> |
| %17 = function_ref @closure_projection_test : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Baz>) -> () |
| |
| // The partial apply has one value argument for each pair of arguments that was |
| // previously used to capture and pass the variable by reference |
| // CHECK: {{.*}} = partial_apply [[SPECIALIZED_FUNC]]([[BOX1_COPY]], [[LOADBAZ]]) |
| %21 = partial_apply %17(%19, %20) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Baz>) -> () |
| |
| destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Baz> |
| destroy_value %5 : $<τ_0_0> { var τ_0_0 } <Baz> |
| |
| return %21 : $@callee_owned () -> () |
| } |
| |
| // CHECK-LABEL: sil @$S23closure_projection_testTf2ni_n : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned Baz) -> () { |
| // CHECK: bb0([[UNPROMOTED_BAZ:%.*]] : @owned $<τ_0_0> { var τ_0_0 } <Baz>, [[BAZ:%.*]] : @owned $Baz): |
| // CHECK: [[BORROWED_BAZ:%.*]] = begin_borrow [[BAZ]] : $Baz |
| // CHECK: [[X:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.x |
| // CHECK: [[BAR:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.bar |
| // CHECK: [[BAR_COPY:%.*]] = copy_value [[BAR]] |
| // CHECK: [[BAR2:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.bar |
| // CHECK: [[BAR2_COPY:%.*]] = copy_value [[BAR2]] |
| // CHECK: [[BAR2_COPY_BORROW:%.*]] = begin_borrow [[BAR2_COPY]] |
| // CHECK: apply {{%.*}}([[BAR_COPY]], [[BAR2_COPY_BORROW]], [[X]]) |
| // CHECK: end_borrow [[BAR2_COPY_BORROW]] from [[BAR2_COPY]] |
| // CHECK: destroy_value [[BAR2_COPY]] |
| // CHECK: end_borrow [[BORROWED_BAZ]] from [[BAZ]] |
| // CHECK: destroy_value [[BAZ]] |
| // CHECK: } // end sil function '$S23closure_projection_testTf2ni_n' |
| sil @closure_projection_test : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Baz>) -> () { |
| bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Baz>, %1 : @owned $<τ_0_0> { var τ_0_0 } <Baz>): |
| %0a = project_box %0 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %2 = struct_element_addr %0a : $*Baz, #Baz.x |
| %3 = struct_element_addr %0a : $*Baz, #Baz.bar |
| %4 = load [trivial] %2 : $*Int |
| %5 = load [take] %3 : $*Bar |
| %6 = load [copy] %3 : $*Bar |
| %7 = begin_borrow %6 : $Bar |
| %8 = function_ref @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> () |
| apply %8(%5, %7, %4) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> () |
| end_borrow %7 from %6 : $Bar, $Bar |
| destroy_value %6 : $Bar |
| |
| %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Baz>, 0 |
| %9 = struct_element_addr %1a : $*Baz, #Baz.x |
| %10 = struct_element_addr %1a : $*Baz, #Baz.bar |
| %11 = load [trivial] %9 : $*Int |
| %12 = load [copy] %10 : $*Bar |
| %13 = load [copy] %10 : $*Bar |
| %14 = begin_borrow %13 : $Bar |
| %15 = function_ref @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> () |
| apply %15(%12, %14, %11) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> () |
| end_borrow %14 from %13 : $Bar, $Bar |
| destroy_value %13 : $Bar |
| |
| destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Baz> |
| destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Baz> |
| %t = tuple() |
| return %t : $() |
| } |