blob: 839d794e4b7825e4402f7a2186bce84d159d5a8e [file] [log] [blame]
// RUN: %target-sil-opt -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
}
// CHECK-LABEL: sil @test_capture_promotion_on_stack
sil @test_capture_promotion_on_stack : $@convention(thin) () -> () {
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 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: [[PA:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[CLOSURE_PROMOTE]]([[LOADFOO]], [[LOADBAZ]], [[LOADINT]])
// CHECK-NEXT: [[MD1:%.*]] = mark_dependence [[PA]] : $@noescape @callee_guaranteed () -> Int on [[LOADFOO]] : $Foo
// CHECK-NEXT: [[MD2:%.*]] = mark_dependence [[MD1]] : $@noescape @callee_guaranteed () -> Int on [[LOADBAZ]] : $Baz
// CHECK-NEXT: apply [[MD2]]() : $@noescape @callee_guaranteed () -> Int
// CHECK-NEXT: dealloc_stack [[PA]] : $@noescape @callee_guaranteed () -> Int
// CHECK-NEXT: strong_release [[LOADFOO]] : $Foo
// CHECK-NEXT: release_value [[LOADBAZ]] : $Baz
// CHECK-NEXT: strong_release {{.*}} : $<τ_0_0> { var τ_0_0 } <Int>
// CHECK-NEXT: strong_release {{.*}} : $<τ_0_0> { var τ_0_0 } <Baz>
// CHECK-NEXT: strong_release {{.*}} : $<τ_0_0> { var τ_0_0 } <Foo>
%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
%21 = partial_apply [callee_guaranteed] [on_stack] %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
%md = mark_dependence %21 :$@noescape @callee_guaranteed () -> Int on %1 : $_0_0> { var τ_0_0 } <Foo>
%md2 = mark_dependence %md :$@noescape @callee_guaranteed () -> Int on %6 : $_0_0> { var τ_0_0 } <Baz>
%md3 = mark_dependence %md2 :$@noescape @callee_guaranteed () -> Int on %11 : $_0_0> { var τ_0_0 } <Int>
apply %md3() : $@noescape @callee_guaranteed () -> Int
dealloc_stack %21 : $@noescape @callee_guaranteed () -> 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>
%tuple = tuple()
return %tuple : $()
}