| // RUN: %empty-directory(%t) |
| // RUN: %target-build-swift %S/Inputs/struct_with_fields.swift -parse-as-library -wmo -enable-library-evolution -module-name=Test -emit-module -emit-module-path=%t/Test.swiftmodule -c -o %t/test.o |
| |
| // RUN: %target-build-swift -O %s -module-name=test -Xfrontend -sil-verify-all -I%t -emit-sil | %FileCheck %s |
| |
| // RUN: %target-build-swift -Onone %s -I%t %t/test.o -o %t/Onone.out |
| // RUN: %target-build-swift -O %s -I%t %t/test.o -o %t/O.out |
| // RUN: %target-run %t/Onone.out > %t/Onone.txt |
| // RUN: %target-run %t/O.out > %t/O.txt |
| // RUN: diff %t/Onone.txt %t/O.txt |
| |
| // REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib |
| |
| import Test |
| |
| final class C<T> { |
| var x: Int |
| var z: T |
| let immutable: String |
| private(set) var secretlyMutable: String |
| |
| init(x: Int, z: T) { |
| self.x = x |
| self.z = z |
| self.immutable = "somestring" |
| self.secretlyMutable = immutable |
| } |
| } |
| |
| struct Point { |
| var x: Double |
| var y: Double |
| } |
| |
| struct S<T> { |
| var x: Int |
| var y: Int? |
| var z: T |
| var p: Point |
| var op: Point? |
| var c: C<T> |
| } |
| |
| struct NonOffsetableProperties { |
| // observers |
| var x: Int { didSet {} } |
| // reabstracted |
| var y: () -> () |
| // computed |
| var z: Int { return 0 } |
| } |
| |
| struct TupleProperties { |
| // unlabeled |
| var a: (Int, String) |
| // labeled |
| let b: (x: String, y: Int) |
| // reference writable |
| let c: (m: C<Int>, n: C<String>) |
| } |
| |
| typealias Tuple<T, U> = (S<T>, C<U>) |
| |
| func getIdentityKeyPathOfType<T>(_: T.Type) -> KeyPath<T, T> { |
| return \.self |
| } |
| |
| |
| @inline(never) |
| func printOffset(_ o: Int?) { |
| print(o as Any) |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @$s4test0A13StructOffsetsyyF |
| // CHECK-NOT: _storedInlineOffset |
| // CHECK-NOT: class_method |
| // CHECK: } // end sil function '$s4test0A13StructOffsetsyyF' |
| @inline(never) |
| func testStructOffsets() { |
| let SLayout = MemoryLayout<S<Int>>.self |
| printOffset(SLayout.offset(of: \S<Int>.x)) |
| printOffset(SLayout.offset(of: \S<Int>.y)) |
| printOffset(SLayout.offset(of: \S<Int>.z)) |
| printOffset(SLayout.offset(of: \S<Int>.p)) |
| printOffset(SLayout.offset(of: \S<Int>.p.x)) |
| printOffset(SLayout.offset(of: \S<Int>.p.y)) |
| printOffset(SLayout.offset(of: \S<Int>.c)) |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @$s4test0A20GenericStructOffsetsyyxmlF |
| // CHECK-NOT: _storedInlineOffset |
| // CHECK-NOT: class_method |
| // CHECK: } // end sil function '$s4test0A20GenericStructOffsetsyyxmlF' |
| @inline(never) |
| @_semantics("optimize.sil.specialize.generic.never") |
| func testGenericStructOffsets<T>(_ t: T.Type) { |
| let SLayout = MemoryLayout<S<T>>.self |
| printOffset(SLayout.offset(of: \S<T>.x)) |
| printOffset(SLayout.offset(of: \S<T>.y)) |
| printOffset(SLayout.offset(of: \S<T>.z)) |
| printOffset(SLayout.offset(of: \S<T>.p)) |
| printOffset(SLayout.offset(of: \S<T>.p.x)) |
| printOffset(SLayout.offset(of: \S<T>.p.y)) |
| printOffset(SLayout.offset(of: \S<T>.c)) |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @$s4test0A10NonOffsetsyyF |
| // CHECK-NOT: _storedInlineOffset |
| // CHECK-NOT: class_method |
| // CHECK: } // end sil function '$s4test0A10NonOffsetsyyF' |
| @inline(never) |
| func testNonOffsets() { |
| let NOPLayout = MemoryLayout<NonOffsetableProperties>.self |
| printOffset(NOPLayout.offset(of: \NonOffsetableProperties.x)) |
| printOffset(NOPLayout.offset(of: \NonOffsetableProperties.y)) |
| printOffset(NOPLayout.offset(of: \NonOffsetableProperties.z)) |
| printOffset(MemoryLayout<C<Int>>.offset(of: \C<Int>.x)) |
| let SLayout = MemoryLayout<S<Int>>.self |
| printOffset(SLayout.offset(of: \S<Int>.c.x)) |
| printOffset(SLayout.offset(of: \S<Int>.op!.x)) |
| printOffset(SLayout.offset(of: \S<Int>.op?.x)) |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @$s4test0A11SelfOffsetsyyF |
| // CHECK-NOT: _storedInlineOffset |
| // CHECK-NOT: class_method |
| // CHECK: } // end sil function '$s4test0A11SelfOffsetsyyF' |
| @inline(never) |
| func testSelfOffsets() { |
| let SLayout = MemoryLayout<S<Int>>.self |
| printOffset(SLayout.offset(of: \.self)) |
| printOffset(SLayout.offset(of: getIdentityKeyPathOfType(S<Int>.self))) |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @$s4test0A12TupleOffsetsyyF |
| // CHECK-NOT: _storedInlineOffset |
| // CHECK-NOT: class_method |
| // CHECK: } // end sil function '$s4test0A12TupleOffsetsyyF' |
| @inline(never) |
| func testTupleOffsets() { |
| let TPLayout = MemoryLayout<TupleProperties>.self |
| printOffset(TPLayout.offset(of: \TupleProperties.self)) |
| printOffset(TPLayout.offset(of: \TupleProperties.a)) |
| printOffset(TPLayout.offset(of: \TupleProperties.a.0)) |
| printOffset(TPLayout.offset(of: \TupleProperties.a.1)) |
| printOffset(TPLayout.offset(of: \TupleProperties.b)) |
| printOffset(TPLayout.offset(of: \TupleProperties.b.x)) |
| printOffset(TPLayout.offset(of: \TupleProperties.b.y)) |
| printOffset(TPLayout.offset(of: \TupleProperties.c)) |
| printOffset(TPLayout.offset(of: \TupleProperties.c.m)) |
| printOffset(TPLayout.offset(of: \TupleProperties.c.n)) |
| |
| let TLayout = MemoryLayout<Tuple<Int, Int>>.self |
| printOffset(TLayout.offset(of: \Tuple<Int, Int>.self)) |
| printOffset(TLayout.offset(of: \Tuple<Int, Int>.0)) |
| printOffset(TLayout.offset(of: \Tuple<Int, Int>.0.x)) |
| printOffset(TLayout.offset(of: \Tuple<Int, Int>.1)) |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @$s4test0A19GenericTupleOffsetsyyxmlF |
| // CHECK-NOT: _storedInlineOffset |
| // CHECK-NOT: class_method |
| // CHECK: } // end sil function '$s4test0A19GenericTupleOffsetsyyxmlF' |
| @inline(never) |
| @_semantics("optimize.sil.specialize.generic.never") |
| func testGenericTupleOffsets<T>(_ t: T.Type) { |
| let TLayout = MemoryLayout<Tuple<T, T>>.self |
| printOffset(TLayout.offset(of: \Tuple<T, T>.self)) |
| printOffset(TLayout.offset(of: \Tuple<T, T>.0)) |
| printOffset(TLayout.offset(of: \Tuple<T, T>.0.x)) |
| printOffset(TLayout.offset(of: \Tuple<T, T>.1)) |
| } |
| |
| // CHECK-LABEL: sil {{.*}} @$s4test0A16ResilientOffsetsyyF |
| // CHECK: class_method {{.*}}_storedInlineOffset |
| // CHECK: } // end sil function '$s4test0A16ResilientOffsetsyyF' |
| @inline(never) |
| func testResilientOffsets() { |
| let TLayout = MemoryLayout<TestStruct>.self |
| printOffset(TLayout.offset(of: \TestStruct.x)) |
| } |
| |
| print("### testStructOffsets") |
| testStructOffsets() |
| print("### testGenericStructOffsets") |
| testGenericStructOffsets(Int.self) |
| print("### testNonOffsets") |
| testNonOffsets() |
| print("### testSelfOffsets") |
| testSelfOffsets() |
| print("### testTupleOffsets") |
| testTupleOffsets() |
| print("### testGenericTupleOffsets") |
| testGenericTupleOffsets(Int.self) |
| print("### testResilientOffsets") |
| testResilientOffsets() |
| |