mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
rdar://149985633 Using at least Int8 here allows LLVM to apply more optimizations, reducing code size, avoiding stack allocations and as a result often eliminating complete stack frames.
341 lines
11 KiB
Plaintext
341 lines
11 KiB
Plaintext
// RUN: %empty-directory(%t)
|
|
// RUN: %{python} %utils/chex.py < %s > %t/moveonly_deinit.sil
|
|
// RUN: %target-swift-frontend -enable-experimental-feature MoveOnlyEnumDeinits -emit-ir %t/moveonly_deinit.sil | %FileCheck %t/moveonly_deinit.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
|
|
|
|
// REQUIRES: swift_feature_MoveOnlyEnumDeinits
|
|
|
|
// UNSUPPORTED: CPU=arm64e
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
// Check that box destructor invokes deinit for a captured move-only value.
|
|
// CHECK: @[[BOX_STRUCT_METADATA:[A-Za-z0-9_.]+]] = {{.*}} constant %swift.full_boxmetadata { ptr @[[BOX_STRUCT_DESTRUCTOR:[A-Za-z0-9_.]+]]
|
|
|
|
sil_stage canonical
|
|
|
|
class C {}
|
|
|
|
// CHECK-LABEL: @{{.*}}8MOStructVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, nontrivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0x81_0007>
|
|
// CHECK-32-SAME: <i32 0x81_0003>
|
|
struct MOStruct: ~Copyable {
|
|
var x: Int
|
|
var y: C
|
|
|
|
deinit
|
|
}
|
|
|
|
// CHECK-LABEL: @{{.*}}6MOEnumOWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, enum, nontrivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0xA1_0007>
|
|
// CHECK-32-SAME: <i32 0xA1_0003>
|
|
enum MOEnum: ~Copyable {
|
|
case x(Int)
|
|
case y(C)
|
|
|
|
deinit
|
|
}
|
|
|
|
// CHECK-LABEL: @{{.*}}13MOComboStructVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, non-inline, nontrivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0x83_0007>
|
|
// CHECK-32-SAME: <i32 0x83_0003>
|
|
struct MOComboStruct: ~Copyable {
|
|
var a: MOStruct
|
|
var b: MOEnum
|
|
var c: C
|
|
}
|
|
|
|
// CHECK-LABEL: @{{.*}}11MOComboEnumOWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, enum, nontrivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0xA1_0007>
|
|
// CHECK-32-SAME: <i32 0xA1_0003>
|
|
enum MOComboEnum: ~Copyable {
|
|
case a(MOStruct)
|
|
case b(MOEnum)
|
|
case c(C)
|
|
}
|
|
|
|
// Move-only types should not share value witnesses or box metadata with
|
|
// common layout types.
|
|
|
|
// CHECK-LABEL: @{{.*}}13MOEmptyStructVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, nontrivial deinit, byte aligned
|
|
// CHECK-SAME: <i32 0x81_0000>
|
|
struct MOEmptyStruct: ~Copyable {
|
|
deinit
|
|
}
|
|
|
|
// CHECK-LABEL: @{{.*}}15MOIntLikeStructVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, nontrivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0x81_0007>
|
|
// CHECK-32-SAME: <i32 0x81_0003>
|
|
struct MOIntLikeStruct: ~Copyable {
|
|
var x: Int
|
|
|
|
deinit
|
|
}
|
|
|
|
// CHECK-LABEL: @{{.*}}26MOSingleRefcountLikeStructVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, nontrivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0x81_0007>
|
|
// CHECK-32-SAME: <i32 0x81_0003>
|
|
struct MOSingleRefcountLikeStruct: ~Copyable {
|
|
var x: C
|
|
|
|
deinit
|
|
}
|
|
|
|
// Even if they don't have deinits, we shouldn't share a vwt.
|
|
|
|
// CHECK-LABEL: @{{.*}}21MOEmptyStructNoDeinitVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, trivial deinit, byte aligned
|
|
// CHECK-SAME: <i32 0x80_0000>
|
|
struct MOEmptyStructNoDeinit: ~Copyable {
|
|
}
|
|
|
|
// CHECK-LABEL: @{{.*}}23MOIntLikeStructNoDeinitVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, trivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0x80_0007>
|
|
// CHECK-32-SAME: <i32 0x80_0003>
|
|
struct MOIntLikeStructNoDeinit: ~Copyable {
|
|
var x: Int
|
|
}
|
|
|
|
// CHECK-LABEL: @{{.*}}34MOSingleRefcountLikeStructNoDeinitVWV" =
|
|
// CHECK-SAME: @__swift_cannot_copy_noncopyable_type
|
|
// noncopyable, nontrivial deinit, pointer aligned
|
|
// CHECK-64-SAME: <i32 0x81_0007>
|
|
// CHECK-32-SAME: <i32 0x81_0003>
|
|
struct MOSingleRefcountLikeStructNoDeinit: ~Copyable {
|
|
var x: C
|
|
}
|
|
|
|
// Type metadata records for noncopyable types should be in a separate list
|
|
// from copyable types.
|
|
|
|
// CHECK-LABEL: @"$s{{.*}}1CCHn" =
|
|
// CHECK-SAME: section "[[COPYABLE_SECTION_NAME:[^"]+]]"
|
|
|
|
// CHECK-NOT: @"$s{{.*}}8MOStructVHn" = {{.*}} section "[[COPYABLE_SECTION_NAME]]"
|
|
|
|
// CHECK-LABEL: @"$s{{.*}}8MOStructVHn" =
|
|
// CHECK-SAME: section "[[NONCOPYABLE_SECTION_NAME:[^"]+]]"
|
|
|
|
// CHECK-LABEL: @"$s{{.*}}6MOEnumOHn" =
|
|
// CHECK-SAME: section "[[NONCOPYABLE_SECTION_NAME]]"
|
|
|
|
// Very large structs will use indirect conventions for their deinit.
|
|
|
|
struct MOVeryBigStructDeinit: ~Copyable {
|
|
var x: Int, y: Int, z: Int, w: Int, a: Int, b: Int, c: Int, d: Int
|
|
|
|
deinit
|
|
}
|
|
|
|
// Generic structs have equally generic deinits.
|
|
|
|
protocol P {}
|
|
extension Int: P {}
|
|
|
|
struct MOGenericDeinit<T: P, U>: ~Copyable {
|
|
var t: T
|
|
var u: U
|
|
|
|
deinit
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_struct_value(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: call{{.*}}@destroy_struct(
|
|
// CHECK-NEXT: ret void
|
|
sil @destroy_struct_value : $@convention(thin) (@owned MOStruct) -> () {
|
|
entry(%b : $MOStruct):
|
|
release_value %b : $MOStruct
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_struct_value_indirect(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: call{{.*}}@destroy_struct(
|
|
// CHECK-NEXT: ret void
|
|
sil @destroy_struct_value_indirect : $@convention(thin) (@in MOStruct) -> () {
|
|
entry(%b : $*MOStruct):
|
|
destroy_addr %b : $*MOStruct
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_enum_value(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: call{{.*}}@destroy_enum(
|
|
// CHECK-NEXT: ret void
|
|
sil @destroy_enum_value : $@convention(thin) (@owned MOEnum) -> () {
|
|
entry(%b : $MOEnum):
|
|
release_value %b : $MOEnum
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_enum_value_indirect(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: getelementptr
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: call{{.*}}@destroy_enum(
|
|
// CHECK-NEXT: ret void
|
|
sil @destroy_enum_value_indirect : $@convention(thin) (@in MOEnum) -> () {
|
|
entry(%b : $*MOEnum):
|
|
destroy_addr %b : $*MOEnum
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_combo_struct_value(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK-NEXT: call {{.*}} @[[COMBO_STRUCT_OUTLINED_DESTROY:"\$.*13MOComboStructVWOh"]](
|
|
// CHECK-NEXT: ret void
|
|
sil @destroy_combo_struct_value : $@convention(thin) (@owned MOComboStruct) -> () {
|
|
entry(%b : $MOComboStruct):
|
|
release_value %b : $MOComboStruct
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK: define{{.*}}@[[COMBO_STRUCT_OUTLINED_DESTROY]](
|
|
// CHECK: call {{.*}} @destroy_struct
|
|
// CHECK: call {{.*}} @destroy_enum
|
|
// CHECK: call {{.*}} @swift_release
|
|
// CHECK: ret {{.*}} %0
|
|
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_combo_enum_value(
|
|
// CHECK-NEXT: entry:
|
|
// CHECK: call {{.*}} @[[COMBO_ENUM_OUTLINED_DESTROY:"\$.*11MOComboEnumOWOe"]](
|
|
// CHECK-NEXT: ret void
|
|
sil @destroy_combo_enum_value : $@convention(thin) (@owned MOComboEnum) -> () {
|
|
entry(%b : $MOComboEnum):
|
|
release_value %b : $MOComboEnum
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK: define{{.*}}@[[COMBO_ENUM_OUTLINED_DESTROY]](
|
|
// CHECK: switch
|
|
// CHECK-NEXT: i8 0, label %[[STRUCT:[0-9]+]]
|
|
// CHECK-NEXT: i8 1, label %[[ENUM:[0-9]+]]
|
|
// CHECK-NEXT: i8 2, label %[[CLASS:[0-9]+]]
|
|
// CHECK: [[STRUCT]]:
|
|
// CHECK: call {{.*}} @destroy_struct
|
|
// CHECK: [[ENUM]]:
|
|
// CHECK: call {{.*}} @destroy_enum
|
|
// CHECK: [[CLASS]]:
|
|
// CHECK: call {{.*}} @swift_release
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_very_big_direct(
|
|
// CHECK: call {{.*}} @destroy_big(
|
|
sil @destroy_very_big_direct : $@convention(thin) (@owned MOVeryBigStructDeinit) -> () {
|
|
entry(%b : $MOVeryBigStructDeinit):
|
|
release_value %b : $MOVeryBigStructDeinit
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_very_big_indirect(
|
|
// CHECK: call {{.*}} @destroy_big(
|
|
sil @destroy_very_big_indirect : $@convention(thin) (@in MOVeryBigStructDeinit) -> () {
|
|
entry(%b : $*MOVeryBigStructDeinit):
|
|
destroy_addr %b : $*MOVeryBigStructDeinit
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_generic_instance_t(
|
|
// CHECK: call {{.*}} @destroy_generic(
|
|
sil @destroy_generic_instance_t : $@convention(thin) (@owned MOGenericDeinit<Int, Int>) -> () {
|
|
entry(%b : $MOGenericDeinit<Int, Int>):
|
|
release_value %b : $MOGenericDeinit<Int, Int>
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_generic_instance_nt(
|
|
// CHECK: call {{.*}} @destroy_generic(
|
|
sil @destroy_generic_instance_nt : $@convention(thin) (@owned MOGenericDeinit<Int, C>) -> () {
|
|
entry(%b : $MOGenericDeinit<Int, C>):
|
|
release_value %b : $MOGenericDeinit<Int, C>
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@destroy_generic_poly(
|
|
// CHECK: call {{.*}} @destroy_generic(
|
|
sil @destroy_generic_poly : $@convention(thin) <U, T: P> (@in MOGenericDeinit<T, U>) -> () {
|
|
entry(%b : $*MOGenericDeinit<T, U>):
|
|
destroy_addr %b : $*MOGenericDeinit<T, U>
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{.*}}@box_struct(
|
|
// CHECK: call {{.*}} @swift_allocObject({{.*}} ptr @[[BOX_STRUCT_METADATA]],
|
|
|
|
// CHECK: define{{.*}}@[[BOX_STRUCT_DESTRUCTOR]](
|
|
// CHECK: call {{.*}} @destroy_struct
|
|
// CHECK: call {{.*}} @destroy_enum
|
|
// CHECK: call {{.*}} @swift_release
|
|
sil @box_struct : $@convention(thin) (@owned MOComboStruct) -> Builtin.NativeObject {
|
|
entry(%0 : $MOComboStruct):
|
|
%b = alloc_box ${ var MOComboStruct }
|
|
%p = project_box %b : ${ var MOComboStruct }, 0
|
|
store %0 to %p : $*MOComboStruct
|
|
%r = unchecked_ref_cast %b : ${ var MOComboStruct } to $Builtin.NativeObject
|
|
return %r : $Builtin.NativeObject
|
|
}
|
|
|
|
sil @destroy_struct : $@convention(method) (@owned MOStruct) -> ()
|
|
sil @destroy_enum : $@convention(method) (@owned MOEnum) -> ()
|
|
sil @destroy_intlike_struct : $@convention(method) (@owned MOIntLikeStruct) -> ()
|
|
sil @destroy_empty_struct : $@convention(method) (@owned MOEmptyStruct) -> ()
|
|
sil @destroy_single_refcount_like_struct : $@convention(method) (@owned MOSingleRefcountLikeStruct) -> ()
|
|
|
|
sil @destroy_big : $@convention(method) (@in MOVeryBigStructDeinit) -> ()
|
|
sil @destroy_generic : $@convention(method) <T: P, U> (@in MOGenericDeinit<T, U>) -> ()
|
|
|
|
sil_vtable C {}
|
|
|
|
sil_moveonlydeinit MOStruct { @destroy_struct }
|
|
sil_moveonlydeinit MOEnum { @destroy_enum }
|
|
sil_moveonlydeinit MOEmptyStruct { @destroy_empty_struct }
|
|
sil_moveonlydeinit MOIntLikeStruct { @destroy_intlike_struct }
|
|
sil_moveonlydeinit MOSingleRefcountLikeStruct { @destroy_single_refcount_like_struct }
|
|
sil_moveonlydeinit MOVeryBigStructDeinit { @destroy_big }
|
|
sil_moveonlydeinit MOGenericDeinit { @destroy_generic }
|
|
|
|
// Check that destroy value witnesses invoke the deinit function, either
|
|
// indirectly or directly.
|
|
|
|
// CHECK-LABEL: define {{.*}} @"{{.*}}8MOStructVwxx"
|
|
// CHECK: call {{.*}} @destroy_struct(
|
|
// CHECK-LABEL: define {{.*}} @"{{.*}}6MOEnumOwxx"
|
|
// CHECK: call {{.*}} @destroy_enum(
|
|
// CHECK-LABEL: define {{.*}} @"{{.*}}13MOComboStructVwxx"
|
|
// CHECK: call {{.*}} @destroy_struct(
|
|
// CHECK: call {{.*}} @destroy_enum(
|
|
// CHECK: call {{.*}} @swift_release
|
|
// CHECK-LABEL: define {{.*}} @"{{.*}}11MOComboEnumOwxx"
|
|
// CHECK: call {{.*}} @[[COMBO_ENUM_OUTLINED_DESTROY]]
|
|
|
|
// CHECK-LABEL: define {{.*}} @"{{.*}}13MOEmptyStructVwxx"
|
|
// CHECK: call {{.*}} @destroy_empty_struct(
|
|
// CHECK-LABEL: define {{.*}} @"{{.*}}15MOIntLikeStructVwxx"
|
|
// CHECK: call {{.*}} @destroy_intlike_struct(
|
|
// CHECK-LABEL: define {{.*}} @"{{.*}}26MOSingleRefcountLikeStructVwxx"
|
|
// CHECK: call {{.*}} @destroy_single_refcount_like_struct(
|