Files
swift-mirror/test/IRGen/generic_structs.sil
Nate Chandler 2b50150e61 [metadata prespecialization] Zero trailing flags.
Previously, the trailing flags field of runtime instantiated generic
metadata for types which had prespecialization enabled were not zeroed.
Consequently, the field always contained garbage.  Often, metadata was
instantiated on new (and so, zeroed) pages, so the garbage happened to
be zero as is appropriate.  However, when the metadata was instantiated
on pages which had previously been dirtied, the garbage value would
sometimes indicate that the metadata was canonical statically
specialized.  When that occurred, swift_checkMetadataState would
incorrectly return a metadata state of complete, despite the fact that
the metadata might not in fact be complete.  As a result, the runtime
was trafficking in incomplete metadata as if it were complete, resulting
in various crashes that would arise from for example missing a witness
table or a value witness table.

Here the problem is corrected.  The trailing flags field of structs and
enums that have the field is set to 0.

For structs, this is accomplished by modifying the extra data pattern to
exist not only when there is fixed type info for the type but also when
the type is being prespecialized.  Specifically, the extra data for a
struct is, rather than an i32 array of field offsets, a struct
consisting of none, one, or both of the following: (1) the array of
field offsets, (2) the trailing flags.

Similarly, enums now have an extra data pattern which consists of none,
one, or both of the following: (1) the payload size, (2) the trailing
flags.  Enum metadata extra data setting was previously achieved by
customizing the metadata allocation function; that customization is now
eliminated, being replaced with the shared runtime code for copying
extra data into place, a modest code size savings.

rdar://problem/61465515
2020-04-23 18:18:40 -07:00

262 lines
12 KiB
Plaintext

