| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil %s -lslocation-dump -ml=only-type-expansion | %FileCheck %s |
| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil %s -lslocation-dump-use-new-projection -lslocation-dump -ml=only-type-expansion | %FileCheck %s |
| |
| sil_stage canonical |
| |
| import Builtin |
| |
| struct Int { |
| var value : Builtin.Int64 |
| } |
| |
| struct Int32{ |
| var value : Builtin.Int32 |
| } |
| |
| struct Int64 { |
| var value : Builtin.Int64 |
| } |
| |
| struct Bool { |
| var value : Builtin.Int1 |
| } |
| |
| struct S1 { |
| var a: Int |
| var b: Int |
| init(a: Int, b: Int) |
| init() |
| } |
| |
| struct S2 { |
| var a: Int |
| var b: S1 |
| init(a: Int, b: S1) |
| init() |
| } |
| |
| class C1 { |
| var a : Int |
| deinit |
| init(a: Int) |
| } |
| |
| struct S3 { |
| var c: C1 |
| var a: S2 |
| var b: C1 |
| init(c: C1, a: S2, b: C1) |
| init() |
| } |
| |
| struct S4 { |
| var c: (Int, Int, S1) |
| init(c: (Int, Int, S1)) |
| init() |
| } |
| |
| struct S5 { |
| var c: (Int, Int, S3) |
| init(c: (Int, Int, S3)) |
| init() |
| } |
| |
| struct S6 { |
| var tuple: (Int, Int) |
| } |
| |
| enum Example { |
| case A(Int64) |
| case B(Int32) |
| } |
| |
| |
| sil @S1_init : $@convention(thin) (@thin S1.Type) -> S1 |
| sil @S2_init : $@convention(thin) (@thin S2.Type) -> S2 |
| sil @C1_init : $@convention(thin) (@thick C1.Type) -> @owned C1 |
| sil @S3_init : $@convention(thin) (@thin S3.Type) -> @owned S3 |
| sil @S4_init : $@convention(thin) (@thin S4.Type) -> @owned S4 |
| sil @S5_init : $@convention(thin) (@thin S5.Type) -> @owned S5 |
| sil @S6_init : $@convention(thin) (@thin S6.Type) -> S6 |
| |
| // CHECK-LABEL: @test_struct_type_expansion |
| // CHECK: #0 store |
| // CHECK-NEXT: Projection Path [$*S1 |
| // CHECK-NEXT: Field: var b: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S1 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK: #1 store |
| // CHECK-NEXT: Projection Path [$*S2 |
| // CHECK-NEXT: Field: var b: S1 in: $*S1 |
| // CHECK-NEXT: Field: var b: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S2 |
| // CHECK-NEXT: Field: var b: S1 in: $*S1 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S2 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| sil hidden @test_struct_type_expansion : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_stack $S1, var, name "a" // users: %5, %12 |
| %1 = alloc_stack $S2, var, name "b" // users: %9, %11 |
| %2 = function_ref @S1_init : $@convention(thin) (@thin S1.Type) -> S1 // user: %4 |
| %3 = metatype $@thin S1.Type // user: %4 |
| %4 = apply %2(%3) : $@convention(thin) (@thin S1.Type) -> S1 // user: %5 |
| store %4 to %0 : $*S1 // id: %5 |
| %6 = function_ref @S2_init : $@convention(thin) (@thin S2.Type) -> S2 // user: %8 |
| %7 = metatype $@thin S2.Type // user: %8 |
| %8 = apply %6(%7) : $@convention(thin) (@thin S2.Type) -> S2 // user: %9 |
| store %8 to %1 : $*S2 // id: %9 |
| %10 = tuple () // user: %13 |
| dealloc_stack %1 : $*S2 // id: %11 |
| dealloc_stack %0 : $*S1 // id: %12 |
| return %10 : $() // id: %13 |
| } |
| |
| // Make sure we do not expand the reference type. |
| // |
| // CHECK-LABEL: test_class_stack_slot |
| // CHECK: #0 store |
| // CHECK-NOT: var |
| // CHECK: #1 store |
| sil hidden @test_class_stack_slot : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_stack $C1, var, name "a" // users: %4, %7 |
| %1 = function_ref @C1_init : $@convention(thin) (@thick C1.Type) -> @owned C1 // user: %3 |
| %2 = metatype $@thick C1.Type // user: %3 |
| %3 = apply %1(%2) : $@convention(thin) (@thick C1.Type) -> @owned C1 // users: %4, %5 |
| store %3 to %0 : $*C1 // id: %4 |
| store %3 to %0 : $*C1 // id: %4 |
| strong_release %3 : $C1 // id: %5 |
| %6 = tuple () // user: %8 |
| dealloc_stack %0 : $*C1 // id: %7 |
| return %6 : $() // id: %8 |
| } |
| |
| // CHECK-LABEL: test_struct_and_class_slot |
| // CHECK: #0 store |
| // CHECK-NEXT: Projection Path [$*S3 |
| // CHECK-NEXT: Field: var b: C1 in: $*C1] |
| // CHECK-NEXT: Projection Path [$*S3 |
| // CHECK-NEXT: Field: var a: S2 in: $*S2 |
| // CHECK-NEXT: Field: var b: S1 in: $*S1 |
| // CHECK-NEXT: Field: var b: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S3 |
| // CHECK-NEXT: Field: var a: S2 in: $*S2 |
| // CHECK-NEXT: Field: var b: S1 in: $*S1 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S3 |
| // CHECK-NEXT: Field: var a: S2 in: $*S2 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S3 |
| // CHECK-NEXT: Field: var c: C1 in: $*C1] |
| sil hidden @test_struct_and_class_slot : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_stack $S3, var, name "a" // users: %4, %7 |
| // function_ref test.S3.init (test.S3.Type)() -> test.S3 |
| %1 = function_ref @S3_init : $@convention(thin) (@thin S3.Type) -> @owned S3 // user: %3 |
| %2 = metatype $@thin S3.Type // user: %3 |
| %3 = apply %1(%2) : $@convention(thin) (@thin S3.Type) -> @owned S3 // users: %4, %5 |
| store %3 to %0 : $*S3 // id: %4 |
| release_value %3 : $S3 // id: %5 |
| %6 = tuple () // user: %8 |
| dealloc_stack %0 : $*S3 // id: %7 |
| return %6 : $() // id: %8 |
| } |
| |
| // Test tuple expansion. |
| // |
| // CHECK-LABEL: test_tuple |
| // CHECK: #0 store |
| // CHECK-NEXT: Projection Path [$*S4 |
| // CHECK-NEXT: Field: var c: (Int, Int, S1) in: $*(Int, Int, S1) |
| // CHECK-NEXT: Index: 2 in: $*S1 |
| // CHECK-NEXT: Field: var b: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S4 |
| // CHECK-NEXT: Field: var c: (Int, Int, S1) in: $*(Int, Int, S1) |
| // CHECK-NEXT: Index: 2 in: $*S1 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S4 |
| // CHECK-NEXT: Field: var c: (Int, Int, S1) in: $*(Int, Int, S1) |
| // CHECK-NEXT: Index: 1 in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S4 |
| // CHECK-NEXT: Field: var c: (Int, Int, S1) in: $*(Int, Int, S1) |
| // CHECK-NEXT: Index: 0 in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| sil hidden @test_tuple : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_stack $S4, var, name "x" // users: %4, %7 |
| // function_ref test.S4.init (test.S4.Type)() -> test.S4 |
| %1 = function_ref @S4_init : $@convention(thin) (@thin S4.Type) -> @owned S4 // user: %3 |
| %2 = metatype $@thin S4.Type // user: %3 |
| %3 = apply %1(%2) : $@convention(thin) (@thin S4.Type) -> @owned S4 // users: %4, %5 |
| store %3 to %0 : $*S4 // id: %4 |
| release_value %3 : $S4 // id: %5 |
| %6 = tuple () // user: %8 |
| dealloc_stack %0 : $*S4 // id: %7 |
| return %6 : $() // id: %8 |
| } |
| |
| // CHECK-LABEL: tuple_test_with_reference |
| // CHECK: #0 store |
| // CHECK-NEXT: Projection Path [$*S5 |
| // CHECK-NEXT: Field: var c: (Int, Int, S3) in: $*(Int, Int, S3) |
| // CHECK-NEXT: Index: 2 in: $*S3 |
| // CHECK-NEXT: Field: var b: C1 in: $*C1] |
| // CHECK-NEXT: Projection Path [$*S5 |
| // CHECK-NEXT: Field: var c: (Int, Int, S3) in: $*(Int, Int, S3) |
| // CHECK-NEXT: Index: 2 in: $*S3 |
| // CHECK-NEXT: Field: var a: S2 in: $*S2 |
| // CHECK-NEXT: Field: var b: S1 in: $*S1 |
| // CHECK-NEXT: Field: var b: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S5 |
| // CHECK-NEXT: Field: var c: (Int, Int, S3) in: $*(Int, Int, S3) |
| // CHECK-NEXT: Index: 2 in: $*S3 |
| // CHECK-NEXT: Field: var a: S2 in: $*S2 |
| // CHECK-NEXT: Field: var b: S1 in: $*S1 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S5 |
| // CHECK-NEXT: Field: var c: (Int, Int, S3) in: $*(Int, Int, S3) |
| // CHECK-NEXT: Index: 2 in: $*S3 |
| // CHECK-NEXT: Field: var a: S2 in: $*S2 |
| // CHECK-NEXT: Field: var a: Int in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S5 |
| // CHECK-NEXT: Field: var c: (Int, Int, S3) in: $*(Int, Int, S3) |
| // CHECK-NEXT: Index: 2 in: $*S3 |
| // CHECK-NEXT: Field: var c: C1 in: $*C1] |
| // CHECK-NEXT: Projection Path [$*S5 |
| // CHECK-NEXT: Field: var c: (Int, Int, S3) in: $*(Int, Int, S3) |
| // CHECK-NEXT: Index: 1 in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| // CHECK-NEXT: Projection Path [$*S5 |
| // CHECK-NEXT: Field: var c: (Int, Int, S3) in: $*(Int, Int, S3) |
| // CHECK-NEXT: Index: 0 in: $*Int |
| // CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| sil hidden @tuple_test_with_reference : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_stack $S5, var, name "x" // users: %4, %7 |
| // function_ref test.S5.init (test.S5.Type)() -> test.S5 |
| %1 = function_ref @S5_init : $@convention(thin) (@thin S5.Type) -> @owned S5 // user: %3 |
| %2 = metatype $@thin S5.Type // user: %3 |
| %3 = apply %1(%2) : $@convention(thin) (@thin S5.Type) -> @owned S5 // users: %4, %5 |
| store %3 to %0 : $*S5 // id: %4 |
| release_value %3 : $S5 // id: %5 |
| %6 = tuple () // user: %8 |
| dealloc_stack %0 : $*S5 // id: %7 |
| return %6 : $() // id: %8 |
| } |
| |
| /// CHECK-LABEL: tuple_inside_struct |
| /// CHECK: #0 store |
| /// CHECK-NEXT: Projection Path [$*S6 |
| /// CHECK-NEXT: Field: var tuple: (Int, Int) in: $*(Int, Int) |
| /// CHECK-NEXT: Index: 1 in: $*Int |
| /// CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| /// CHECK-NEXT: Projection Path [$*S6 |
| /// CHECK-NEXT: Field: var tuple: (Int, Int) in: $*(Int, Int) |
| /// CHECK-NEXT: Index: 0 in: $*Int |
| /// CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| sil hidden @tuple_inside_struct : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_stack $S6, var, name "x" // users: %4, %7 |
| %1 = function_ref @S6_init : $@convention(thin) (@thin S6.Type) -> S6 // user: %3 |
| %2 = metatype $@thin S6.Type // user: %3 |
| %3 = apply %1(%2) : $@convention(thin) (@thin S6.Type) -> S6 // users: %4, %5 |
| store %3 to %0 : $*S6 // id: %4 |
| %6 = tuple () // user: %8 |
| dealloc_stack %0 : $*S6 // id: %7 |
| return %6 : $() // id: %8 |
| } |
| |
| /// Given an enum type, we expands it into nothing as its meaningless to call |
| /// getStoredProperties on enum without specifying the tag. Enum is sort of |
| /// like union in C, i.e. its memory can be interpreted differently depending |
| /// on the chosen tag. |
| /// |
| /// CHECK-LABEL: enum_test |
| /// CHECK: #0 store |
| /// CHECK-NOT: Int64 |
| /// CHECK-NOT: Int32 |
| /// CHECK: #1 store |
| /// CHECK-NEXT: Projection Path [$*Int |
| /// CHECK-NEXT: Field: var value: Int64 in: $*Builtin.Int64] |
| sil hidden @enum_test : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_stack $Example, var, name "ee" // users: %5, %11 |
| %1 = alloc_stack $Int, var, name "a" // users: %8, %10 |
| %2 = integer_literal $Builtin.Int64, 10 // user: %3 |
| %3 = struct $Int64 (%2 : $Builtin.Int64) // user: %4 |
| %4 = enum $Example, #Example.A!enumelt.1, %3 : $Int64 // user: %5 |
| store %4 to %0 : $*Example // id: %5 |
| %6 = integer_literal $Builtin.Int64, 10 // user: %7 |
| %7 = struct $Int (%6 : $Builtin.Int64) // user: %8 |
| store %7 to %1 : $*Int // id: %8 |
| %9 = tuple () // user: %12 |
| dealloc_stack %1 : $*Int // id: %10 |
| dealloc_stack %0 : $*Example // id: %11 |
| return %9 : $() // id: %12 |
| } |