Files
swift-mirror/test/IRGen/moveonly_deinit.sil
Dario Rexin 48ee212303 [IRGen] Use at least Int8 for extra tag bits
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.
2025-04-30 15:55:17 -07:00

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(