| // RUN: %empty-directory(%t) |
| // RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../Inputs/resilient_struct.swift |
| // RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience %s | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize -DINT=i%target-ptrsize |
| // RUN: %target-swift-frontend -I %t -emit-ir -enable-resilience -O %s |
| |
| // We only use fragile class layouts when Objective-C interop is enabled. |
| |
| // REQUIRES: objc_interop |
| // REQUIRES: CPU=x86_64 |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| import resilient_struct |
| |
| public class ClassWithResilientField { |
| var first: Int |
| var second: Size |
| var third: Int |
| |
| init(x: Int, y: Size, z: Int) |
| } |
| |
| sil_vtable ClassWithResilientField {} |
| |
| // Field offsets are statically known: |
| // CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC5firstSivpWvd" = hidden constant i64 16, align 8 |
| // CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC6second16resilient_struct4SizeVvpWvd" = hidden constant i64 24, align 8 |
| // CHECK-DAG: @"$s31completely_fragile_class_layout23ClassWithResilientFieldC5thirdSivpWvd" = hidden constant i64 40, align 8 |
| |
| // Class has static metadata: |
| // CHECK-LABEL: $s31completely_fragile_class_layout23ClassWithResilientFieldCMf |
| |
| // rdar://problem/41308521 -- enum lowering needs to pretend payloads are |
| // resilient and not use spare bits, even when bypassing resilience while |
| // lowering class fields. |
| |
| // Because ResilientRef is resilient, the enum stores the tag out-of-line, |
| // rather than packing it into the spare bits of the payload. Make sure that |
| // this layout is maintained even when the enum is a class field, which |
| // forces it to be lowered without resilience. |
| enum EnumWithResilientPayload { |
| case none |
| case some(ClassWithResilientEnum) |
| case data(ResilientRef) |
| } |
| |
| // Note that 'second' is at offset 25, which means 'first' is 9 bytes in size; |
| // an 8 byte payload and an out-of-line tag, as expected. |
| public class ClassWithResilientEnum { |
| var first: EnumWithResilientPayload |
| var second: Int8 |
| |
| init(x: EnumWithResilientPayload, y: Int8) |
| } |
| |
| sil_vtable ClassWithResilientEnum {} |
| |
| // Field offsets are statically known: |
| // CHECK-LABEL: @"$s31completely_fragile_class_layout22ClassWithResilientEnumC5firstAA0hfG7PayloadOvpWvd" = hidden constant i64 16, align 8 |
| // CHECK-LABEL: @"$s31completely_fragile_class_layout22ClassWithResilientEnumC6seconds4Int8VvpWvd" = hidden constant i64 25, align 8 |
| |
| |
| // When allocating a class with resiliently-sized fields, we must still load |
| // the size and alignment from metadata, because its metadata may have been |
| // re-initialized. |
| |
| // CHECK-LABEL: define {{(dllexport )?}}{{(protected )?}}swiftcc void @allocClassWithResilientField() |
| sil @allocClassWithResilientField : $@convention(thin) () -> () { |
| bb0: |
| |
| // CHECK: [[T0:%.*]] = call swiftcc %swift.metadata_response @"$s31completely_fragile_class_layout23ClassWithResilientFieldCMa"(i64 0) |
| // CHECK-NEXT: [[META:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 |
| // CHECK-NEXT: [[META_ADDR:%.*]] = bitcast %swift.type* [[META]] to i8* |
| // CHECK-NEXT: [[SIZE_ADDR:%.*]] = getelementptr inbounds i8, i8* [[META_ADDR]], i32 48 |
| // CHECK-NEXT: [[SIZE_PTR:%.*]] = bitcast i8* [[SIZE_ADDR]] to i32* |
| // CHECK-NEXT: [[SIZE_2:%.*]] = load i32, i32* [[SIZE_PTR]], align 8 |
| // CHECK-NEXT: [[SIZE:%.*]] = zext i32 [[SIZE_2]] to i64 |
| // CHECK-NEXT: [[ALIGN_ADDR:%.*]] = getelementptr inbounds i8, i8* [[META_ADDR]], i32 52 |
| // CHECK-NEXT: [[ALIGN_PTR:%.*]] = bitcast i8* [[ALIGN_ADDR]] to i16* |
| // CHECK-NEXT: [[ALIGN_2:%.*]] = load i16, i16* [[ALIGN_PTR]], align 4 |
| // CHECK-NEXT: [[ALIGN:%.*]] = zext i16 [[ALIGN_2]] to i64 |
| // CHECK-NEXT: [[ALLOC:%.*]] = call noalias %swift.refcounted* @swift_allocObject(%swift.type* [[META]], i64 [[SIZE]], i64 [[ALIGN]]) |
| %c = alloc_ref $ClassWithResilientField |
| |
| // ... dealloc_ref also does the same thing. |
| |
| // CHECK-NEXT: [[SELF:%.*]] = bitcast %swift.refcounted* [[ALLOC]] to %T31completely_fragile_class_layout23ClassWithResilientFieldC* |
| // CHECK-NEXT: [[ISA_ADDR:%.*]] = getelementptr inbounds %T31completely_fragile_class_layout23ClassWithResilientFieldC, %T31completely_fragile_class_layout23ClassWithResilientFieldC* [[SELF]], i32 0, i32 0, i32 0 |
| // CHECK-NEXT: [[META:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]], align 8 |
| // CHECK-NEXT: [[META_ADDR:%.*]] = bitcast %swift.type* [[META]] to i8* |
| // CHECK-NEXT: [[SIZE_ADDR:%.*]] = getelementptr inbounds i8, i8* [[META_ADDR]], i32 48 |
| // CHECK-NEXT: [[SIZE_PTR:%.*]] = bitcast i8* [[SIZE_ADDR]] to i32* |
| // CHECK-NEXT: [[SIZE_2:%.*]] = load i32, i32* [[SIZE_PTR]], align 8 |
| // CHECK-NEXT: [[SIZE:%.*]] = zext i32 [[SIZE_2]] to i64 |
| // CHECK-NEXT: [[ALIGN_ADDR:%.*]] = getelementptr inbounds i8, i8* [[META_ADDR]], i32 52 |
| // CHECK-NEXT: [[ALIGN_PTR:%.*]] = bitcast i8* [[ALIGN_ADDR]] to i16* |
| // CHECK-NEXT: [[ALIGN_2:%.*]] = load i16, i16* [[ALIGN_PTR]], align 4 |
| // CHECK-NEXT: [[ALIGN:%.*]] = zext i16 [[ALIGN_2]] to i64 |
| // CHECK-NEXT: [[ALLOC:%.*]] = bitcast %T31completely_fragile_class_layout23ClassWithResilientFieldC* [[SELF]] to %swift.refcounted* |
| // CHECK-NEXT: call void @swift_deallocClassInstance(%swift.refcounted* [[ALLOC]], i64 [[SIZE]], i64 [[ALIGN]]) |
| dealloc_ref %c : $ClassWithResilientField |
| |
| %result = tuple () |
| return %result : $() |
| } |
| |
| // Metadata accessor for ClassWithResilientField is trivial: |
| // CHECK-LABEL: define swiftcc %swift.metadata_response @"$s31completely_fragile_class_layout23ClassWithResilientFieldCMa |
| // CHECK: call %objc_class* @swift_getInitializedObjCClass(%objc_class* {{.*}} @"$s31completely_fragile_class_layout23ClassWithResilientFieldCMf" |
| // CHECK: ret |
| |
| // Accessing a field whose offset depends on resilient types should |
| // use the field offset global. |
| |
| // CHECK-LABEL: define swiftcc {{(dllexport )?}}{{(protected )?}}i64 @accessClassWithResilientField(%T31completely_fragile_class_layout23ClassWithResilientFieldC*) |
| sil @accessClassWithResilientField : $@convention(thin) (@guaranteed ClassWithResilientField) -> Int { |
| bb0(%0 : @guaranteed $ClassWithResilientField): |
| |
| // CHECK: [[OFFSET:%.*]] = load i64, i64* @"$s31completely_fragile_class_layout23ClassWithResilientFieldC5thirdSivpWvd", align 8 |
| // CHECK-NEXT: [[SELF_ADDR:%.*]] = bitcast %T31completely_fragile_class_layout23ClassWithResilientFieldC* %0 to i8* |
| // CHECK-NEXT: [[FIELD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[SELF_ADDR]], i64 [[OFFSET]] |
| // CHECK-NEXT: [[FIELD_PTR2:%.*]] = bitcast i8* [[FIELD_ADDR]] to %TSi* |
| // CHECK-NEXT: [[FIELD_PTR:%.*]] = getelementptr inbounds %TSi, %TSi* [[FIELD_PTR2]], i32 0, i32 0 |
| |
| %1 = ref_element_addr %0 : $ClassWithResilientField, #ClassWithResilientField.third |
| |
| // CHECK-NEXT: [[VALUE:%.*]] = load i64, i64* [[FIELD_PTR]], align 8 |
| %2 = load [trivial] %1 : $*Int |
| |
| // CHECK-NEXT: ret i64 [[VALUE]] |
| return %2 : $Int |
| } |
| |
| // Metadata accessor for ClassWithResilientEnum is trivial: |
| // CHECK-LABEL: define swiftcc %swift.metadata_response @"$s31completely_fragile_class_layout22ClassWithResilientEnumCMa |
| // CHECK: call %objc_class* @swift_getInitializedObjCClass(%objc_class* {{.*}} @"$s31completely_fragile_class_layout22ClassWithResilientEnumCMf" |
| // CHECK: ret |