// RUN: %empty-directory(%t)
// RUN: %{python} %utils/chex.py < %s > %t/generic_structs.sil
// RUN: %target-swift-frontend -disable-type-layout -disable-generic-metadata-prespecialization %t/generic_structs.sil -emit-ir | %FileCheck %t/generic_structs.sil
// REQUIRES: CPU=x86_64
import Builtin
// -- Generic structs with fixed layout should have no completion function
// and emit the field offset vector as part of the pattern.
// CHECK: [[PATTERN:@.*]] = internal constant { i32, i32, i32, [4 x i8] } { i32 0, i32 1, i32 8, [4 x i8] zeroinitializer }, align 8
// CHECK-LABEL: @"$s15generic_structs18FixedLayoutGenericVMP" = internal constant <{ {{.*}} }> <{
// -- instantiation function
// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$s15generic_structs18FixedLayoutGenericVMi"
// -- completion function
// CHECK-SAME: i32 0,
// -- pattern flags
// CHECK-SAME: <i32 0x4000_0001>,
// -- vwtable pointer
// CHECK-SAME: @"$s15generic_structs18FixedLayoutGenericVWV"
// -- extra data pattern
// CHECK-SAME: { i32, i32, i32, [4 x i8] }* [[PATTERN]]
// CHECK-SAME: i16 1,
// CHECK-SAME: i16 2 }>
// -- Generic structs with dynamic layout contain the vwtable pattern as part
// of the metadata pattern, and no independent vwtable symbol
// CHECK: @"$s15generic_structs13SingleDynamicVWV" = internal constant
// CHECK-SAME: i8* bitcast (%swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)* @"$s15generic_structs13SingleDynamicVwCP" to i8*),
// -- ...
// -- placeholder for size, stride, flags
// CHECK-SAME: i64 0,
// CHECK-SAME: i64 0,
// CHECK-SAME: i32 4194304,
// CHECK-SAME: i32 0 }
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[SINGLEDYNAMIC_NAME:@.*]] = private constant [14 x i8] c"SingleDynamic\00"
// CHECK: @"$s15generic_structs13SingleDynamicVMn" = hidden constant
// -- flags: struct, unique, generic
// CHECK-SAME: <i32 0x0000_00D1>
// -- name
// CHECK-SAME: [14 x i8]* [[SINGLEDYNAMIC_NAME]]
// -- field count
// CHECK-SAME: i32 1,
// -- field offset vector offset
// CHECK-SAME: i32 3,
// -- generic instantiation info
// CHECK-SAME: [{{[0-9]+}} x i8*]* @"$s15generic_structs13SingleDynamicVMI"
// CHECK-SAME: @"$s15generic_structs13SingleDynamicVMP"
// -- generic params, requirements, key args, extra args
// CHECK-SAME: i16 1, i16 0, i16 1, i16 0
// -- generic parameters
// CHECK-SAME: <i8 0x80>
// CHECK-SAME: }>
// CHECK: @"$s15generic_structs13SingleDynamicVMP" = internal constant <{ {{.*}} }> <{
// -- instantiation function
// CHECK-SAME: %swift.type* (%swift.type_descriptor*, i8**, i8*)* @"$s15generic_structs13SingleDynamicVMi"
// -- vwtable pointer
// CHECK-SAME: @"$s15generic_structs13SingleDynamicVWV"
// -- Nominal type descriptor for generic struct with protocol requirements
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
// CHECK: [[DYNAMICWITHREQUIREMENTS_NAME:@.*]] = private constant [24 x i8] c"DynamicWithRequirements\00"
// CHECK: @"$s15generic_structs23DynamicWithRequirementsVMn" = hidden constant <{ {{.*}} i32 }> <{
// -- flags: struct, unique, generic
// CHECK-SAME: <i32 0x0000_00D1>
// -- name
// CHECK-SAME: [24 x i8]* [[DYNAMICWITHREQUIREMENTS_NAME]]
// -- field count
// CHECK-SAME: i32 2,
// -- field offset vector offset
// CHECK-SAME: i32 6,
// -- generic params, requirements, key args, extra args
// CHECK-SAME: i16 2, i16 2, i16 4, i16 0,
// -- generic parameters
// CHECK-SAME: <i8 0x80>, <i8 0x80>,
// -- generic requirement
// -- protocol requirement with key arg
// CHECK-SAME: i32 128
// -- param 0
// CHECK-SAME: i32 0
// -- protocol Req1
// CHECK-SAME: @"$s15generic_structs4Req1Mp"
// -- protocol requirement with key arg
// CHECK-SAME: i32 128
// -- param 1
// CHECK-SAME: i32 2
// -- protocol Req2
// CHECK-SAME: @"$s15generic_structs4Req2Mp"
// CHECK-SAME: }>
// CHECK: @"$s15generic_structs23DynamicWithRequirementsVMP" = internal constant <{ {{.*}} }> <{
// -- Fixed-layout struct metadata contains fixed field offsets
// CHECK: @"$s15generic_structs6IntishVMf" = internal constant <{ {{.*}} i32, [4 x i8] }> <{
// CHECK-SAME: i32 0
// CHECK-SAME: }>
// CHECK: @"$s15generic_structs7CharethVMf" = internal constant <{ {{.*}} i32, [4 x i8] }> <{
// CHECK-SAME: i32 0
// CHECK-SAME: }>
// CHECK: @"$s15generic_structs8StringlyVMf" = internal constant <{ {{.*}} i32, i32, i32, [4 x i8] }> <{
// CHECK-SAME: i32 0, i32 8, i32 16, [4 x i8] zeroinitializer
// CHECK-SAME: }>
struct FixedLayoutGeneric<T> {
var x: Byteful
var y: Byteful
var z: Intish
}
struct SingleDynamic<T> {
var x : T
}
protocol Req1 { associatedtype Assoc1 }
protocol Req2 {}
struct DynamicWithRequirements<T: Req1, U: Req2> {
var x : T
var y : U
}
struct Intish { var value : Builtin.Int64 }
struct Chareth { var value : Builtin.Int21 }
struct Byteful { var value : Builtin.Int8 }
struct Stringly {
var owner : Builtin.NativeObject
var base : Builtin.RawPointer
var size : Builtin.Int64
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i32 } @concrete_instances(i64 %0, i32 %1) {{.*}} {
// CHECK: entry:
// CHECK: %2 = trunc i32 %1 to i21
// CHECK: %3 = zext i21 %2 to i32
// CHECK: %4 = insertvalue { i64, i32 } undef, i64 %0, 0
// CHECK: %5 = insertvalue { i64, i32 } %4, i32 %3, 1
// CHECK: ret { i64, i32 } %5
// CHECK: }
sil @concrete_instances : $(SingleDynamic<Intish>, SingleDynamic<Chareth>) -> (Intish, Chareth) {
entry(%0 : $SingleDynamic<Intish>, %1 : $SingleDynamic<Chareth>):
%a = struct_extract %0 : $SingleDynamic<Intish>, #SingleDynamic.x
%b = struct_extract %1 : $SingleDynamic<Chareth>, #SingleDynamic.x
%c = tuple (%a : $Intish, %b : $Chareth)
return %c : $(Intish, Chareth)
}
struct ComplexDynamic<U, V> {
var a, a2 : Byteful
var b : U
var c : SingleDynamic<V>
var d : Chareth
}
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @explode_complex_dynamic
sil @explode_complex_dynamic : $<A, B> (@in ComplexDynamic<A, B>, @inout Byteful, @inout A, @inout B, @inout Chareth) -> () {
entry(%0 : $*ComplexDynamic<A, B>, %1 : $*Byteful, %2 : $*A, %3 : $*B, %4 : $*Chareth):
%a = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.a2
// CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i32*
// CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i32, i32* [[METADATA]], i64 10
// CHECK: [[FIELD_OFFSET:%.*]] = load i32, i32* [[FIELD_OFFSET_ADDR]], align 8
// CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
// CHECK: [[BYTE_OFFSET:%.*]] = getelementptr inbounds i8, i8* [[BYTES]], i32 [[FIELD_OFFSET]]
// CHECK: bitcast i8* [[BYTE_OFFSET]] to %swift.opaque*
%b = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.b
// CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i32*
// CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i32, i32* [[METADATA]], i64 11
// CHECK: [[FIELD_OFFSET:%.*]] = load i32, i32* [[FIELD_OFFSET_ADDR]], align 8
// CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
// CHECK: [[BYTE_OFFSET:%.*]] = getelementptr inbounds i8, i8* [[BYTES]], i32 [[FIELD_OFFSET]]
// CHECK: bitcast i8* [[BYTE_OFFSET]] to %T15generic_structs13SingleDynamicV
%5 = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.c
%c = struct_element_addr %5 : $*SingleDynamic<B>, #SingleDynamic.x
// CHECK: [[METADATA:%.*]] = bitcast %swift.type* {{%.*}} to i32*
// CHECK: [[FIELD_OFFSET_ADDR:%.*]] = getelementptr inbounds i32, i32* [[METADATA]], i64 12
// CHECK: [[FIELD_OFFSET:%.*]] = load i32, i32* [[FIELD_OFFSET_ADDR]], align 8
// CHECK: [[BYTES:%.*]] = bitcast %T15generic_structs14ComplexDynamicV* %0 to i8*
// CHECK: [[BYTE_OFFSET:%.*]] = getelementptr inbounds i8, i8* [[BYTES]], i32 [[FIELD_OFFSET]]
// CHECK: bitcast i8* [[BYTE_OFFSET]] to %T15generic_structs7CharethV
%d = struct_element_addr %0 : $*ComplexDynamic<A, B>, #ComplexDynamic.d
copy_addr %a to %1 : $*Byteful
copy_addr %b to %2 : $*A
copy_addr %c to %3 : $*B
copy_addr %d to %4 : $*Chareth
%v = tuple ()
return %v : $()
}
// CHECK-LABEL: define{{( protected)?}} internal %swift.type* @"$s15generic_structs13SingleDynamicVMi"(%swift.type_descriptor* %0, i8** %1, i8* %2)
// CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type**
// CHECK: %T = load %swift.type*, %swift.type** [[T0]], align 8
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2, i64 16)
// CHECK-NEXT: ret %swift.type* [[METADATA]]
// CHECK: }
// CHECK-LABEL: define{{( protected)?}} internal swiftcc %swift.metadata_response @"$s15generic_structs13SingleDynamicVMr"
// CHECK-SAME: (%swift.type* [[METADATA:%.*]], i8* %0, i8** %1) {{.*}} {
// Lay out fields.
// CHECK: [[T0:%.*]] = bitcast %swift.type* [[METADATA]] to i32*
// CHECK: [[T1:%.*]] = getelementptr inbounds i32, i32* [[T0]], i64 6
// CHECK: [[T2:%.*]] = getelementptr inbounds i8**, i8*** [[TYPES:%.*]], i32 0
// CHECK: call void @swift_initStructMetadata(%swift.type* [[METADATA]], i64 0, i64 1, i8*** [[TYPES]], i32* [[T1]])
// CHECK: ret %swift.metadata_response
// CHECK: }
// Check that we directly delegate buffer witnesses to a single dynamic field:
// initializeBufferWithCopyOfBuffer
// CHECK-LABEL: define internal %swift.opaque* @"$s15generic_structs13SingleDynamicVwCP"([24 x i8]* noalias %dest, [24 x i8]* noalias %src, %swift.type* %"SingleDynamic<T>") {{.*}} {
// CHECK: %T = load %swift.type*,
// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8***
// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8**, i8*** [[T0]], i64 -1
// CHECK-NEXT: %T.valueWitnesses = load i8**, i8*** [[T1]]
// CHECK-NEXT: [[T1:%.*]] = load i8*, i8** %T.valueWitnesses,
// CHECK-NEXT: [[FN:%.*]] = bitcast i8* [[T1]] to %swift.opaque* ([24 x i8]*, [24 x i8]*, %swift.type*)*
// CHECK-NEXT: [[T0:%.*]] = call %swift.opaque* [[FN]]([24 x i8]* noalias %dest, [24 x i8]* noalias %src, %swift.type* %T)
// CHECK-NEXT: [[T1:%.*]] = bitcast %swift.opaque* [[T0]] to {{.*}}
// CHECK-NEXT: [[T2:%.*]] = bitcast {{.*}} [[T1]] to %swift.opaque*
// CHECK-NEXT: ret %swift.opaque* [[T2]]
protocol HasAssociatedType {
associatedtype Assoc
}
protocol ParentHasAssociatedType : HasAssociatedType {
associatedtype Assoc : HasAssociatedType
}
struct GenericLayoutWithAssocType<T: ParentHasAssociatedType> {
var x: T.Assoc
var y: T.Assoc.Assoc
}
// CHECK-LABEL: define internal %swift.type* @"$s15generic_structs26GenericLayoutWithAssocTypeVMi"(
// CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type**
// CHECK: %T = load %swift.type*, %swift.type** [[T0]], align 8
// CHECK: [[T1:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T0]], i32 1
// CHECK: [[T2:%.*]] = bitcast %swift.type** [[T1]] to i8***
// CHECK: %T.ParentHasAssociatedType = load i8**, i8*** [[T2]],
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata
// CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$s15generic_structs26GenericLayoutWithAssocTypeVMr"(
// CHECK: [[T0:%.*]] = call{{( tail)?}} swiftcc %swift.metadata_response @swift_checkMetadataState(i64 0, %swift.type* %T)
// CHECK: [[T_CHECKED:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
// CHECK: [[T0_GEP:%.*]] = getelementptr inbounds i8*, i8** %T.ParentHasAssociatedType, i32 1
// CHECK: [[T0:%.*]] = load i8*, i8** [[T0_GEP]]
// CHECK: [[T1:%.*]] = bitcast i8* [[T0]] to i8**
// CHECK: [[T4:%.*]] = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.HasAssociatedType, %swift.type* %T, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
// CHECK: %T.Assoc = extractvalue %swift.metadata_response [[T4]], 0
// CHECK: %T.Assoc.HasAssociatedType = call swiftcc i8** @swift_getAssociatedConformanceWitness(i8** %T.ParentHasAssociatedType, %swift.type* %T, %swift.type* %T.Assoc,
// CHECK: [[T2:%.*]] = call swiftcc %swift.metadata_response @swift_getAssociatedTypeWitness(i64 0, i8** %T.Assoc.HasAssociatedType, %swift.type* %T.Assoc, %swift.protocol_requirement* @"$s15generic_structs17HasAssociatedTypeTL", %swift.protocol_requirement* @"$s5Assoc15generic_structs17HasAssociatedTypePTl")
// CHECK: %T.Assoc.Assoc = extractvalue %swift.metadata_response [[T2]], 0