mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
556 lines
28 KiB
Plaintext
556 lines
28 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all %s -capture-promotion \
|
|
// RUN: -enable-experimental-feature NonescapableTypes -module-name Swift \
|
|
// RUN: | %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
|
|
}
|
|
|
|
@_marker public protocol Escapable { }
|
|
|
|
struct Nonescapable: ~Escapable {}
|
|
|
|
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) -> ()
|
|
sil @guaranteed_nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_capture_promotion
|
|
sil [ossa] @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 [ossa] @test_capture_promotion_indirect
|
|
sil [ossa] @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 [ossa] @$s8closure0Tf2iii_n : $@convention(thin) (@owned Foo, @owned Baz, Int) -> (Int, Builtin.Int64) {
|
|
// CHECK: bb0([[ORIGINAL_ARG0:%.*]] : @owned $Foo, [[ORIGINAL_ARG1:%.*]] : @owned $Baz, [[ARG2:%.*]] : $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 : (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]]
|
|
// 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]]
|
|
// 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]]
|
|
// 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 [ossa] @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 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
|
|
%9 = begin_borrow %8 : $Foo
|
|
%11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
|
|
end_borrow %9 : $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 [ossa] @test_unpromotable
|
|
sil [ossa] @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 [ossa] @mutate_foo : $@convention(thin) (@inout Foo) -> ()
|
|
|
|
sil private [ossa] @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 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
|
|
%9 = begin_borrow %8 : $Foo
|
|
%11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
|
|
end_borrow %9 : $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 [ossa] @apply : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @captureWithinGeneric
|
|
sil [ossa] @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 [init] %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 [init] %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 [ossa] @$s27closureWithGenericSignatureTf2ni_n : $@convention(thin) <{{[^>]+}}> (@owned <τ_0_0> { var τ_0_0 } <Int>, Int) -> ()
|
|
sil [ossa] @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 [ossa] @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 : @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 : (Foo) -> () -> Int, $@convention(method) (@guaranteed Foo) -> Int
|
|
%9 = begin_borrow %8 : $Foo
|
|
%11 = apply %10(%9) : $@convention(method) (@guaranteed Foo) -> Int
|
|
end_borrow %9 : $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 [ossa] @mutate_int : $@convention(thin) (@inout Int) -> ()
|
|
|
|
// CHECK-LABEL: sil [ossa] @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 [ossa] @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 [ossa] @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 [ossa] @test_capture_projection_test : $@convention(thin) () -> @owned @callee_owned () -> () {
|
|
sil [ossa] @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 [ossa] @$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: [[BAR_COPY_2:%.*]] = copy_value [[BAR_COPY]]
|
|
// CHECK: [[BAR2:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.bar
|
|
// CHECK: [[BAR2_COPY:%.*]] = copy_value [[BAR2]]
|
|
// CHECK: [[BAR2_COPY_BORROW:%.*]] = begin_borrow [[BAR2_COPY]]
|
|
// CHECK: [[LOAD_BORROW_EXT:%.*]] = struct_extract [[BORROWED_BAZ]]
|
|
// CHECK: apply {{%.*}}([[BAR_COPY]], [[BAR2_COPY_BORROW]], [[X]])
|
|
// CHECK: apply {{%.*}}([[BAR_COPY_2]], [[LOAD_BORROW_EXT]], [[X]])
|
|
// CHECK: end_borrow [[BAR2_COPY_BORROW]]
|
|
// CHECK: destroy_value [[BAR2_COPY]]
|
|
// CHECK: end_borrow [[BORROWED_BAZ]]
|
|
// CHECK: destroy_value [[BAZ]]
|
|
// CHECK: } // end sil function '$s23closure_projection_testTf2ni_n'
|
|
sil [ossa] @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 : $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
|
|
%10a = struct_element_addr %1a : $*Baz, #Baz.bar
|
|
%11 = load [trivial] %9 : $*Int
|
|
%12 = load [copy] %10 : $*Bar
|
|
%12a = copy_value %12 : $Bar
|
|
%13 = load [copy] %10 : $*Bar
|
|
%14 = begin_borrow %13 : $Bar
|
|
%15 = function_ref @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
|
|
%16 = load_borrow %10a : $*Bar
|
|
apply %15(%12, %14, %11) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
|
|
apply %15(%12a, %16, %11) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
|
|
end_borrow %16 : $Bar
|
|
end_borrow %14 : $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 : $()
|
|
}
|
|
|
|
|
|
|
|
// Make sure that we properly handle guaranteed arguments when specializing here.
|
|
sil [ossa] @capture_promotion_callee_guaranteed_box : $@convention(thin) (@guaranteed { var Builtin.NativeObject }) -> () {
|
|
bb0(%0 : @guaranteed ${ var Builtin.NativeObject }):
|
|
%1 = project_box %0 : ${ var Builtin.NativeObject }, 0
|
|
%2 = begin_access [read] [unknown] %1 : $*Builtin.NativeObject
|
|
%3 = load [copy] %2 : $*Builtin.NativeObject
|
|
end_access %2 : $*Builtin.NativeObject
|
|
%4 = function_ref @guaranteed_nativeobject_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
destroy_value %3 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Just make sure that we specialized so that the ownership verifier can make
|
|
// sure we emitted ownership correctly.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @capture_promotion_caller_guaranteed_box : $@convention(thin) (@owned Builtin.NativeObject) -> @owned @callee_owned () -> () {
|
|
// CHECK: [[FUNC_REF:%.*]] = function_ref @$s39capture_promotion_callee_guaranteed_boxTf2i_n :
|
|
// CHECK: apply [[FUNC_REF]](
|
|
// CHECK: } // end sil function 'capture_promotion_caller_guaranteed_box'
|
|
sil [ossa] @capture_promotion_caller_guaranteed_box : $@convention(thin) (@owned Builtin.NativeObject) -> @owned @callee_owned () -> () {
|
|
bb0(%0 : @owned $Builtin.NativeObject):
|
|
%1 = alloc_box ${ var Builtin.NativeObject }
|
|
%2 = project_box %1 : ${ var Builtin.NativeObject }, 0
|
|
store %0 to [init] %2 : $*Builtin.NativeObject
|
|
%3 = function_ref @capture_promotion_callee_guaranteed_box : $@convention(thin) (@guaranteed { var Builtin.NativeObject }) -> ()
|
|
%pai = partial_apply %3(%1) : $@convention(thin) (@guaranteed { var Builtin.NativeObject }) -> ()
|
|
return %pai : $@callee_owned () -> ()
|
|
}
|
|
|
|
sil @foo_dependence : $@convention(thin) (@guaranteed Foo) -> _scope(0) @owned Nonescapable
|
|
sil @use_nonescapable : $@convention(thin) (@guaranteed Nonescapable) -> ()
|
|
|
|
// Test that the pass does not crash when it sees a mark_dependence on an alloc_box base that does not have a partial_apply value.
|
|
sil [ossa] @test_capture_promotion_mark_dependence : $@convention(thin) () -> () {
|
|
bb0:
|
|
%6 = alloc_box ${ let Foo }, let, name "c"
|
|
%7 = begin_borrow [lexical] [var_decl] %6 : ${ let Foo }
|
|
%8 = project_box %7 : ${ let Foo }, 0
|
|
%9 = metatype $@thick Foo.Type
|
|
|
|
%12 = function_ref @foo_allocating_init : $@convention(thin) (@thick Foo.Type) -> @owned Foo
|
|
%13 = apply %12(%9) : $@convention(thin) (@thick Foo.Type) -> @owned Foo
|
|
store %13 to [init] %8 : $*Foo
|
|
%16 = load_borrow %8 : $*Foo
|
|
|
|
%17 = function_ref @foo_dependence : $@convention(thin) (@guaranteed Foo) -> _scope(0) @owned Nonescapable
|
|
%18 = apply %17(%16) : $@convention(thin) (@guaranteed Foo) -> _scope(0) @owned Nonescapable
|
|
|
|
%19 = mark_dependence [unresolved] %18 : $Nonescapable on %6 : ${ let Foo }
|
|
%20 = move_value [var_decl] %19 : $Nonescapable
|
|
end_borrow %16 : $Foo
|
|
|
|
%23 = function_ref @use_nonescapable : $@convention(thin) (@guaranteed Nonescapable) -> ()
|
|
%24 = apply %23(%20) : $@convention(thin) (@guaranteed Nonescapable) -> ()
|
|
destroy_value %20 : $Nonescapable
|
|
end_borrow %7 : ${ let Foo }
|
|
|
|
destroy_value %6 : ${ let Foo }
|
|
%28 = tuple ()
|
|
return %28 : $()
|
|
}
|