| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -capture-promotion | %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 |
| |
| // CHECK-LABEL: sil @test_capture_promotion |
| sil @test_capture_promotion : $@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 %1a : $*Foo |
| %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 %6a : $*Baz |
| %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 %11a : $*Int |
| |
| // CHECK-NOT: function_ref @closure0 : |
| // CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @$S8closure0Tf2iii_n |
| // CHECK-NOT: function_ref @closure0 : |
| |
| // The three strong retains are removed |
| |
| // The Foo variable is loaded from and retained, because it is a reference type |
| // CHECK-NEXT: [[LOADFOO:%.*]] = load {{.*}} : $*Foo |
| // CHECK-NEXT: strong_retain [[LOADFOO]] : $Foo |
| |
| // The Baz variable is loaded and retain_value'd, because it is a non-trivial |
| // aggregate type |
| // CHECK-NEXT: [[LOADBAZ:%.*]] = load {{.*}} : $*Baz |
| // CHECK-NEXT: retain_value [[LOADBAZ:%.*]] : $Baz |
| |
| // The Int variable is loaded only, because it is trivial |
| // CHECK-NEXT: [[LOADINT:%.*]] = load {{.*}} : $*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]]) |
| |
| %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 |
| strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| strong_retain %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_retain %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| %21 = partial_apply %17(%1, %6, %11) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Foo>, @owned <τ_0_0> { var τ_0_0 } <Baz>, @owned <τ_0_0> { var τ_0_0 } <Int>) -> Int |
| |
| strong_release %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| strong_release %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_release %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| |
| return %21 : $@callee_owned () -> Int |
| } |
| |
| // CHECK-LABEL: sil @test_capture_promotion_indirect |
| sil @test_capture_promotion_indirect : $@convention(thin) () -> @owned @callee_owned () -> @out 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 %1a : $*Foo |
| %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 %6a : $*Baz |
| %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 %11a : $*Int |
| |
| // CHECK-NOT: function_ref @closure_indirect_result : |
| // CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @$S23closure_indirect_resultTf2niii_n |
| // CHECK-NOT: function_ref @closure_indirect_result : |
| |
| // The three strong retains are removed |
| |
| // The Foo variable is loaded from and retained, because it is a reference type |
| // CHECK-NEXT: [[LOADFOO:%.*]] = load {{.*}} : $*Foo |
| // CHECK-NEXT: strong_retain [[LOADFOO]] : $Foo |
| |
| // The Baz variable is loaded and retain_value'd, because it is a non-trivial |
| // aggregate type |
| // CHECK-NEXT: [[LOADBAZ:%.*]] = load {{.*}} : $*Baz |
| // CHECK-NEXT: retain_value [[LOADBAZ:%.*]] : $Baz |
| |
| // The Int variable is loaded only, because it is trivial |
| // CHECK-NEXT: [[LOADINT:%.*]] = load {{.*}} : $*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]]) |
| |
| |
| %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 |
| strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| strong_retain %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_retain %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| %21 = partial_apply %17(%1, %6, %11) : $@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 |
| |
| strong_release %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| strong_release %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_release %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 |
| // CHECK: [[DUMMY_FUNC:%.*]] = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int |
| |
| // The load of %1 is removed, and its uses replaced with the Foo argument |
| // CHECK-NEXT: strong_retain {{.*}} : $Foo |
| // CHECK-NEXT: [[METHOD_FOO:%.*]] = class_method {{.*}} : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| // CHECK-NEXT: [[APPLY_FOO:%.*]] = apply [[METHOD_FOO]]({{.*}}) : $@convention(method) (@guaranteed Foo) -> Int |
| |
| // The struct_element_addr of %3 followed by a load is replaced by a struct_extract of the Baz argument |
| // CHECK-NEXT: [[EXTRACT_BAZ_X:%.*]] = struct_extract {{.*}} : $Baz, #Baz.x |
| |
| // CHECK-NEXT: [[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-NEXT: release_value {{.*}} : $Baz |
| |
| // The release of %0 is replaced by a strong_release of the Foo argument, since |
| // it is a reference type |
| // CHECK-NEXT: strong_release {{.*}} : $Foo |
| |
| // CHECK-NEXT: return [[RETVAL]] : $Int |
| |
| 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 { |
| bb0(%0 : $<τ_0_0> { var τ_0_0 } <Foo>, %2 : $<τ_0_0> { var τ_0_0 } <Baz>, %4 : $<τ_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 %1 : $*Foo |
| strong_retain %8 : $Foo |
| %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| %11 = apply %10(%8) : $@convention(method) (@guaranteed Foo) -> Int |
| %12 = struct_element_addr %3 : $*Baz, #Baz.x |
| %13 = load %12 : $*Int |
| %14 = load %5 : $*Int |
| %15 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int |
| strong_release %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| strong_release %2 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_release %0 : $<τ_0_0> { var τ_0_0 } <Foo> |
| return %15 : $Int |
| } |
| |
| // 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 %1a : $*Foo |
| %17 = function_ref @closure1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Foo>) -> Int |
| strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| // CHECK: partial_apply {{%.*}}({{%.*}}) |
| %21 = partial_apply %17(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Foo>) -> Int |
| strong_release %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| return %21 : $@callee_owned () -> Int |
| } |
| |
| sil @mutate_foo : $@convention(thin) (@inout Foo) -> () |
| |
| sil private @closure1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Foo>) -> Int { |
| bb0(%0 : $<τ_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 %1 : $*Foo |
| strong_retain %8 : $Foo |
| %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| %11 = apply %10(%8) : $@convention(method) (@guaranteed Foo) -> Int |
| %12 = function_ref @mutate_foo : $@convention(thin) (@inout Foo) -> () |
| %13 = apply %12(%1) : $@convention(thin) (@inout Foo) -> () |
| strong_release %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 : $*Int, %1 : $*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>) -> () |
| strong_retain %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| strong_retain %2 : $<τ_0_0> { var τ_0_0 } <Int> |
| // CHECK: partial_apply [[PROMOTED]]<{{[^>]+}}>( |
| %10 = partial_apply %7<T>(%4, %2) : $@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 |
| strong_release %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| copy_addr %2a to %0 : $*Int |
| strong_release %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 : $<τ_0_0> { var τ_0_0 } <Int>, %2 : $<τ_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 %3 : $*Int |
| %6 = load %3 : $*Int |
| %7 = apply %4(%5, %6) : $@convention(thin) (Int, Int) -> Int |
| assign %7 to %1 : $*Int |
| strong_release %2 : $<τ_0_0> { var τ_0_0 } <Int> |
| strong_release %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: $*Int, %1 : $<τ_0_0> { var τ_0_0 } <Foo>, %2 : $<τ_0_0> { var τ_0_0 } <Baz>, %4 : $<τ_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 |
| %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 %17 : $*Foo |
| strong_retain %8 : $Foo |
| %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| %11 = apply %10(%8) : $@convention(method) (@guaranteed Foo) -> Int |
| %12 = struct_element_addr %3 : $*Baz, #Baz.x |
| %13 = load %12 : $*Int |
| %14 = load %5 : $*Int |
| %15 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int |
| strong_release %4 : $<τ_0_0> { var τ_0_0 } <Int> |
| strong_release %2 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_release %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| store %15 to %0 : $*Int |
| %16 = tuple() |
| return %16 : $() |
| } |
| |
| // CHECK-LABEL: sil @test_with_dynamic_self |
| // CHECK: %{{[0-9]+}} = partial_apply %{{[0-9]+}}(%{{[0-9]+}}, %{{[0-9]+}}) : $@convention(thin) (Int, @thick @dynamic_self Bar.Type) -> () // type-defs: %1 |
| // CHECK: return |
| sil @test_with_dynamic_self : $@convention(method) (Int, @guaranteed Bar) -> () { |
| bb0(%0 : $Int, %1 : $Bar): |
| %4 = alloc_box ${ var Int }, var, name "item" |
| %5 = project_box %4 : ${ var Int }, 0 |
| store %0 to %5 : $*Int |
| %17 = function_ref @closure_with_dynamic_self : $@convention(thin) (@owned { var Int }, @thick @dynamic_self Bar.Type) -> () |
| %21 = metatype $@thick @dynamic_self Bar.Type |
| %26 = partial_apply %17(%4, %21) : $@convention(thin) (@owned { var Int }, @thick @dynamic_self Bar.Type) -> () |
| %39 = tuple () |
| return %39 : $() |
| } |
| |
| sil private @closure_with_dynamic_self : $@convention(thin) (@owned { var Int }, @thick @dynamic_self Bar.Type) -> () { |
| bb0(%1 : ${ var Int }, %2 : $@thick @dynamic_self Bar.Type): |
| strong_release %1 : ${ var Int } |
| %39 = tuple () |
| return %39 : $() |
| } |
| // CHECK-LABEL: sil private @$S19closure0_guaranteedTf2iii_n : $@convention(thin) (@guaranteed Foo, @guaranteed Baz, Int) -> Int |
| // CHECK-NOT: project_box |
| // CHECK: [[X:%.*]] = struct_extract %1 : $Baz, #Baz.x |
| // CHECK: [[R:%.*]] = apply {{.*}}({{.*}}, [[X]], %2) : $@convention(thin) (Int, Int, Int) -> Int |
| // CHECK: return [[R]] : $Int |
| |
| sil private @closure0_guaranteed : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Foo>, @guaranteed <τ_0_0> { var τ_0_0 } <Baz>, @guaranteed <τ_0_0> { var τ_0_0 } <Int>) -> Int { |
| bb0(%0 : $<τ_0_0> { var τ_0_0 } <Foo>, %2 : $<τ_0_0> { var τ_0_0 } <Baz>, %4 : $<τ_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 () |
| %7 = function_ref @dummy_func : $@convention(thin) (Int, Int, Int) -> Int |
| %8 = load %1 : $*Foo |
| strong_retain %8 : $Foo |
| %10 = class_method %8 : $Foo, #Foo.foo!1 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int |
| %11 = apply %10(%8) : $@convention(method) (@guaranteed Foo) -> Int |
| %12 = struct_element_addr %3 : $*Baz, #Baz.x |
| %13 = load %12 : $*Int |
| %14 = load %5 : $*Int |
| %15 = apply %7(%11, %13, %14) : $@convention(thin) (Int, Int, Int) -> Int |
| return %15 : $Int |
| } |
| |
| sil @test_capture_promotion_guaranteed : $@convention(thin) () -> @owned @callee_guaranteed () -> 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 %1a : $*Foo |
| %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 %6a : $*Baz |
| %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 %11a : $*Int |
| |
| // CHECK-NOT: function_ref @closure0_guaranteed |
| // CHECK: [[CLOSURE_PROMOTE:%.*]] = function_ref @$S19closure0_guaranteedTf2iii_n |
| // CHECK-NOT: function_ref @closure0_guaranteed |
| |
| // The three strong retains are removed |
| |
| // The Foo variable is loaded from and retained, because it is a reference type |
| // CHECK-NEXT: [[LOADFOO:%.*]] = load {{.*}} : $*Foo |
| // CHECK-NEXT: strong_retain [[LOADFOO]] : $Foo |
| |
| // The Baz variable is loaded and retain_value'd, because it is a non-trivial |
| // aggregate type |
| // CHECK-NEXT: [[LOADBAZ:%.*]] = load {{.*}} : $*Baz |
| // CHECK-NEXT: retain_value [[LOADBAZ:%.*]] : $Baz |
| |
| // The Int variable is loaded only, because it is trivial |
| // CHECK-NEXT: [[LOADINT:%.*]] = load {{.*}} : $*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 [callee_guaranteed] [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]]) |
| |
| %17 = function_ref @closure0_guaranteed : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Foo>, @guaranteed <τ_0_0> { var τ_0_0 } <Baz>, @guaranteed <τ_0_0> { var τ_0_0 } <Int>) -> Int |
| strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| strong_retain %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_retain %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| %21 = partial_apply [callee_guaranteed] %17(%1, %6, %11) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Foo>, @guaranteed <τ_0_0> { var τ_0_0 } <Baz>, @guaranteed <τ_0_0> { var τ_0_0 } <Int>) -> Int |
| |
| strong_release %11 : $<τ_0_0> { var τ_0_0 } <Int> |
| strong_release %6 : $<τ_0_0> { var τ_0_0 } <Baz> |
| strong_release %1 : $<τ_0_0> { var τ_0_0 } <Foo> |
| |
| return %21 : $@callee_guaranteed () -> Int |
| } |