mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This was never used to generate a .swiftinterface, so can be safely removed. It was used to guard compiler fixes that might break older .swiftinterface files. Now, we guard the same fixes by checking the source file type.
593 lines
29 KiB
Plaintext
593 lines
29 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -capture-promotion \
|
|
// RUN: -enable-experimental-feature LifetimeDependence \
|
|
// RUN: -module-name Swift \
|
|
// RUN: | %FileCheck %s
|
|
|
|
// REQUIRES: swift_feature_LifetimeDependence
|
|
|
|
// 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
|
|
}
|
|
|
|
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) -> @lifetime(borrow 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) -> @lifetime(borrow 0) @owned Nonescapable
|
|
%18 = apply %17(%16) : $@convention(thin) (@guaranteed Foo) -> @lifetime(borrow 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 : $()
|
|
}
|
|
|
|
sil [ossa] @closable : $@convention(thin) (@guaranteed { var Bar }) -> Builtin.Int64 {
|
|
entry(%box : @guaranteed ${ var Bar }):
|
|
%retval = integer_literal $Builtin.Int64, 0
|
|
return %retval : $Builtin.Int64
|
|
}
|
|
|
|
// Test that a dealloc_box is not regarded as a mutation which would obstruct promotion.
|
|
// CHECK-LABEL: sil [ossa] @with_dealloc_box : {{.*}} {
|
|
// CHECK: load [copy]
|
|
// CHECK-LABEL: } // end sil function 'with_dealloc_box'
|
|
sil [ossa] @with_dealloc_box : $@convention(thin) (@owned Bar) -> () {
|
|
entry(%idle_incoming : @owned $Bar):
|
|
%box = alloc_box ${ var Bar }
|
|
%box_borrow = begin_borrow [var_decl] %box : ${ var Bar }
|
|
%box_addr = project_box %box_borrow : ${ var Bar }, 0
|
|
store %idle_incoming to [init] %box_addr : $*Bar
|
|
%closable = function_ref @closable : $@convention(thin) (@guaranteed { var Bar }) -> Builtin.Int64
|
|
%box_copy = copy_value %box_borrow : ${ var Bar }
|
|
mark_function_escape %box_addr : $*Bar
|
|
%closure = partial_apply [callee_guaranteed] %closable(%box_copy) : $@convention(thin) (@guaranteed { var Bar }) -> Builtin.Int64
|
|
cond_br undef, exit, die
|
|
|
|
die:
|
|
destroy_value %closure : $@callee_guaranteed () -> Builtin.Int64
|
|
end_borrow %box_borrow : ${ var Bar }
|
|
dealloc_box %box : ${ var Bar }
|
|
unreachable
|
|
|
|
exit:
|
|
destroy_value %closure : $@callee_guaranteed () -> Builtin.Int64
|
|
end_borrow %box_borrow : ${ var Bar }
|
|
destroy_value %box : ${ var Bar }
|
|
%retval = tuple ()
|
|
return %retval :$()
|
|
}
|