| // RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil %s -gnone -emit-ir -disable-objc-attr-requires-foundation-module | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime-%target-ptrsize |
| |
| // REQUIRES: CPU=i386_or_x86_64 |
| |
| // We have to claim this is raw SIL because there are critical edges from non |
| // cond_br instructions. |
| sil_stage raw |
| |
| import Builtin |
| import Swift |
| |
| // -- Singleton enum. The representation is just the singleton payload. |
| // CHECK: %O4enum9Singleton = type <{ <{ i64, i64 }> }> |
| |
| // -- Singleton enum with heap object ref payload. <rdar://problem/15679353> |
| // CHECK: %O4enum12SingletonRef = type <{ %swift.refcounted* }> |
| |
| // -- No-payload enums. The representation is just an enum tag. |
| // CHECK: %O4enum10NoPayloads = type <{ i8 }> |
| // CHECK: %O4enum11NoPayloads2 = type <{ i8 }> |
| |
| // -- Single-payload enum, no extra inhabitants in the payload type. The |
| // representation adds a tag bit to distinguish payload from enum tag: |
| // case x(i64): X0 X1 X2 ... X63 | 0, where X0...X63 are the payload bits |
| // case y: 0 0 0 ... 0 | 1 |
| // case z: 1 0 0 ... 0 | 1 |
| // CHECK-64: %O4enum17SinglePayloadNoXI = type <{ [8 x i8], [1 x i8] }> |
| // CHECK-64: %O4enum18SinglePayloadNoXI2 = type <{ [8 x i8], [1 x i8] }> |
| // CHECK-32: %O4enum17SinglePayloadNoXI = type <{ [4 x i8], [1 x i8] }> |
| // CHECK-32: %O4enum18SinglePayloadNoXI2 = type <{ [4 x i8], [1 x i8] }> |
| |
| // -- Single-payload enum, spare bits. The representation uses a tag bit |
| // out of the payload to distinguish payload from enum tag: |
| // case x(i3): X0 X1 X2 0 0 0 0 0 |
| // case y: 0 0 0 1 0 0 0 0 |
| // case z: 1 0 0 1 0 0 0 0 |
| // CHECK: %O4enum21SinglePayloadSpareBit = type <{ [8 x i8] }> |
| |
| // -- Single-payload enum containing a no-payload enum as its payload. |
| // The representation takes extra inhabitants starting after the greatest |
| // discriminator value used by the nested no-payload enum. |
| // CHECK: %O4enum19SinglePayloadNested = type <{ [1 x i8] }> |
| |
| // -- Single-payload enum containing another single-payload enum as its |
| // payload. |
| // The representation takes extra inhabitants from the nested enum's payload |
| // that were unused by the nested enum. |
| // CHECK: %O4enum25SinglePayloadNestedNested = type <{ [1 x i8] }> |
| |
| // -- Multi-payload enum, no spare bits. The representation adds tag bits |
| // to discriminate payloads. No-payload cases all share a tag. |
| // case x(i8): X0 X1 X2 ... X7 X8 | 0 0 |
| // case y(i7): Y0 Y1 Y2 ... Y7 0 | 1 0 |
| // case z(i2): Z0 Z1 0 ... 0 0 | 0 1 |
| // case a: 0 0 0 ... 0 0 | 1 1 |
| // case b: 1 0 0 ... 0 0 | 1 1 |
| // case c: 0 1 0 ... 0 0 | 1 1 |
| // CHECK: %O4enum23MultiPayloadNoSpareBits = type <{ [8 x i8], [1 x i8] }> |
| |
| // -- Multi-payload enum, one spare bit. The representation uses spare bits |
| // common to all payloads to partially discriminate payloads, with added |
| // tag bits to cover the gap. No-payload cases all share a tag. |
| // case x(i7): X0 X1 X2 X3 X4 X5 X6 0 | 0 |
| // case y(i1): Y 0 0 0 0 0 0 1 | 0 |
| // case z(i5): Z0 Z1 Z2 Z3 Z4 0 0 0 | 1 |
| // case a: 0 0 0 0 0 0 0 1 | 1 |
| // case b: 1 0 0 0 0 0 0 1 | 1 |
| // case c: 0 1 0 0 0 0 0 1 | 1 |
| // CHECK: %O4enum23MultiPayloadOneSpareBit = type <{ [8 x i8], [1 x i8] }> |
| |
| // -- Multi-payload enum, two spare bits. Same as above, except we have enough |
| // spare bits not to require any added tag bits. |
| // case x(i6): X0 X1 X2 X3 X4 X5 0 0 |
| // case y(i1): Y 0 0 0 0 0 1 0 |
| // case z(i5): Z0 Z1 Z2 Z3 Z4 0 0 1 |
| // case a: 0 0 0 0 0 0 1 1 |
| // case b: 1 0 0 0 0 0 1 1 |
| // case c: 0 1 0 0 0 0 1 1 |
| // CHECK: %O4enum24MultiPayloadTwoSpareBits = type <{ [8 x i8] }> |
| |
| // CHECK-64: %O4enum30MultiPayloadSpareBitAggregates = type <{ [16 x i8] }> |
| |
| // CHECK-64: %O4enum18MultiPayloadNested = type <{ [9 x i8] }> |
| // CHECK-32: %O4enum18MultiPayloadNested = type <{ [5 x i8] }> |
| |
| // 32-bit object references don't have enough spare bits. |
| // CHECK-64: %O4enum27MultiPayloadNestedSpareBits = type <{ [8 x i8] }> |
| |
| // -- Dynamic enums. The type layout is opaque; we dynamically bitcast to |
| // the element type. |
| // CHECK: %O4enum20DynamicSinglePayload = type <{}> |
| // CHECK: [[DYNAMIC_SINGLE_EMPTY_PAYLOAD:%GO4enum20DynamicSinglePayloadT__]] = type <{ [1 x i8] }> |
| |
| // -- Address-only multi-payload enums. We can't use spare bits. |
| // CHECK-64: %O4enum32MultiPayloadAddressOnlySpareBits = type <{ [16 x i8], [1 x i8] }> |
| // CHECK-32: %O4enum32MultiPayloadAddressOnlySpareBits = type <{ [8 x i8], [1 x i8] }> |
| |
| // CHECK: [[DYNAMIC_SINGLETON:%O4enum16DynamicSingleton.*]] = type <{}> |
| |
| // CHECK: %O4enum40MultiPayloadLessThan32BitsWithEmptyCases = type <{ [1 x i8], [1 x i8] }> |
| |
| // -- Dynamic metadata template carries a value witness table pattern |
| // we fill in on instantiation. |
| // The witness table pattern includes extra inhabitant witness |
| // implementations which are used if the instance has extra inhabitants. |
| // FIXME: Strings should be unnamed_addr. rdar://problem/22674524 |
| // CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private constant [7 x i8] c"value\00\00" |
| // CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [25 x i8] c"O4enum16DynamicSingleton\00" |
| // CHECK: @_TMnO4enum16DynamicSingleton = hidden constant <{ {{.*}} i32 }> <{ |
| // CHECK: [25 x i8]* [[DYNAMICSINGLETON_NAME]] |
| // -- One payload |
| // CHECK: i32 1, |
| // -- No empty cases |
| // CHECK: i32 0, |
| // -- Case names |
| // CHECK: [[DYNAMICSINGLETON_FIELD_NAMES]] |
| // -- Case type accessor |
| // CHECK: @get_field_types_DynamicSingleton |
| // -- generic parameter vector offset |
| // CHECK: i32 3, |
| // -- generic parameter vector length; witness table counts |
| // CHECK: i32 1, i32 0 |
| // CHECK: }> |
| |
| // CHECK: @_TMPO4enum16DynamicSingleton = hidden global <{ {{.*}}* }> <{ |
| // CHECK: %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSingleton |
| // CHECK: @_TMnO4enum16DynamicSingleton |
| // CHECK: i8* null |
| // CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum16DynamicSingleton to i8*) |
| // CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum16DynamicSingleton to i8*) |
| |
| // -- No-payload enums have extra inhabitants in |
| // their value witness table. |
| // CHECK: @_TWVO4enum10NoPayloads = hidden constant [26 x i8*] [ |
| // -- ... |
| // -- size |
| // CHECK: i8* inttoptr ([[WORD:i32|i64]] 1 to i8*), |
| // -- flags 0x24_0000 - alignment 1, has extra inhabitants and enum witnesses |
| // CHECK: i8* inttoptr ([[WORD]] 2359296 to i8*), |
| // -- stride |
| // CHECK: i8* inttoptr ([[WORD]] 1 to i8*), |
| // -- num extra inhabitants (256 - 3 valid states) |
| // CHECK: i8* inttoptr ([[WORD]] 253 to i8*) |
| // -- storeExtraInhabitant |
| // CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum10NoPayloads to i8*) |
| // -- getExtraInhabitantIndex |
| // CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum10NoPayloads to i8*) |
| // CHECK: ] |
| |
| // -- Single-payload enums take unused extra inhabitants from their payload |
| // as their own. |
| // CHECK: @_TWVO4enum19SinglePayloadNested = hidden constant [26 x i8*] [ |
| // -- ... |
| // -- size |
| // CHECK: i8* inttoptr ([[WORD]] 1 to i8*), |
| // -- flags 0x4_0000 - alignment 1, has extra inhabitants |
| // CHECK: i8* inttoptr ([[WORD]] 2359296 to i8*), |
| // -- stride |
| // CHECK: i8* inttoptr ([[WORD]] 1 to i8*), |
| // -- num extra inhabitants (253 from payload - 3 empty cases) |
| // CHECK: i8* inttoptr ([[WORD]] 250 to i8*) |
| // -- storeExtraInhabitant |
| // CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum19SinglePayloadNested to i8*) |
| // -- getExtraInhabitantIndex |
| // CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum19SinglePayloadNested to i8*) |
| // CHECK: ] |
| |
| |
| // CHECK: @_TMPO4enum20DynamicSinglePayload = hidden global <{ {{.*}}* }> <{ |
| // CHECK: %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSinglePayload |
| // CHECK: i8* null |
| // CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum20DynamicSinglePayload to i8*) |
| // CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum20DynamicSinglePayload to i8*) |
| |
| // CHECK: @_TWVO4enum18MultiPayloadNested = hidden constant [26 x i8*] [ |
| // CHECK: i8* inttoptr ([[WORD]] 9 to i8*), |
| // CHECK: i8* inttoptr ([[WORD]] 16 to i8*) |
| // CHECK: ] |
| |
| enum Empty {} |
| |
| enum EmptySingleton { |
| case foo |
| } |
| |
| enum Singleton { |
| case value(Builtin.Int64, Builtin.Int64) |
| } |
| |
| enum SingletonRef { |
| case value(Builtin.NativeObject) |
| } |
| |
| enum DynamicSingleton<T> { |
| case value(T) |
| } |
| |
| // CHECK: define{{( protected)?}} void @singleton_switch(i64, i64) {{.*}} { |
| sil @singleton_switch : $(Singleton) -> () { |
| // CHECK: entry: |
| entry(%u : $Singleton): |
| // CHECK: br label %[[DEST:[0-9]+]] |
| switch_enum %u : $Singleton, case #Singleton.value!enumelt.1: dest |
| |
| // CHECK: ; <label>:[[DEST]] |
| dest: |
| // CHECK: ret void |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} void @singleton_switch_arg(i64, i64) {{.*}} { |
| sil @singleton_switch_arg : $(Singleton) -> () { |
| // CHECK: entry: |
| entry(%u : $Singleton): |
| // CHECK: br label %[[PREDEST:[0-9]+]] |
| switch_enum %u : $Singleton, case #Singleton.value!enumelt.1: dest |
| |
| // CHECK: ; <label>:[[PREDEST]] |
| // CHECK: br label %[[DEST:[0-9]+]] |
| // CHECK: ; <label>:[[DEST]] |
| dest(%u2 : $(Builtin.Int64, Builtin.Int64)): |
| // CHECK: {{%.*}} = phi i64 [ %0, %[[PREDEST]] ] |
| // CHECK: {{%.*}} = phi i64 [ %1, %[[PREDEST]] ] |
| // CHECK: ret void |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} void @singleton_switch_indirect(%O4enum9Singleton* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: entry: |
| // CHECK: br label %[[DEST:[0-9]+]] |
| // CHECK: ; <label>:[[DEST]] |
| // CHECK: [[ADDR:%.*]] = bitcast %O4enum9Singleton* %0 to <{ i64, i64 }>* |
| // CHECK: ret void |
| // CHECK: } |
| sil @singleton_switch_indirect : $(@inout Singleton) -> () { |
| entry(%u : $*Singleton): |
| switch_enum_addr %u : $*Singleton, case #Singleton.value!enumelt.1: dest |
| dest: |
| %u2 = unchecked_take_enum_data_addr %u : $*Singleton, #Singleton.value!enumelt.1 |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} { i64, i64 } @singleton_inject(i64, i64) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[A:%.*]] = insertvalue { i64, i64 } undef, i64 %0, 0 |
| // CHECK: [[B:%.*]] = insertvalue { i64, i64 } [[A]], i64 %1, 1 |
| // CHECK: ret { i64, i64 } [[B]] |
| // CHECK: } |
| sil @singleton_inject : $(Builtin.Int64, Builtin.Int64) -> Singleton { |
| entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64): |
| %t = tuple (%0 : $Builtin.Int64, %1 : $Builtin.Int64) |
| %u = enum $Singleton, #Singleton.value!enumelt.1, %t : $(Builtin.Int64, Builtin.Int64) |
| return %u : $Singleton |
| } |
| |
| // CHECK: define{{( protected)?}} void @singleton_inject_indirect(i64, i64, %O4enum9Singleton* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum9Singleton* %2 to <{ i64, i64 }>* |
| // CHECK: [[DATA_0_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 0 |
| // CHECK: store i64 %0, i64* [[DATA_0_ADDR]] |
| // CHECK: [[DATA_1_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 1 |
| // CHECK: store i64 %1, i64* [[DATA_1_ADDR]] |
| // CHECK: ret void |
| // CHECK: } |
| sil @singleton_inject_indirect : $(Builtin.Int64, Builtin.Int64, @inout Singleton) -> () { |
| entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64, %2 : $*Singleton): |
| %t = tuple (%0 : $Builtin.Int64, %1 : $Builtin.Int64) |
| %a = init_enum_data_addr %2 : $*Singleton, #Singleton.value!enumelt.1 |
| store %t to %a : $*(Builtin.Int64, Builtin.Int64) |
| inject_enum_addr %2 : $*Singleton, #Singleton.value!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| |
| enum NoPayloads { |
| case x |
| case y |
| case z |
| } |
| |
| sil @a : $@convention(thin) () -> () |
| sil @b : $@convention(thin) () -> () |
| sil @c : $@convention(thin) () -> () |
| sil @d : $@convention(thin) () -> () |
| sil @e : $@convention(thin) () -> () |
| sil @f : $@convention(thin) () -> () |
| |
| |
| // CHECK: define{{( protected)?}} void @no_payload_switch(i8) {{.*}} { |
| sil @no_payload_switch : $@convention(thin) (NoPayloads) -> () { |
| // CHECK: entry: |
| entry(%u : $NoPayloads): |
| // CHECK: switch i8 %0, label %[[DFLT:[0-9]+]] [ |
| // CHECK: i8 0, label %[[X_DEST:[0-9]+]] |
| // CHECK: i8 1, label %[[Y_DEST:[0-9]+]] |
| // CHECK: i8 2, label %[[Z_DEST:[0-9]+]] |
| // CHECK: ] |
| // CHECK: ; <label>:[[DFLT]] |
| // CHECK: unreachable |
| switch_enum %u : $NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest |
| |
| // CHECK: ; <label>:[[X_DEST]] |
| // CHECK: call void @a() |
| // CHECK: br label %[[END:[0-9]+]] |
| x_dest: |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| br end |
| // CHECK: ; <label>:[[Y_DEST]] |
| // CHECK: call void @b() |
| // CHECK: br label %[[END]] |
| y_dest: |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| br end |
| // CHECK: ; <label>:[[Z_DEST]] |
| // CHECK: call void @c() |
| // CHECK: br label %[[END]] |
| z_dest: |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[END]] |
| // CHECK: ret void |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} void @no_payload_switch_indirect(%O4enum10NoPayloads* nocapture dereferenceable({{.*}})) {{.*}} { |
| sil @no_payload_switch_indirect : $@convention(thin) (@inout NoPayloads) -> () { |
| entry(%u : $*NoPayloads): |
| // CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads, %O4enum10NoPayloads* %0, i32 0, i32 0 |
| // CHECK: [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]] |
| // CHECK: switch i8 [[TAG]] |
| switch_enum_addr %u : $*NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest |
| |
| x_dest: |
| br end |
| y_dest: |
| br end |
| z_dest: |
| br end |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} i8 @no_payload_inject_x() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret i8 0 |
| // CHECK: } |
| sil @no_payload_inject_x : $() -> NoPayloads { |
| entry: |
| %u = enum $NoPayloads, #NoPayloads.x!enumelt |
| return %u : $NoPayloads |
| } |
| |
| // CHECK: define{{( protected)?}} i8 @no_payload_inject_y() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret i8 1 |
| // CHECK: } |
| sil @no_payload_inject_y : $() -> NoPayloads { |
| entry: |
| %u = enum $NoPayloads, #NoPayloads.y!enumelt |
| return %u : $NoPayloads |
| } |
| |
| // CHECK: define{{( protected)?}} i8 @no_payload_inject_z() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret i8 2 |
| // CHECK: } |
| sil @no_payload_inject_z : $() -> NoPayloads { |
| entry: |
| %u = enum $NoPayloads, #NoPayloads.z!enumelt |
| return %u : $NoPayloads |
| } |
| |
| // CHECK: define{{( protected)?}} void @no_payload_inject_z_indirect(%O4enum10NoPayloads* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads, %O4enum10NoPayloads* %0, i32 0, i32 0 |
| // CHECK: store i8 2, i8* [[TAG_ADDR]] |
| // CHECK: ret void |
| // CHECK: } |
| sil @no_payload_inject_z_indirect : $(@inout NoPayloads) -> () { |
| entry(%0 : $*NoPayloads): |
| inject_enum_addr %0 : $*NoPayloads, #NoPayloads.z!enumelt |
| %v = tuple () |
| return %v : $() |
| } |
| |
| |
| enum NoPayloads2 { |
| case a |
| case e |
| case i |
| case o |
| case u |
| case y |
| } |
| |
| // CHECK: define{{( protected)?}} void @no_payload_switch_2(i8) {{.*}} { |
| sil @no_payload_switch_2 : $@convention(thin) (NoPayloads2) -> () { |
| // CHECK: entry: |
| entry(%u : $NoPayloads2): |
| // CHECK: [[COND:%.*]] = icmp ne i8 %0, 4 |
| // CHECK: br i1 [[COND]], label %[[DEFAULT_DEST:[0-9]+]], label %[[U_DEST:[0-9]+]] |
| switch_enum %u : $NoPayloads2, case #NoPayloads2.u!enumelt: u_dest, default default_dest |
| |
| // CHECK: ; <label>:[[U_DEST]] |
| u_dest: |
| // CHECK: call void @a() |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| // CHECK: br label %[[END:[0-9]+]] |
| br end |
| |
| // CHECK: ; <label>:[[DEFAULT_DEST]] |
| default_dest: |
| // CHECK: call void @b() |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| // CHECK: br label %[[END]] |
| br end |
| |
| // CHECK: ; <label>:[[END]] |
| end: |
| // CHECK: ret void |
| %x = tuple () |
| return %x : $() |
| } |
| |
| |
| enum SinglePayloadNoXI { |
| case x(Builtin.Word) |
| case y |
| } |
| |
| enum SinglePayloadNoXI2 { |
| case x(Builtin.Word) |
| case y |
| case z |
| case w |
| case v |
| case u |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_no_xi_switch([[WORD:i64]], i1) {{.*}} { |
| // CHECK-32: define{{( protected)?}} void @single_payload_no_xi_switch([[WORD:i32]], i1) {{.*}} { |
| sil @single_payload_no_xi_switch : $@convention(thin) (SinglePayloadNoXI2) -> () { |
| // CHECK: entry: |
| entry(%u : $SinglePayloadNoXI2): |
| // CHECK: br i1 %1, label %[[TAGS:[0-9]+]], label %[[X_DEST:[0-9]+]] |
| // CHECK: ; <label>:[[TAGS]] |
| // CHECK: switch [[WORD]] %0, label %[[DFLT:[0-9]+]] [ |
| // CHECK: [[WORD]] 0, label %[[Y_DEST:[0-9]+]] |
| // CHECK: [[WORD]] 1, label %[[Z_DEST:[0-9]+]] |
| // CHECK: [[WORD]] 2, label %[[W_DEST:[0-9]+]] |
| // CHECK: [[WORD]] 3, label %[[V_DEST:[0-9]+]] |
| // CHECK: [[WORD]] 4, label %[[U_DEST:[0-9]+]] |
| // CHECK: ] |
| // CHECK: ; <label>:[[DFLT]] |
| // CHECK: unreachable |
| switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt.1: x_dest, case #SinglePayloadNoXI2.y!enumelt: y_dest, case #SinglePayloadNoXI2.z!enumelt: z_dest, case #SinglePayloadNoXI2.w!enumelt: w_dest, case #SinglePayloadNoXI2.v!enumelt: v_dest, case #SinglePayloadNoXI2.u!enumelt: u_dest |
| |
| |
| // CHECK: ; <label>:[[X_DEST]] |
| // CHECK: call void @a() |
| // CHECK: br label %[[END:[0-9]+]] |
| x_dest: |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[Y_DEST]] |
| // CHECK: call void @b() |
| // CHECK: br label %[[END]] |
| y_dest: |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[Z_DEST]] |
| // CHECK: call void @c() |
| // CHECK: br label %[[END]] |
| z_dest: |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[W_DEST]] |
| // CHECK: call void @a() |
| // CHECK: br label %[[END:[0-9]+]] |
| w_dest: |
| %d = function_ref @a : $@convention(thin) () -> () |
| apply %d() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[V_DEST]] |
| // CHECK: call void @b() |
| // CHECK: br label %[[END]] |
| v_dest: |
| %e = function_ref @b : $@convention(thin) () -> () |
| apply %e() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[U_DEST]] |
| // CHECK: call void @c() |
| // CHECK: br label %[[END]] |
| u_dest: |
| %f = function_ref @c : $@convention(thin) () -> () |
| apply %f() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[END]] |
| // CHECK: ret void |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} void @single_payload_no_xi_switch_arg([[WORD]], i1) {{.*}} { |
| sil @single_payload_no_xi_switch_arg : $@convention(thin) (SinglePayloadNoXI2) -> () { |
| // CHECK: entry: |
| entry(%u : $SinglePayloadNoXI2): |
| // CHECK: br i1 %1, label %[[TAGS:[0-9]+]], label %[[X_PREDEST:[0-9]+]] |
| // CHECK: ; <label>:[[TAGS]] |
| // CHECK: switch [[WORD]] %0, label %[[DFLT:[0-9]+]] [ |
| // CHECK: [[WORD]] 0, label %[[Y_DEST:[0-9]+]] |
| // CHECK: [[WORD]] 1, label %[[Z_DEST:[0-9]+]] |
| // CHECK: [[WORD]] 2, label %[[SPLITEDGE:[0-9]+]] |
| // CHECK: [[WORD]] 3, label %[[SPLITEDGE]] |
| // CHECK: [[WORD]] 4, label %[[SPLITEDGE]] |
| // CHECK: ] |
| // CHECK: ; <label>:[[DFLT]] |
| // CHECK: unreachable |
| switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt.1: x_dest, case #SinglePayloadNoXI2.y!enumelt: y_dest, case #SinglePayloadNoXI2.z!enumelt: z_dest, default end |
| |
| // CHECK: ; <label>:[[X_PREDEST]] |
| // CHECK: br label %[[X_DEST:[0-9]+]] |
| // CHECK: ; <label>:[[SPLITEDGE]] |
| // CHECK: br label %[[END:[0-9]+]] |
| // CHECK: ; <label>:[[X_DEST]] |
| // CHECK: {{%.*}} = phi [[WORD]] [ %0, %[[X_PREDEST]] ] |
| x_dest(%u2 : $Builtin.Word): |
| // CHECK: call void @a() |
| // CHECK: br label %[[END]] |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[Y_DEST]] |
| y_dest: |
| // CHECK: call void @b() |
| // CHECK: br label %[[END]] |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[Z_DEST]] |
| z_dest: |
| // CHECK: call void @c() |
| // CHECK: br label %[[END]] |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK: ; <label>:[[END]] |
| // CHECK: ret void |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} { [[WORD]], i1 } @single_payload_no_xi_inject_x([[WORD]]) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[A:%.*]] = insertvalue { [[WORD]], i1 } undef, [[WORD]] %0, 0 |
| // CHECK: [[B:%.*]] = insertvalue { [[WORD]], i1 } [[A]], i1 false, 1 |
| // CHECK: ret { [[WORD]], i1 } [[B]] |
| // CHECK: } |
| sil @single_payload_no_xi_inject_x : $(Builtin.Word) -> SinglePayloadNoXI2 { |
| entry(%0 : $Builtin.Word): |
| %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1, %0 : $Builtin.Word |
| return %u : $SinglePayloadNoXI2 |
| } |
| |
| // CHECK: define{{( protected)?}} void @single_payload_no_xi_inject_x_indirect([[WORD]], %O4enum18SinglePayloadNoXI2* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %1 to [[WORD]]* |
| // CHECK: store [[WORD]] %0, [[WORD]]* [[DATA_ADDR]] |
| // CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2, %O4enum18SinglePayloadNoXI2* %1, i32 0, i32 1 |
| // CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1* |
| // CHECK: store i1 false, i1* [[TAG_ADDR]] |
| // CHECK: ret void |
| // CHECK: } |
| sil @single_payload_no_xi_inject_x_indirect : $(Builtin.Word, @inout SinglePayloadNoXI2) -> () { |
| entry(%0 : $Builtin.Word, %1 : $*SinglePayloadNoXI2): |
| %a = init_enum_data_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1 |
| store %0 to %a : $*Builtin.Word |
| inject_enum_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK: define{{( protected)?}} { [[WORD]], i1 } @single_payload_no_xi_inject_y() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret { [[WORD]], i1 } { [[WORD]] 0, i1 true } |
| // CHECK: } |
| sil @single_payload_no_xi_inject_y : $() -> SinglePayloadNoXI2 { |
| entry: |
| %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt |
| return %u : $SinglePayloadNoXI2 |
| } |
| |
| // CHECK: define{{( protected)?}} void @single_payload_no_xi_inject_y_indirect(%O4enum18SinglePayloadNoXI2* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %0 to [[WORD]]* |
| // CHECK: store [[WORD]] 0, [[WORD]]* [[PAYLOAD_ADDR]] |
| // CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2, %O4enum18SinglePayloadNoXI2* %0, i32 0, i32 1 |
| // CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1* |
| // CHECK: store i1 true, i1* [[TAG_ADDR]] |
| // CHECK: ret void |
| // CHECK: } |
| sil @single_payload_no_xi_inject_y_indirect : $(@inout SinglePayloadNoXI2) -> () { |
| entry(%0 : $*SinglePayloadNoXI2): |
| inject_enum_addr %0 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK: define{{( protected)?}} { [[WORD]], i1 } @single_payload_no_xi_inject_z() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret { [[WORD]], i1 } { [[WORD]] 1, i1 true } |
| // CHECK: } |
| sil @single_payload_no_xi_inject_z : $() -> SinglePayloadNoXI2 { |
| entry: |
| %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.z!enumelt |
| return %u : $SinglePayloadNoXI2 |
| } |
| |
| |
| // -- Test packing and unpacking aggregates. |
| |
| enum AggregateSinglePayload { |
| case x(Builtin.Word, Builtin.Word) |
| case y |
| case z |
| } |
| |
| sil @int21_sink : $@convention(thin) (Builtin.Int21) -> () |
| sil @int64_sink : $@convention(thin) (Builtin.Word) -> () |
| |
| // CHECK-LABEL: define{{( protected)?}} void @aggregate_single_payload_unpack |
| // CHECK: ([[WORD]], [[WORD]], i1) {{.*}} { |
| sil @aggregate_single_payload_unpack : $@convention(thin) (AggregateSinglePayload) -> () { |
| entry(%u : $AggregateSinglePayload): |
| switch_enum %u : $AggregateSinglePayload, case #AggregateSinglePayload.x!enumelt.1: x_dest, default end |
| |
| // CHECK: [[FIRST:%.*]] = phi [[WORD]] [ %0 |
| // CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1 |
| // CHECK: call void @int64_sink([[WORD]] [[FIRST]]) |
| // CHECK: call void @int64_sink([[WORD]] [[SECOND]]) |
| x_dest(%v : $(Builtin.Word, Builtin.Word)): |
| %f = function_ref @int64_sink : $@convention(thin) (Builtin.Word) -> () |
| %a = tuple_extract %v : $(Builtin.Word, Builtin.Word), 0 |
| %b = tuple_extract %v : $(Builtin.Word, Builtin.Word), 1 |
| %c = apply %f(%a) : $@convention(thin) (Builtin.Word) -> () |
| %d = apply %f(%b) : $@convention(thin) (Builtin.Word) -> () |
| br end |
| |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} { [[WORD]], [[WORD]] } @aggregate_single_payload_unsafe_unpack([[WORD]], [[WORD]], i1) {{.*}} { |
| // CHECK: [[A:%.*]] = insertvalue { [[WORD]], [[WORD]] } undef, [[WORD]] %0, 0 |
| // CHECK: [[B:%.*]] = insertvalue { [[WORD]], [[WORD]] } [[A]], [[WORD]] %1, 1 |
| // CHECK: ret { [[WORD]], [[WORD]] } [[B]] |
| sil @aggregate_single_payload_unsafe_unpack : $@convention(thin) (AggregateSinglePayload) -> (Builtin.Word, Builtin.Word) { |
| entry(%u : $AggregateSinglePayload): |
| %x = unchecked_enum_data %u : $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1 |
| return %x : $(Builtin.Word, Builtin.Word) |
| } |
| |
| // CHECK: define{{( protected)?}} { [[WORD]], [[WORD]], i1 } @aggregate_single_payload_inject([[WORD]], [[WORD]]) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[RES_0:%.*]] = insertvalue { [[WORD]], [[WORD]], i1 } undef, [[WORD]] %0, 0 |
| // CHECK: [[RES_1:%.*]] = insertvalue { [[WORD]], [[WORD]], i1 } [[RES_0]], [[WORD]] %1, 1 |
| // CHECK: [[RES:%.*]] = insertvalue { [[WORD]], [[WORD]], i1 } [[RES_1]], i1 false, 2 |
| // CHECK: ret { [[WORD]], [[WORD]], i1 } [[RES]] |
| // CHECK: } |
| sil @aggregate_single_payload_inject : $(Builtin.Word, Builtin.Word) -> AggregateSinglePayload { |
| entry(%0 : $Builtin.Word, %1 : $Builtin.Word): |
| %t = tuple (%0 : $Builtin.Word, %1 : $Builtin.Word) |
| %u = enum $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1, %t : $(Builtin.Word, Builtin.Word) |
| return %u : $AggregateSinglePayload |
| } |
| |
| struct CharLike { var value : Builtin.Int21 } |
| struct IntLike { var value : Builtin.Word } |
| struct RangeLike { var from, to : Builtin.Word } |
| |
| enum AggregateSinglePayload2 { |
| case x(CharLike, IntLike, RangeLike) |
| case y |
| case z |
| } |
| |
| // CHECK: define{{( protected)?}} void @aggregate_single_payload_unpack_2(%O4enum23AggregateSinglePayload2* noalias nocapture dereferenceable({{.*}})) {{.*}} { |
| sil @aggregate_single_payload_unpack_2 : $@convention(thin) (AggregateSinglePayload2) -> () { |
| entry(%u : $AggregateSinglePayload2): |
| // CHECK: [[CHUNK0:%.*]] = load [[WORD]] |
| // CHECK: [[CHUNK1:%.*]] = load [[WORD]] |
| // CHECK: [[CHUNK2:%.*]] = load [[WORD]] |
| // CHECK: [[CHUNK3:%.*]] = load [[WORD]] |
| switch_enum %u : $AggregateSinglePayload2, case #AggregateSinglePayload2.x!enumelt.1: x_dest, default end |
| |
| // CHECK: [[TRUNC:%.*]] = trunc [[WORD]] [[CHUNK0]] to i21 |
| // CHECK: phi i21 [ [[TRUNC]] |
| // CHECK: phi [[WORD]] [ [[CHUNK1]] |
| // CHECK: phi [[WORD]] [ [[CHUNK2]] |
| // CHECK: phi [[WORD]] [ [[CHUNK3]] |
| x_dest(%v : $(CharLike, IntLike, RangeLike)): |
| br end |
| |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} void @aggregate_single_payload_2_inject(%O4enum23AggregateSinglePayload2* noalias nocapture sret, i21, [[WORD]], [[WORD]], [[WORD]]) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[ZEXT_0:%.*]] = zext i21 %1 to [[WORD]] |
| // CHECK: store [[WORD]] [[ZEXT_0]] |
| // CHECK: store [[WORD]] %2 |
| // CHECK: store [[WORD]] %3 |
| // CHECK: store [[WORD]] %4 |
| // CHECK: } |
| sil @aggregate_single_payload_2_inject : $(CharLike, IntLike, RangeLike) -> AggregateSinglePayload2 { |
| entry(%0 : $CharLike, %1 : $IntLike, %2 : $RangeLike): |
| %t = tuple (%0 : $CharLike, %1 : $IntLike, %2 : $RangeLike) |
| %u = enum $AggregateSinglePayload2, #AggregateSinglePayload2.x!enumelt.1, %t : $(CharLike, IntLike, RangeLike) |
| return %u : $AggregateSinglePayload2 |
| } |
| |
| enum AggregateSinglePayload3 { |
| case x(Builtin.Int21, Builtin.Word) |
| case y |
| case z |
| } |
| |
| // CHECK: define{{( protected)?}} void @aggregate_single_payload_unpack_3([[WORD]], [[WORD]]) {{.*}} { |
| sil @aggregate_single_payload_unpack_3 : $@convention(thin) (AggregateSinglePayload3) -> () { |
| entry(%u : $AggregateSinglePayload3): |
| switch_enum %u : $AggregateSinglePayload3, case #AggregateSinglePayload3.x!enumelt.1: x_dest, default end |
| |
| // CHECK: [[TRUNC:%.*]] = trunc [[WORD]] %0 to i21 |
| // CHECK: [[FIRST:%.*]] = phi i21 [ [[TRUNC]] |
| // CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1 |
| // CHECK: call void @int21_sink(i21 [[FIRST]]) |
| // CHECK: call void @int64_sink([[WORD]] [[SECOND]]) |
| x_dest(%v : $(Builtin.Int21, Builtin.Word)): |
| %f = function_ref @int21_sink : $@convention(thin) (Builtin.Int21) -> () |
| %g = function_ref @int64_sink : $@convention(thin) (Builtin.Word) -> () |
| %a = tuple_extract %v : $(Builtin.Int21, Builtin.Word), 0 |
| %b = tuple_extract %v : $(Builtin.Int21, Builtin.Word), 1 |
| %c = apply %f(%a) : $@convention(thin) (Builtin.Int21) -> () |
| %d = apply %g(%b) : $@convention(thin) (Builtin.Word) -> () |
| br end |
| |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK: define{{( protected)?}} { [[WORD]], [[WORD]] } @aggregate_single_payload_inject_x3(i21, [[WORD]]) {{.*}} { |
| // CHECK: entry: |
| // CHECK: [[ZEXT_0:%.*]] = zext i21 %0 to [[WORD]] |
| // CHECK: [[A:%.*]] = insertvalue { [[WORD]], [[WORD]] } undef, [[WORD]] [[ZEXT_0]], 0 |
| // CHECK: [[B:%.*]] = insertvalue { [[WORD]], [[WORD]] } [[A]], [[WORD]] %1, 1 |
| // CHECK: ret { [[WORD]], [[WORD]] } [[B]] |
| // CHECK: } |
| sil @aggregate_single_payload_inject_x3 : $(Builtin.Int21, Builtin.Word) -> AggregateSinglePayload3 { |
| entry(%0 : $Builtin.Int21, %1 : $Builtin.Word): |
| %t = tuple (%0 : $Builtin.Int21, %1 : $Builtin.Word) |
| %u = enum $AggregateSinglePayload3, #AggregateSinglePayload3.x!enumelt.1, %t : $(Builtin.Int21, Builtin.Word) |
| return %u : $AggregateSinglePayload3 |
| } |
| |
| // CHECK: define{{( protected)?}} { [[WORD]], [[WORD]] } @aggregate_single_payload_inject_y3() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret { [[WORD]], [[WORD]] } { [[WORD]] 2097152, [[WORD]] 0 } |
| // CHECK: } |
| // 2097152 == 0x200000 |
| sil @aggregate_single_payload_inject_y3 : $() -> AggregateSinglePayload3 { |
| entry: |
| %u = enum $AggregateSinglePayload3, #AggregateSinglePayload3.y!enumelt |
| return %u : $AggregateSinglePayload3 |
| } |
| |
| enum SinglePayloadSpareBit { |
| case x(Builtin.Int63) |
| case y |
| case z |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_spare_bit_switch(i64) {{.*}} { |
| // CHECK-32: define{{( protected)?}} void @single_payload_spare_bit_switch(i32, i32) {{.*}} { |
| sil @single_payload_spare_bit_switch : $@convention(thin) (SinglePayloadSpareBit) -> () { |
| // CHECK: entry: |
| entry(%u : $SinglePayloadSpareBit): |
| // CHECK-64: switch i64 %0, label %[[X_DEST:[0-9]+]] [ |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]] |
| // -- 0x8000_0000_0000_0001 |
| // CHECK-64: i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]] |
| // CHECK-64: ] |
| |
| // CHECK-32: switch i32 %0, label %[[X_DEST:[0-9]+]] [ |
| // CHECK-32: i32 0, label %[[Y_HIGH:[0-9]+]] |
| // CHECK-32: i32 1, label %[[Z_HIGH:[0-9]+]] |
| // CHECK-32: ] |
| // CHECK-32: ; <label>:[[Y_HIGH]] |
| // CHECK-32: [[IS_Y:%.*]] = icmp eq i32 %1, -2147483648 |
| // CHECK-32: br i1 [[IS_Y]], label %[[Y_DEST:[0-9]+]], label %[[X_DEST]] |
| // CHECK-32: ; <label>:[[Z_HIGH]] |
| // CHECK-32: [[IS_Z:%.*]] = icmp eq i32 %1, -2147483648 |
| // CHECK-32: br i1 [[IS_Z]], label %[[Z_DEST:[0-9]+]], label %[[X_DEST]] |
| switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest |
| |
| // CHECK: ; <label>:[[X_DEST]] |
| x_dest: |
| // CHECK: call void @a() |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| // CHECK: br label %[[END:[0-9]+]] |
| br end |
| |
| // CHECK: ; <label>:[[Y_DEST]] |
| y_dest: |
| // CHECK: call void @b() |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| // CHECK: br label %[[END]] |
| br end |
| |
| // CHECK: ; <label>:[[Z_DEST]] |
| z_dest: |
| // CHECK: call void @c() |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| // CHECK: br label %[[END]] |
| br end |
| |
| // CHECK: ; <label>:[[END]] |
| end: |
| // CHECK: ret void |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_spare_bit_switch_arg(i64) {{.*}} { |
| sil @single_payload_spare_bit_switch_arg : $@convention(thin) (SinglePayloadSpareBit) -> () { |
| // CHECK: entry: |
| entry(%u : $SinglePayloadSpareBit): |
| // CHECK-64: switch i64 %0, label %[[X_PREDEST:[0-9]+]] [ |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]] |
| // -- 0x8000_0000_0000_0001 |
| // CHECK-64: i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]] |
| // CHECK-64: ] |
| switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest |
| |
| // CHECK-64: ; <label>:[[X_PREDEST]] |
| // CHECK-64: [[TRUNC_PAYLOAD:%.*]] = trunc i64 %0 to i63 |
| // CHECK-64: br label %[[X_DEST:[0-9]+]] |
| // CHECK-64: ; <label>:[[X_DEST]] |
| // CHECK-64: {{%.*}} = phi i63 [ [[TRUNC_PAYLOAD]], %[[X_PREDEST]] ] |
| x_dest(%u2 : $Builtin.Int63): |
| // CHECK-64: call void @a() |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| // CHECK-64: br label %[[END:[0-9]+]] |
| br end |
| |
| // CHECK-64: ; <label>:[[Y_DEST]] |
| y_dest: |
| // CHECK-64: call void @b() |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| // CHECK-64: br label %[[END]] |
| br end |
| |
| // CHECK-64: ; <label>:[[Z_DEST]] |
| z_dest: |
| // CHECK-64: call void @c() |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| // CHECK-64: br label %[[END]] |
| br end |
| |
| // CHECK-64: ; <label>:[[END]] |
| end: |
| // CHECK-64: ret void |
| %x = tuple () |
| return %x : $() |
| } |
| |
| sil @single_payload_spare_bit_switch_indirect : $@convention(thin) (@inout SinglePayloadSpareBit) -> () { |
| entry(%u : $*SinglePayloadSpareBit): |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: switch i64 [[PAYLOAD]] |
| switch_enum_addr %u : $*SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest |
| |
| // CHECK-64: ; <label>: |
| // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i63* |
| x_dest: |
| %u2 = unchecked_take_enum_data_addr %u : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1 |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| br end |
| |
| y_dest: |
| br end |
| |
| z_dest: |
| br end |
| |
| end: |
| %x = tuple () |
| return %x : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @single_payload_spare_bit_inject_x(i63) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[A:%.*]] = zext i63 %0 to i64 |
| // CHECK-64: ret i64 [[A]] |
| // CHECK-64: } |
| sil @single_payload_spare_bit_inject_x : $(Builtin.Int63) -> SinglePayloadSpareBit { |
| entry(%0 : $Builtin.Int63): |
| %u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1, %0 : $Builtin.Int63 |
| return %u : $SinglePayloadSpareBit |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_spare_bit_inject_x_indirect(i63, %O4enum21SinglePayloadSpareBit* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %1 to i63* |
| // CHECK-64: store i63 %0, i63* [[DATA_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () { |
| entry(%0 : $Builtin.Int63, %1 : $*SinglePayloadSpareBit): |
| %a = init_enum_data_addr %1 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1 |
| store %0 to %a : $*Builtin.Int63 |
| inject_enum_addr %1 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @single_payload_spare_bit_inject_y() {{.*}} { |
| // CHECK-64: entry: |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: ret i64 -9223372036854775808 |
| // CHECK-64: } |
| sil @single_payload_spare_bit_inject_y : $() -> SinglePayloadSpareBit { |
| entry: |
| %u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.y!enumelt |
| return %u : $SinglePayloadSpareBit |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_spare_bit_inject_y_indirect(%O4enum21SinglePayloadSpareBit* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64* |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @single_payload_spare_bit_inject_y_indirect : $(@inout SinglePayloadSpareBit) -> () { |
| entry(%0 : $*SinglePayloadSpareBit): |
| inject_enum_addr %0 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.y!enumelt |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @single_payload_spare_bit_inject_z() {{.*}} { |
| // CHECK-64: entry: |
| // 0x8000_0000_0000_0001 |
| // CHECK-64: ret i64 -9223372036854775807 |
| // CHECK-64: } |
| sil @single_payload_spare_bit_inject_z : $() -> SinglePayloadSpareBit { |
| entry: |
| %u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.z!enumelt |
| return %u : $SinglePayloadSpareBit |
| } |
| |
| enum SinglePayloadNested { |
| case a(NoPayloads) |
| case b |
| case c |
| case d |
| } |
| |
| enum SinglePayloadNestedNested { |
| case e(SinglePayloadNested) |
| case f |
| case g |
| case h |
| } |
| |
| // CHECK: define{{( protected)?}} void @single_payload_nested_switch(i8) {{.*}} { |
| sil @single_payload_nested_switch : $(SinglePayloadNestedNested) -> () { |
| entry(%u : $SinglePayloadNestedNested): |
| // CHECK: switch i8 {{%.*}}, label {{%.*}} [ |
| // CHECK: i8 6, label {{%.*}} |
| // CHECK: i8 7, label {{%.*}} |
| // CHECK: i8 8, label {{%.*}} |
| // CHECK: ] |
| switch_enum %u : $SinglePayloadNestedNested, case #SinglePayloadNestedNested.e!enumelt.1: e_dest, case #SinglePayloadNestedNested.f!enumelt: f_dest, case #SinglePayloadNestedNested.g!enumelt: g_dest, case #SinglePayloadNestedNested.h!enumelt: h_dest |
| |
| e_dest(%v : $SinglePayloadNested): |
| // CHECK: switch i8 {{%.*}}, label {{%.*}} [ |
| // CHECK: i8 3, label {{%.*}} |
| // CHECK: i8 4, label {{%.*}} |
| // CHECK: i8 5, label {{%.*}} |
| // CHECK: ] |
| switch_enum %v : $SinglePayloadNested, case #SinglePayloadNested.a!enumelt.1: a_dest, case #SinglePayloadNested.b!enumelt: b_dest, case #SinglePayloadNested.c!enumelt: c_dest, case #SinglePayloadNested.d!enumelt: d_dest |
| f_dest: |
| br end |
| g_dest: |
| br end |
| h_dest: |
| br end |
| |
| a_dest(%w : $NoPayloads): |
| // CHECK: switch i8 {{%.*}}, label {{%.*}} [ |
| // CHECK: i8 0, label {{%.*}} |
| // CHECK: i8 1, label {{%.*}} |
| // CHECK: i8 2, label {{%.*}} |
| // CHECK: ] |
| switch_enum %w : $NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest |
| b_dest: |
| br end |
| c_dest: |
| br end |
| d_dest: |
| br end |
| |
| x_dest: |
| br end |
| y_dest: |
| br end |
| z_dest: |
| br end |
| |
| end: |
| %x = tuple() |
| return %x : $() |
| } |
| |
| class C {} |
| sil_vtable C {} |
| |
| sil @_TFC4enum1CD : $@convention(method) (C) -> () |
| |
| @objc class OC {} |
| sil_vtable OC {} |
| sil hidden @_TToFC4enum2OCcfT_S0_ : $@convention(thin) (OC) -> OC { |
| entry(%x : $OC): |
| return %x : $OC |
| } |
| |
| enum SinglePayloadClass { |
| case x(C) |
| case y |
| case z |
| case w |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_class_switch(i64) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: switch i64 %0, label {{%.*}} [ |
| // CHECK-64: i64 0, label {{%.*}} |
| // CHECK-64: i64 2, label {{%.*}} |
| // CHECK-64: i64 4, label {{%.*}} |
| // CHECK-64: ] |
| // CHECK-64: ; <label> |
| // CHECK-64: inttoptr [[WORD]] %0 to %C4enum1C* |
| |
| // CHECK-32: define{{( protected)?}} void @single_payload_class_switch(i32) {{.*}} { |
| // CHECK-32: entry: |
| // CHECK-32: switch i32 %0, label {{%.*}} [ |
| // CHECK-32: i32 0, label {{%.*}} |
| // CHECK-32: i32 1, label {{%.*}} |
| // CHECK-32: i32 2, label {{%.*}} |
| // CHECK-32: ] |
| // CHECK-32: ; <label> |
| // CHECK-32: inttoptr [[WORD]] %0 to %C4enum1C* |
| |
| sil @single_payload_class_switch : $(SinglePayloadClass) -> () { |
| entry(%c : $SinglePayloadClass): |
| switch_enum %c : $SinglePayloadClass, case #SinglePayloadClass.x!enumelt.1: x_dest, case #SinglePayloadClass.y!enumelt: y_dest, case #SinglePayloadClass.z!enumelt: z_dest, case #SinglePayloadClass.w!enumelt: w_dest |
| |
| x_dest(%d : $C): |
| br end |
| y_dest: |
| br end |
| z_dest: |
| br end |
| w_dest: |
| br end |
| |
| end: |
| return undef : $() |
| } |
| |
| protocol PC : class {} |
| @objc protocol PO {} |
| |
| enum SinglePayloadClassProtocol { |
| case x(PC) |
| case y, z, w |
| } |
| |
| enum SinglePayloadObjCProtocol { |
| case x(PO) |
| case y, z, w |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_class_protocol_switch(i64, i64) {{.*}} { |
| // CHECK-64: switch i64 %0, label {{%.*}} [ |
| // CHECK-64: i64 0, label {{%.*}} |
| // CHECK-64: i64 2, label {{%.*}} |
| // CHECK-64: i64 4, label {{%.*}} |
| // CHECK-64: ] |
| |
| // CHECK-objc-64: inttoptr i64 %0 to %objc_object* |
| // CHECK-native-64: inttoptr i64 %0 to %swift.refcounted* |
| // CHECK-64: inttoptr i64 %1 to i8** |
| |
| // CHECK-32: define{{( protected)?}} void @single_payload_class_protocol_switch(i32, i32) {{.*}} { |
| // CHECK-32: switch i32 %0, label {{%.*}} [ |
| // CHECK-32: i32 0, label {{%.*}} |
| // CHECK-32: i32 1, label {{%.*}} |
| // CHECK-32: i32 2, label {{%.*}} |
| // CHECK-32: ] |
| |
| // CHECK-objc-32: inttoptr i32 %0 to %objc_object* |
| // CHECK-native-32: inttoptr i32 %0 to %swift.refcounted* |
| // CHECK-32: inttoptr i32 %1 to i8** |
| |
| sil @single_payload_class_protocol_switch : $(SinglePayloadClassProtocol) -> () { |
| entry(%c : $SinglePayloadClassProtocol): |
| switch_enum %c : $SinglePayloadClassProtocol, case #SinglePayloadClassProtocol.x!enumelt.1: x_dest, case #SinglePayloadClassProtocol.y!enumelt: y_dest, case #SinglePayloadClassProtocol.z!enumelt: z_dest, case #SinglePayloadClassProtocol.w!enumelt: w_dest |
| |
| x_dest(%d : $PC): |
| br end |
| y_dest: |
| br end |
| z_dest: |
| br end |
| w_dest: |
| br end |
| |
| end: |
| return undef : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @single_payload_objc_protocol_switch(i64) {{.*}} { |
| // CHECK-64: switch i64 %0, label {{%.*}} |
| // CHECK-64: i64 0, label {{%.*}} |
| // CHECK-64: i64 2, label {{%.*}} |
| // CHECK-64: i64 4, label {{%.*}} |
| // CHECK-64: ] |
| // CHECK-objc-64: inttoptr i64 %0 to %objc_object* |
| // CHECK-native-64: inttoptr i64 %0 to %swift.refcounted* |
| |
| // CHECK-32: define{{( protected)?}} void @single_payload_objc_protocol_switch(i32) {{.*}} { |
| // CHECK-32: switch i32 %0, label {{%.*}} |
| // CHECK-32: i32 0, label {{%.*}} |
| // CHECK-32: i32 1, label {{%.*}} |
| // CHECK-32: i32 2, label {{%.*}} |
| // CHECK-32: ] |
| // CHECK-objc-32: inttoptr i32 %0 to %objc_object* |
| // CHECK-native-32: inttoptr i32 %0 to %swift.refcounted* |
| |
| sil @single_payload_objc_protocol_switch : $(SinglePayloadObjCProtocol) -> () { |
| entry(%c : $SinglePayloadObjCProtocol): |
| switch_enum %c : $SinglePayloadObjCProtocol, case #SinglePayloadObjCProtocol.x!enumelt.1: x_dest, case #SinglePayloadObjCProtocol.y!enumelt: y_dest, case #SinglePayloadObjCProtocol.z!enumelt: z_dest, case #SinglePayloadObjCProtocol.w!enumelt: w_dest |
| |
| x_dest(%d : $PO): |
| br end |
| y_dest: |
| br end |
| z_dest: |
| br end |
| w_dest: |
| br end |
| |
| end: |
| return undef : $() |
| } |
| |
| |
| enum DynamicSinglePayload<T> { |
| case x(T) |
| case y |
| case z |
| case w |
| } |
| |
| // CHECK: define{{( protected)?}} void @dynamic_single_payload_switch(%O4enum20DynamicSinglePayload* noalias nocapture, %swift.type* %T) {{.*}} { |
| // CHECK: [[OPAQUE_ENUM:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque* |
| // CHECK: [[CASE_INDEX:%.*]] = call i32 @swift_rt_swift_getEnumCaseSinglePayload(%swift.opaque* [[OPAQUE_ENUM]], %swift.type* %T, i32 3) |
| // CHECK: switch i32 [[CASE_INDEX]], label {{%.*}} [ |
| // CHECK: i32 -1, label {{%.*}} |
| // CHECK: i32 2, label {{%.*}} |
| // CHECK: ] |
| sil @dynamic_single_payload_switch : $<T> (@in DynamicSinglePayload<T>) -> () { |
| entry(%u : $*DynamicSinglePayload<T>): |
| switch_enum_addr %u : $*DynamicSinglePayload<T>, case #DynamicSinglePayload.x!enumelt.1: x_dest, case #DynamicSinglePayload.w!enumelt: w_dest, default default_dest |
| |
| x_dest: |
| br end |
| |
| w_dest: |
| br end |
| |
| default_dest: |
| br end |
| |
| end: |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK: define{{( protected)?}} void @dynamic_single_payload_inject_x(%O4enum20DynamicSinglePayload* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T) {{.*}} { |
| // CHECK: [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque* |
| // CHECK: call void @swift_rt_swift_storeEnumTagSinglePayload(%swift.opaque* [[ADDR]], %swift.type* %T, i32 -1, i32 3) |
| sil @dynamic_single_payload_inject_x : $<T> (@in T) -> @out DynamicSinglePayload<T> { |
| entry(%r : $*DynamicSinglePayload<T>, %t : $*T): |
| inject_enum_addr %r : $*DynamicSinglePayload<T>, #DynamicSinglePayload.x!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK: define{{( protected)?}} void @dynamic_single_payload_inject_y(%O4enum20DynamicSinglePayload* noalias nocapture sret, %swift.type* %T) {{.*}} { |
| // CHECK: [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque* |
| // CHECK: call void @swift_rt_swift_storeEnumTagSinglePayload(%swift.opaque* [[ADDR]], %swift.type* %T, i32 0, i32 3) |
| sil @dynamic_single_payload_inject_y : $<T> () -> @out DynamicSinglePayload<T> { |
| entry(%r : $*DynamicSinglePayload<T>): |
| inject_enum_addr %r : $*DynamicSinglePayload<T>, #DynamicSinglePayload.y!enumelt |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // -- Ensure instantiations of single-payload types with empty payloads work. |
| // Bug discovered by Greg Parker. |
| |
| // CHECK: define{{( protected)?}} void @dynamic_single_payload_empty_payload_switch(i8) {{.*}} { |
| // CHECK: switch i8 {{%.*}}, label {{.*}} [ |
| // CHECK: i8 0, label {{.*}} |
| // CHECK: i8 1, label {{.*}} |
| // CHECK: i8 2, label {{.*}} |
| // CHECK: i8 3, label {{.*}} |
| // CHECK: ] |
| sil @dynamic_single_payload_empty_payload_switch : $DynamicSinglePayload<()> -> () { |
| entry(%x : $DynamicSinglePayload<()>): |
| switch_enum %x : $DynamicSinglePayload<()>, case #DynamicSinglePayload.x!enumelt.1: x_case, case #DynamicSinglePayload.y!enumelt: y_case, case #DynamicSinglePayload.z!enumelt: z_case, default default_case |
| |
| x_case(%a : $()): |
| br end(%a : $()) |
| |
| y_case: |
| %b = tuple () |
| br end(%b : $()) |
| |
| z_case: |
| %c = tuple () |
| br end(%c : $()) |
| |
| default_case: |
| %d = tuple () |
| br end(%d : $()) |
| |
| end(%z : $()): |
| return %z : $() |
| } |
| |
| // CHECK: define{{( protected)?}} i8 @dynamic_single_payload_empty_payload_load([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK: entry: |
| // CHECK: %1 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i8* |
| // CHECK: %2 = load i8, i8* %1 |
| // CHECK: ret i8 %2 |
| // CHECK: } |
| sil @dynamic_single_payload_empty_payload_load : $(@inout DynamicSinglePayload<()>) -> DynamicSinglePayload<()> { |
| entry(%p : $*DynamicSinglePayload<()>): |
| %x = load %p : $*DynamicSinglePayload<()> |
| return %x : $DynamicSinglePayload<()> |
| } |
| |
| // CHECK: define{{( protected)?}} void @dynamic_single_payload_empty_payload_store([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* nocapture dereferenceable({{.*}}), i8) {{.*}} { |
| // CHECK: entry: |
| // CHECK: %2 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i8* |
| // CHECK: store i8 %1, i8* %2 |
| // CHECK: ret void |
| // CHECK: } |
| sil @dynamic_single_payload_empty_payload_store : $(@inout DynamicSinglePayload<()>, DynamicSinglePayload<()>) -> () { |
| entry(%p : $*DynamicSinglePayload<()>, %x : $DynamicSinglePayload<()>): |
| store %x to %p : $*DynamicSinglePayload<()> |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK: define{{( protected)?}} i8 @dynamic_single_payload_empty_payload_inject_payload() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret i8 0 |
| // CHECK: } |
| sil @dynamic_single_payload_empty_payload_inject_payload : $() -> DynamicSinglePayload<()> { |
| %v = tuple () |
| %u = enum $DynamicSinglePayload<()>, #DynamicSinglePayload.x!enumelt, %v : $() |
| return %u : $DynamicSinglePayload<()> |
| } |
| |
| // CHECK: define{{( protected)?}} i8 @dynamic_single_payload_empty_payload_inject_no_payload() {{.*}} { |
| // CHECK: entry: |
| // CHECK: ret i8 1 |
| // CHECK: } |
| sil @dynamic_single_payload_empty_payload_inject_no_payload : $() -> DynamicSinglePayload<()> { |
| %u = enum $DynamicSinglePayload<()>, #DynamicSinglePayload.y!enumelt |
| return %u : $DynamicSinglePayload<()> |
| } |
| |
| // <rdar://problem/15383966> |
| // CHECK: define{{( protected)?}} void @dynamic_single_payload_generic_destroy |
| // CHECK: br i1 |
| // CHECK: <label> |
| // CHECK: call void %destroy |
| // CHECK: <label> |
| sil @dynamic_single_payload_generic_destroy : $@convention(thin) <T> (@in DynamicSinglePayload<T>) -> () { |
| entry(%x : $*DynamicSinglePayload<T>): |
| destroy_addr %x : $*DynamicSinglePayload<T> |
| %z = tuple () |
| return %z : $() |
| } |
| |
| enum MultiPayloadNoSpareBits { |
| case x(Builtin.Int64) |
| case y(Builtin.Int32) |
| case z(Builtin.Int63) |
| case a |
| case b |
| case c |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_no_spare_bits_switch(i64, i8) {{.*}} { |
| sil @multi_payload_no_spare_bits_switch : $(MultiPayloadNoSpareBits) -> () { |
| entry(%u : $MultiPayloadNoSpareBits): |
| // CHECK-64: switch i8 %1, label %[[UNREACHABLE:[0-9]+]] [ |
| // CHECK-64: i8 0, label %[[X_PREDEST:[0-9]+]] |
| // CHECK-64: i8 1, label %[[Y_PREDEST:[0-9]+]] |
| // CHECK-64: i8 2, label %[[Z_PREDEST:[0-9]+]] |
| // CHECK-64: i8 3, label %[[EMPTY:[0-9]+]] |
| // CHECK-64: ] |
| // CHECK-64: ; <label>:[[EMPTY]] |
| // CHECK-64: switch i64 %0, label %[[UNREACHABLE]] [ |
| // CHECK-64: i64 0, label %[[A_DEST:[0-9]+]] |
| // CHECK-64: i64 1, label %[[B_DEST:[0-9]+]] |
| // CHECK-64: i64 2, label %[[C_DEST:[0-9]+]] |
| // CHECK-64: ] |
| // CHECK-64: ; <label>:[[UNREACHABLE]] |
| // CHECK-64: unreachable |
| switch_enum %u : $MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadNoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadNoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest |
| |
| // CHECK-64: ; <label>:[[X_PREDEST]] |
| // CHECK-64: br label %[[X_DEST:[0-9]+]] |
| // CHECK-64: ; <label>:[[Y_PREDEST]] |
| // CHECK-64: [[Y_VALUE:%.*]] = trunc i64 %0 to i32 |
| // CHECK-64: br label %[[Y_DEST:[0-9]+]] |
| // CHECK-64: ; <label>:[[Z_PREDEST]] |
| // CHECK-64: [[Z_VALUE:%.*]] = trunc i64 %0 to i63 |
| // CHECK-64: br label %[[Z_DEST:[0-9]+]] |
| |
| // CHECK-64: ; <label>:[[X_DEST]] |
| // CHECK-64: phi i64 [ %0, %[[X_PREDEST]] ] |
| x_dest(%x : $Builtin.Int64): |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[Y_DEST]] |
| // CHECK-64: phi i32 [ [[Y_VALUE]], %[[Y_PREDEST]] ] |
| y_dest(%y : $Builtin.Int32): |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[Z_DEST]] |
| // CHECK-64: phi i63 [ [[Z_VALUE]], %[[Z_PREDEST]] ] |
| z_dest(%z : $Builtin.Int63): |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[A_DEST]] |
| a_dest: |
| %d = function_ref @d : $@convention(thin) () -> () |
| apply %d() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[B_DEST]] |
| b_dest: |
| %e = function_ref @e : $@convention(thin) () -> () |
| apply %e() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[C_DEST]] |
| c_dest: |
| %f = function_ref @f : $@convention(thin) () -> () |
| apply %f() : $@convention(thin) () -> () |
| br end |
| |
| end: |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_no_spare_bits_switch_indirect(%O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} { |
| sil @multi_payload_no_spare_bits_switch_indirect : $(@inout MultiPayloadNoSpareBits) -> () { |
| entry(%u : $*MultiPayloadNoSpareBits): |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1 |
| // CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8* |
| // CHECK-64: [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]] |
| // CHECK-64: switch i8 [[TAG]] |
| // CHECK-64: switch i64 [[PAYLOAD]] |
| // CHECK-64: ; <label>: |
| // CHECK-64: unreachable |
| switch_enum_addr %u : $*MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadNoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadNoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest |
| |
| // CHECK-64: ; <label>:[[X_DEST:[0-9]+]] |
| // CHECK-64: bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64* |
| // CHECK-64: ; <label>:[[Y_DEST:[0-9]+]] |
| // CHECK-64: bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i32* |
| // CHECK-64: ; <label>:[[Z_DEST:[0-9]+]] |
| // CHECK-64: bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i63* |
| |
| x_dest: |
| %x = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1 |
| br end |
| |
| y_dest: |
| %y = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.y!enumelt.1 |
| br end |
| |
| z_dest: |
| %z = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.z!enumelt.1 |
| br end |
| |
| a_dest: |
| br end |
| |
| b_dest: |
| br end |
| |
| c_dest: |
| br end |
| |
| end: |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i8 } @multi_payload_no_spare_bit_inject_x(i64) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 %0, 0 |
| // CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 0, 1 |
| // CHECK-64: ret { i64, i8 } [[RES]] |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_x : $(Builtin.Int64) -> MultiPayloadNoSpareBits { |
| entry(%0 : $Builtin.Int64): |
| %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1, %0 : $Builtin.Int64 |
| return %u : $MultiPayloadNoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_no_spare_bit_inject_x_indirect(i64, %O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %1 to i64* |
| // CHECK-64: store i64 %0, i64* [[DATA_ADDR]] |
| // CHECK-64: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %1, i32 0, i32 1 |
| // CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8* |
| // CHECK-64: store i8 0, i8* [[TAG_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_x_indirect : $(Builtin.Int64, @inout MultiPayloadNoSpareBits) -> () { |
| entry(%0 : $Builtin.Int64, %1 : $*MultiPayloadNoSpareBits): |
| %a = init_enum_data_addr %1 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1 |
| store %0 to %a : $*Builtin.Int64 |
| inject_enum_addr %1 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i8 } @multi_payload_no_spare_bit_inject_y(i32) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i32 %0 to i64 |
| // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[ZEXT]], 0 |
| // CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 1, 1 |
| // CHECK-64: ret { i64, i8 } [[RES]] |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_y : $(Builtin.Int32) -> MultiPayloadNoSpareBits { |
| entry(%0 : $Builtin.Int32): |
| %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.y!enumelt.1, %0 : $Builtin.Int32 |
| return %u : $MultiPayloadNoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i8 } @multi_payload_no_spare_bit_inject_z(i63) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i63 %0 to i64 |
| // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[ZEXT]], 0 |
| // CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 2, 1 |
| // CHECK-64: ret { i64, i8 } [[RES]] |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_z : $(Builtin.Int63) -> MultiPayloadNoSpareBits { |
| entry(%0 : $Builtin.Int63): |
| %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.z!enumelt.1, %0 : $Builtin.Int63 |
| return %u : $MultiPayloadNoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i8 } @multi_payload_no_spare_bit_inject_a() {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: ret { i64, i8 } { i64 0, i8 3 } |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_a : $() -> MultiPayloadNoSpareBits { |
| entry: |
| %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.a!enumelt |
| return %u : $MultiPayloadNoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_no_spare_bit_inject_a_indirect(%O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64* |
| // CHECK-64: store i64 0, i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1 |
| // CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8* |
| // CHECK-64: store i8 3, i8* [[TAG_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_a_indirect : $(@inout MultiPayloadNoSpareBits) -> () { |
| entry(%0 : $*MultiPayloadNoSpareBits): |
| inject_enum_addr %0 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.a!enumelt |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i8 } @multi_payload_no_spare_bit_inject_b() {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: ret { i64, i8 } { i64 1, i8 3 } |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_b : $() -> MultiPayloadNoSpareBits { |
| entry: |
| %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.b!enumelt |
| return %u : $MultiPayloadNoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i8 } @multi_payload_no_spare_bit_inject_c() {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: ret { i64, i8 } { i64 2, i8 3 } |
| // CHECK-64: } |
| sil @multi_payload_no_spare_bit_inject_c : $() -> MultiPayloadNoSpareBits { |
| entry: |
| %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.c!enumelt |
| return %u : $MultiPayloadNoSpareBits |
| } |
| |
| enum MultiPayloadOneSpareBit { |
| case x(Builtin.Int62) |
| case y(Builtin.Int63) |
| case z(Builtin.Int61) |
| case a |
| case b |
| case c |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_one_spare_bit_switch(i64, i1) {{.*}} { |
| sil @multi_payload_one_spare_bit_switch : $(MultiPayloadOneSpareBit) -> () { |
| entry(%u : $MultiPayloadOneSpareBit): |
| // CHECK-64: [[SPARE_TAG_LSHR:%.*]] = lshr i64 %0, 63 |
| // CHECK-64: [[SPARE_TAG_TRUNC:%.*]] = trunc i64 [[SPARE_TAG_LSHR]] to i8 |
| // CHECK-64: [[SPARE_TAG:%.*]] = and i8 [[SPARE_TAG_TRUNC]], 1 |
| // CHECK-64: [[EXTRA_TAG_ZEXT:%.*]] = zext i1 %1 to i8 |
| // CHECK-64: [[EXTRA_TAG:%.*]] = shl i8 [[EXTRA_TAG_ZEXT]], 1 |
| // CHECK-64: [[TAG:%.*]] = or i8 [[SPARE_TAG]], [[EXTRA_TAG]] |
| // CHECK-64: switch i8 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [ |
| // CHECK-64: i8 0, label %[[X_PREDEST:[0-9]+]] |
| // CHECK-64: i8 1, label %[[Y_PREDEST:[0-9]+]] |
| // CHECK-64: i8 2, label %[[Z_PREDEST:[0-9]+]] |
| // CHECK-64: i8 3, label %[[EMPTY_DEST:[0-9]+]] |
| // CHECK-64: ] |
| |
| // CHECK-64: ; <label>:[[EMPTY_DEST]] |
| // CHECK-64: switch i64 %0, label %[[UNREACHABLE]] [ |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: i64 -9223372036854775808, label %[[A_DEST:[0-9]+]] |
| // -- 0x8000_0000_0000_0001 |
| // CHECK-64: i64 -9223372036854775807, label %[[B_DEST:[0-9]+]] |
| // -- 0x8000_0000_0000_0002 |
| // CHECK-64: i64 -9223372036854775806, label %[[C_DEST:[0-9]+]] |
| // CHECK-64: ] |
| |
| // CHECK-64: ; <label>:[[UNREACHABLE]] |
| // CHECK-64: unreachable |
| switch_enum %u : $MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt.1: x_dest, case #MultiPayloadOneSpareBit.y!enumelt.1: y_dest, case #MultiPayloadOneSpareBit.z!enumelt.1: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest |
| |
| // CHECK-64: ; <label>:[[X_PREDEST]] |
| // CHECK-64: [[X_VALUE:%.*]] = trunc i64 %0 to i62 |
| // CHECK-64: br label %[[X_DEST:[0-9]+]] |
| // CHECK-64: ; <label>:[[Y_PREDEST]] |
| // -- 0x7FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[Y_MASKED:%.*]] = and i64 %0, 9223372036854775807 |
| // CHECK-64: [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i63 |
| // CHECK-64: br label %[[Y_DEST:[0-9]+]] |
| // CHECK-64: ; <label>:[[Z_PREDEST]] |
| // CHECK-64: [[Z_VALUE:%.*]] = trunc i64 %0 to i61 |
| // CHECK-64: br label %[[Z_DEST:[0-9]+]] |
| |
| // CHECK-64: ; <label>:[[X_DEST]] |
| // CHECK-64: phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ] |
| x_dest(%x : $Builtin.Int62): |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[Y_DEST]] |
| // CHECK-64: phi i63 [ [[Y_VALUE]], %[[Y_PREDEST]] ] |
| y_dest(%y : $Builtin.Int63): |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[Z_DEST]] |
| // CHECK-64: phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ] |
| z_dest(%z : $Builtin.Int61): |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[A_DEST]] |
| a_dest: |
| %d = function_ref @d : $@convention(thin) () -> () |
| apply %d() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[B_DEST]] |
| b_dest: |
| %e = function_ref @e : $@convention(thin) () -> () |
| apply %e() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[C_DEST]] |
| c_dest: |
| %f = function_ref @f : $@convention(thin) () -> () |
| apply %f() : $@convention(thin) () -> () |
| br end |
| |
| end: |
| %v = tuple () |
| return %v : $() |
| } |
| |
| sil @multi_payload_one_spare_bit_switch_indirect : $(@inout MultiPayloadOneSpareBit) -> () { |
| entry(%u : $*MultiPayloadOneSpareBit): |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1 |
| // CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1* |
| // CHECK-64: [[TAG:%.*]] = load i1, i1* [[TAG_ADDR]] |
| // CHECK-64: switch i8 {{%.*}} |
| // CHECK-64: switch i64 [[PAYLOAD]] |
| // CHECK-64: ; <label>: |
| // CHECK-64: unreachable |
| switch_enum_addr %u : $*MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt.1: x_dest, case #MultiPayloadOneSpareBit.y!enumelt.1: y_dest, case #MultiPayloadOneSpareBit.z!enumelt.1: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest |
| |
| // CHECK-64: ; <label>:[[X_PREDEST:[0-9]+]] |
| // CHECK-64: bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i62* |
| |
| // CHECK-64: ; <label>:[[Y_PREDEST:[0-9]+]] |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // -- 0x7FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807 |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64* |
| // CHECK-64: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i63* |
| |
| // CHECK-64: ; <label>:[[Z_PREDEST:[0-9]+]] |
| // CHECK-64: bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i61* |
| |
| x_dest: |
| %x = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1 |
| br end |
| |
| y_dest: |
| %y = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1 |
| br end |
| |
| z_dest: |
| %z = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt.1 |
| br end |
| |
| a_dest: |
| br end |
| |
| b_dest: |
| br end |
| |
| c_dest: |
| br end |
| |
| end: |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i1 } @multi_payload_one_spare_bit_inject_x(i62) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i62 %0 to i64 |
| // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[ZEXT]], 0 |
| // CHECK-64: [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 false, 1 |
| // CHECK-64: ret { i64, i1 } [[RES]] |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_x : $(Builtin.Int62) -> MultiPayloadOneSpareBit { |
| entry(%0 : $Builtin.Int62): |
| %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1, %0 : $Builtin.Int62 |
| return %u : $MultiPayloadOneSpareBit |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_one_spare_bit_inject_x_indirect(i62, %O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i62* |
| // CHECK-64: store i62 %0, i62* [[DATA_ADDR]] |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // -- 0x7FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807 |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64* |
| // CHECK-64: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1 |
| // CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1* |
| // CHECK-64: store i1 false, i1* [[TAG_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_x_indirect : $(Builtin.Int62, @inout MultiPayloadOneSpareBit) -> () { |
| entry(%0 : $Builtin.Int62, %1 : $*MultiPayloadOneSpareBit): |
| %a = init_enum_data_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1 |
| store %0 to %a : $*Builtin.Int62 |
| inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i1 } @multi_payload_one_spare_bit_inject_y(i63) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i63 %0 to i64 |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808 |
| // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[TAGGED]], 0 |
| // CHECK-64: [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 false, 1 |
| // CHECK-64: ret { i64, i1 } [[RES]] |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_y : $(Builtin.Int63) -> MultiPayloadOneSpareBit { |
| entry(%0 : $Builtin.Int63): |
| %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1, %0 : $Builtin.Int63 |
| return %u : $MultiPayloadOneSpareBit |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_one_spare_bit_inject_y_indirect(i63, %O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i63* |
| // CHECK-64: store i63 %0, i63* [[DATA_ADDR]] |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // -- 0x7FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807 |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], -9223372036854775808 |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64* |
| // CHECK-64: store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1 |
| // CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1* |
| // CHECK-64: store i1 false, i1* [[TAG_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| |
| sil @multi_payload_one_spare_bit_inject_y_indirect : $(Builtin.Int63, @inout MultiPayloadOneSpareBit) -> () { |
| entry(%0 : $Builtin.Int63, %1 : $*MultiPayloadOneSpareBit): |
| %a = init_enum_data_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1 |
| store %0 to %a : $*Builtin.Int63 |
| inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i1 } @multi_payload_one_spare_bit_inject_z(i61) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i61 %0 to i64 |
| // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[ZEXT]], 0 |
| // CHECK-64: [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 true, 1 |
| // CHECK-64: ret { i64, i1 } [[RES]] |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_z : $(Builtin.Int61) -> MultiPayloadOneSpareBit { |
| entry(%0 : $Builtin.Int61): |
| %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt.1, %0 : $Builtin.Int61 |
| return %u : $MultiPayloadOneSpareBit |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i1 } @multi_payload_one_spare_bit_inject_a() {{.*}} { |
| // CHECK-64: entry: |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: ret { i64, i1 } { i64 -9223372036854775808, i1 true } |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_a : $() -> MultiPayloadOneSpareBit { |
| entry: |
| %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt |
| return %u : $MultiPayloadOneSpareBit |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_one_spare_bit_inject_a_indirect(%O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64* |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1 |
| // CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1* |
| // CHECK-64: store i1 true, i1* [[TAG_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_a_indirect : $(@inout MultiPayloadOneSpareBit) -> () { |
| entry(%0 : $*MultiPayloadOneSpareBit): |
| inject_enum_addr %0 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i1 } @multi_payload_one_spare_bit_inject_b() {{.*}} { |
| // CHECK-64: entry: |
| // -- 0x8000_0000_0000_0001 |
| // CHECK-64: ret { i64, i1 } { i64 -9223372036854775807, i1 true } |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_b : $() -> MultiPayloadOneSpareBit { |
| entry: |
| %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.b!enumelt |
| return %u : $MultiPayloadOneSpareBit |
| } |
| |
| // CHECK-64: define{{( protected)?}} { i64, i1 } @multi_payload_one_spare_bit_inject_c() {{.*}} { |
| // CHECK-64: entry: |
| // -- 0x8000_0000_0000_0002 |
| // CHECK-64: ret { i64, i1 } { i64 -9223372036854775806, i1 true } |
| // CHECK-64: } |
| sil @multi_payload_one_spare_bit_inject_c : $() -> MultiPayloadOneSpareBit { |
| entry: |
| %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.c!enumelt |
| return %u : $MultiPayloadOneSpareBit |
| } |
| |
| |
| enum MultiPayloadTwoSpareBits { |
| case x(Builtin.Int62) |
| case y(Builtin.Int60) |
| case z(Builtin.Int61) |
| case a |
| case b |
| case c |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_two_spare_bits_switch(i64) {{.*}} { |
| sil @multi_payload_two_spare_bits_switch : $(MultiPayloadTwoSpareBits) -> () { |
| entry(%u : $MultiPayloadTwoSpareBits): |
| // CHECK-64: [[TAG_LSHR:%.*]] = lshr i64 %0, 62 |
| // CHECK-64: [[TAG_BYTE:%.*]] = trunc i64 [[TAG_LSHR]] to i8 |
| // CHECK-64: [[TAG:%.*]] = and i8 [[TAG_BYTE]], 3 |
| // CHECK-64: switch i8 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [ |
| // CHECK-64: i8 0, label %[[X_PREDEST:[0-9]+]] |
| // CHECK-64: i8 1, label %[[Y_PREDEST:[0-9]+]] |
| // CHECK-64: i8 2, label %[[Z_PREDEST:[0-9]+]] |
| // CHECK-64: i8 3, label %[[EMPTY_DEST:[0-9]+]] |
| // CHECK-64: ] |
| // CHECK-64: ; <label>:[[EMPTY_DEST]] |
| // CHECK-64: switch i64 %0, label %[[UNREACHABLE]] [ |
| // -- 0xC000_0000_0000_0000 |
| // CHECK-64: i64 -4611686018427387904, label %[[A_DEST:[0-9]+]] |
| // -- 0xC000_0000_0000_0001 |
| // CHECK-64: i64 -4611686018427387903, label %[[B_DEST:[0-9]+]] |
| // -- 0xC000_0000_0000_0002 |
| // CHECK-64: i64 -4611686018427387902, label %[[C_DEST:[0-9]+]] |
| // CHECK-64: ] |
| // CHECK-64: ; <label>:[[UNREACHABLE]] |
| // CHECK-64: unreachable |
| switch_enum %u : $MultiPayloadTwoSpareBits, case #MultiPayloadTwoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadTwoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadTwoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadTwoSpareBits.a!enumelt: a_dest, case #MultiPayloadTwoSpareBits.b!enumelt: b_dest, case #MultiPayloadTwoSpareBits.c!enumelt: c_dest |
| |
| // CHECK-64: ; <label>:[[X_PREDEST]] |
| // CHECK-64: [[X_VALUE:%.*]] = trunc i64 %0 to i62 |
| // CHECK-64: br label %[[X_DEST:[0-9]+]] |
| |
| // CHECK-64: ; <label>:[[Y_PREDEST]] |
| // -- 0x3FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903 |
| // CHECK-64: [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i60 |
| // CHECK-64: br label %[[Y_DEST:[0-9]+]] |
| |
| // CHECK-64: ; <label>:[[Z_PREDEST]] |
| // -- 0x3FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903 |
| // CHECK-64: [[Z_VALUE:%.*]] = trunc i64 [[Z_MASKED]] to i61 |
| // CHECK-64: br label %[[Z_DEST:[0-9]+]] |
| |
| // CHECK-64: ; <label>:[[X_DEST]] |
| // CHECK-64: phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ] |
| x_dest(%x : $Builtin.Int62): |
| %a = function_ref @a : $@convention(thin) () -> () |
| apply %a() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[Y_DEST]] |
| // CHECK-64: phi i60 [ [[Y_VALUE]], %[[Y_PREDEST]] ] |
| y_dest(%y : $Builtin.Int60): |
| %b = function_ref @b : $@convention(thin) () -> () |
| apply %b() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[Z_DEST]] |
| // CHECK-64: phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ] |
| z_dest(%z : $Builtin.Int61): |
| %c = function_ref @c : $@convention(thin) () -> () |
| apply %c() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[A_DEST]] |
| a_dest: |
| %d = function_ref @d : $@convention(thin) () -> () |
| apply %d() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[B_DEST]] |
| b_dest: |
| %e = function_ref @e : $@convention(thin) () -> () |
| apply %e() : $@convention(thin) () -> () |
| br end |
| |
| // CHECK-64: ; <label>:[[C_DEST]] |
| c_dest: |
| %f = function_ref @f : $@convention(thin) () -> () |
| apply %f() : $@convention(thin) () -> () |
| br end |
| |
| end: |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @multi_payload_two_spare_bits_inject_x(i62) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i62 %0 to i64 |
| // CHECK-64: ret i64 [[ZEXT]] |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_x : $(Builtin.Int62) -> MultiPayloadTwoSpareBits { |
| entry(%0 : $Builtin.Int62): |
| %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1, %0 : $Builtin.Int62 |
| return %u : $MultiPayloadTwoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_two_spare_bits_inject_x_indirect(i62, %O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i62* |
| // CHECK-64: store i62 %0, i62* [[DATA_ADDR]] |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // -- 0x3FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903 |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64* |
| // CHECK-64: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_x_indirect : $(Builtin.Int62, @inout MultiPayloadTwoSpareBits) -> () { |
| entry(%0 : $Builtin.Int62, %1 : $*MultiPayloadTwoSpareBits): |
| %a = init_enum_data_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1 |
| store %0 to %a : $*Builtin.Int62 |
| inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @multi_payload_two_spare_bits_inject_y(i60) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i60 %0 to i64 |
| // -- 0x4000_0000_0000_0000 |
| // CHECK-64: [[TAGGED:%.*]] = or i64 [[ZEXT]], 4611686018427387904 |
| // CHECK-64: ret i64 [[TAGGED]] |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_y : $(Builtin.Int60) -> MultiPayloadTwoSpareBits { |
| entry(%0 : $Builtin.Int60): |
| %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1, %0 : $Builtin.Int60 |
| return %u : $MultiPayloadTwoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_two_spare_bits_inject_y_indirect(i60, %O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i60* |
| // CHECK-64: store i60 %0, i60* [[DATA_ADDR]] |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64* |
| // CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]] |
| // -- 0x3FFF_FFFF_FFFF_FFFF |
| // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903 |
| // -- 0x4000_0000_0000_0000 |
| // CHECK-64: [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], 4611686018427387904 |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64* |
| // CHECK-64: store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_y_indirect : $(Builtin.Int60, @inout MultiPayloadTwoSpareBits) -> () { |
| entry(%0 : $Builtin.Int60, %1 : $*MultiPayloadTwoSpareBits): |
| %a = init_enum_data_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1 |
| store %0 to %a : $*Builtin.Int60 |
| inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @multi_payload_two_spare_bits_inject_z(i61) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[ZEXT:%.*]] = zext i61 %0 to i64 |
| // -- 0x8000_0000_0000_0000 |
| // CHECK-64: [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808 |
| // CHECK-64: ret i64 [[TAGGED]] |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_z : $(Builtin.Int61) -> MultiPayloadTwoSpareBits { |
| entry(%0 : $Builtin.Int61): |
| %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.z!enumelt.1, %0 : $Builtin.Int61 |
| return %u : $MultiPayloadTwoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @multi_payload_two_spare_bits_inject_a() {{.*}} { |
| // CHECK-64: entry: |
| // -- 0xC000_0000_0000_0000 |
| // CHECK-64: ret i64 -4611686018427387904 |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_a : $() -> MultiPayloadTwoSpareBits { |
| entry: |
| %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.a!enumelt |
| return %u : $MultiPayloadTwoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} void @multi_payload_two_spare_bits_inject_a_indirect(%O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %0 to i64* |
| // -- 0xC000_0000_0000_0000 |
| // CHECK-64: store i64 -4611686018427387904, i64* [[PAYLOAD_ADDR]] |
| // CHECK-64: ret void |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_a_indirect : $(@inout MultiPayloadTwoSpareBits) -> () { |
| entry(%0 : $*MultiPayloadTwoSpareBits): |
| inject_enum_addr %0 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.a!enumelt |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @multi_payload_two_spare_bits_inject_b() {{.*}} { |
| // CHECK-64: entry: |
| // -- 0xC000_0000_0000_0001 |
| // CHECK-64: ret i64 -4611686018427387903 |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_b : $() -> MultiPayloadTwoSpareBits { |
| entry: |
| %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.b!enumelt |
| return %u : $MultiPayloadTwoSpareBits |
| } |
| |
| // CHECK-64: define{{( protected)?}} i64 @multi_payload_two_spare_bits_inject_c() {{.*}} { |
| // CHECK-64: entry: |
| // -- 0xC000_0000_0000_0002 |
| // CHECK-64: ret i64 -4611686018427387902 |
| // CHECK-64: } |
| sil @multi_payload_two_spare_bits_inject_c : $() -> MultiPayloadTwoSpareBits { |
| entry: |
| %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.c!enumelt |
| return %u : $MultiPayloadTwoSpareBits |
| } |
| |
| class D {} |
| sil_vtable D {} |
| |
| sil @_TFC4enum1DD : $@convention(method) (D) -> () |
| |
| enum MultiPayloadClasses { |
| case x(C) |
| case y(D) |
| case z |
| case w |
| } |
| |
| // CHECK-64-LABEL: define{{( protected)?}} void @multi_payload_classes_switch(i64) {{.*}} { |
| // CHECK-64: %1 = lshr i64 %0, 62 |
| // CHECK-64: %2 = trunc i64 %1 to i8 |
| // CHECK-64: %3 = and i8 %2, 3 |
| // CHECK-64: switch i8 %3, label {{%.*}} [ |
| // CHECK-64: i8 0, label {{%.*}} |
| // CHECK-64: i8 1, label {{%.*}} |
| // CHECK-64: i8 2, label {{%.*}} |
| // CHECK-64: ] |
| // CHECK-64: switch i64 %0, label {{%.*}} [ |
| // -- 0x8000000000000000 |
| // CHECK-64: i64 -9223372036854775808, label {{%.*}} |
| // -- 0x8000000000000008 |
| // CHECK-64: i64 -9223372036854775800, label {{%.*}} |
| // CHECK-64: ] |
| // -- Extract x(C) |
| // CHECK-64: inttoptr i64 %0 to %C4enum1C* |
| // -- Extract y(D) |
| // -- 0x3fffffffffffffff |
| // CHECK-64: [[MASKED:%.*]] = and i64 %0, 4611686018427387903 |
| // CHECK-64: inttoptr i64 [[MASKED]] to %C4enum1D* |
| |
| // CHECK-32-LABEL: define{{( protected)?}} void @multi_payload_classes_switch(i32) {{.*}} { |
| // CHECK-32: %1 = trunc i32 %0 to i8 |
| // CHECK-32: %2 = and i8 %1, 3 |
| // CHECK-32: switch i8 %2, label {{%.*}} [ |
| // CHECK-32: i8 0, label {{%.*}} |
| // CHECK-32: i8 1, label {{%.*}} |
| // CHECK-32: i8 2, label {{%.*}} |
| // CHECK-32: ] |
| // CHECK-32: switch i32 %0, label {{%.*}} [ |
| // CHECK-32: i32 2, label {{%.*}} |
| // CHECK-32: i32 6, label {{%.*}} |
| // CHECK-32: ] |
| // -- Extract x(C) |
| // CHECK-32: inttoptr i32 %0 to %C4enum1C* |
| // -- Extract y(D) |
| // CHECK-32: [[MASKED:%.*]] = and i32 %0, -4 |
| // CHECK-32: inttoptr i32 [[MASKED]] to %C4enum1D* |
| |
| sil @multi_payload_classes_switch : $(MultiPayloadClasses) -> () { |
| entry(%c : $MultiPayloadClasses): |
| switch_enum %c : $MultiPayloadClasses, case #MultiPayloadClasses.x!enumelt.1: x_dest, case #MultiPayloadClasses.y!enumelt.1: y_dest, case #MultiPayloadClasses.z!enumelt: z_dest, case #MultiPayloadClasses.w!enumelt: w_dest |
| |
| x_dest(%x : $C): |
| br end |
| |
| y_dest(%y : $D): |
| br end |
| |
| z_dest: |
| br end |
| |
| w_dest: |
| br end |
| |
| end: |
| return undef : $() |
| } |
| |
| struct S { |
| var a: CharLike |
| var b: IntLike |
| } |
| |
| enum MultiPayloadSpareBitAggregates { |
| // Has spare bits in the padding between Int32 and Int64 |
| case x(Builtin.Int32, Builtin.Int64) |
| // Has spare bits in the object pointers |
| case y(C, C) |
| // Has spare bits in the padding between struct fields |
| case z(S) |
| } |
| |
| // CHECK-64-LABEL: define{{( protected)?}} void @multi_payload_spare_bit_aggregate_switch(i64, i64) {{.*}} { |
| // CHECK-64: [[T0:%.*]] = lshr i64 %0, 62 |
| // CHECK-64: [[TAG_BYTE:%.*]] = trunc i64 [[T0]] to i8 |
| // CHECK-64: [[TAG:%.*]] = and i8 [[TAG_BYTE]], 3 |
| // CHECK-64: switch i8 [[TAG]], label {{%.*}} [ |
| // CHECK-64: i8 0, label %[[X_DEST:[0-9]+]] |
| // CHECK-64: i8 1, label %[[Y_DEST:[0-9]+]] |
| // CHECK-64: i8 2, label %[[Z_DEST:[0-9]+]] |
| // CHECK-64: ] |
| // CHECK-64: ; <label>:[[X_DEST]] |
| // CHECK-64: [[X_0:%.*]] = trunc i64 %0 to i32 |
| // CHECK-64: ; <label>:[[Y_DEST]] |
| // -- 0x3fffffffffffffff |
| // CHECK-64: [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903 |
| // CHECK-64: [[Y_0:%.*]] = inttoptr i64 [[Y_MASKED]] to %C4enum1C* |
| // CHECK-64: [[Y_1:%.*]] = inttoptr i64 %1 to %C4enum1C* |
| // CHECK-64: ; <label>:[[Z_DEST]] |
| // -- 0x3fffffffffffffff |
| // CHECK-64: [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903 |
| // CHECK-64: [[Z_A:%.*]] = trunc i64 [[Z_MASKED]] to i21 |
| |
| sil @multi_payload_spare_bit_aggregate_switch : $(MultiPayloadSpareBitAggregates) -> () { |
| entry(%c : $MultiPayloadSpareBitAggregates): |
| switch_enum %c : $MultiPayloadSpareBitAggregates, case #MultiPayloadSpareBitAggregates.x!enumelt.1: x_dest, case #MultiPayloadSpareBitAggregates.y!enumelt.1: y_dest, case #MultiPayloadSpareBitAggregates.z!enumelt.1: z_dest |
| |
| x_dest(%x : $(Builtin.Int32, Builtin.Int64)): |
| br end |
| |
| y_dest(%y : $(C, C)): |
| br end |
| |
| z_dest(%z : $S): |
| br end |
| |
| end: |
| return undef : $() |
| } |
| |
| // <rdar://problem/15759464> |
| enum MultiPayloadInner { |
| case A(Builtin.Word) |
| case B(Builtin.Word) |
| } |
| |
| enum MultiPayloadNested { |
| case A(MultiPayloadInner) |
| case B(MultiPayloadInner) |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} void @multi_payload_nested_switch |
| // CHECK: %1 = bitcast %O4enum18MultiPayloadNested* %0 to { [[WORD]], i8 }* |
| // CHECK: %2 = getelementptr |
| // CHECK: %3 = load [[WORD]], [[WORD]]* %2 |
| // CHECK: %4 = getelementptr |
| // CHECK: %5 = load i8, i8* %4 |
| // CHECK: %6 = lshr i8 %5, 7 |
| // CHECK: %7 = trunc i8 %6 to i1 |
| // CHECK: br i1 %7 |
| sil @multi_payload_nested_switch : $(@in MultiPayloadNested) -> () { |
| entry(%c : $*MultiPayloadNested): |
| switch_enum_addr %c : $*MultiPayloadNested, case #MultiPayloadNested.A!enumelt.1: a_dest, case #MultiPayloadNested.B!enumelt.1: b_dest |
| |
| a_dest: |
| br end |
| |
| b_dest: |
| br end |
| |
| end: |
| return undef : $() |
| } |
| |
| enum MultiPayloadInnerSpareBits { |
| case A(Builtin.NativeObject) |
| case B(Builtin.NativeObject) |
| case C(Builtin.NativeObject) |
| case D(Builtin.NativeObject) |
| } |
| |
| enum MultiPayloadNestedSpareBits { |
| case A(MultiPayloadInnerSpareBits) |
| case B(MultiPayloadInnerSpareBits) |
| } |
| |
| // CHECK-64-LABEL: define{{( protected)?}} void @multi_payload_nested_spare_bits_switch(%O4enum27MultiPayloadNestedSpareBits* noalias nocapture dereferenceable({{.*}})) {{.*}} { |
| // CHECK-64: entry: |
| // CHECK-64: %1 = bitcast %O4enum27MultiPayloadNestedSpareBits* %0 to [[WORD]]* |
| // CHECK-64: %2 = load [[WORD]], [[WORD]]* %1 |
| // CHECK-64: %3 = lshr [[WORD]] %2, 61 |
| // CHECK-64: %4 = trunc [[WORD]] %3 to i1 |
| // CHECK-64: br i1 %4 |
| sil @multi_payload_nested_spare_bits_switch : $(@in MultiPayloadNestedSpareBits) -> () { |
| entry(%c : $*MultiPayloadNestedSpareBits): |
| switch_enum_addr %c : $*MultiPayloadNestedSpareBits, case #MultiPayloadNestedSpareBits.A!enumelt.1: a_dest, case #MultiPayloadNestedSpareBits.B!enumelt.1: b_dest |
| |
| a_dest: |
| br end |
| |
| b_dest: |
| br end |
| |
| end: |
| return undef : $() |
| } |
| |
| |
| // -- test for a switch_enum bug for multi-payload, no-empty-case enums |
| // uncovered by Chris |
| enum OnlyPayloads { |
| case x(Builtin.Int64) |
| case y(Builtin.Int32) |
| case z(Builtin.Int16) |
| } |
| |
| sil @only_payloads_switch : $(OnlyPayloads) -> () { |
| entry(%0 : $OnlyPayloads): |
| switch_enum %0 : $OnlyPayloads, case #OnlyPayloads.x!enumelt.1: x_dest, case #OnlyPayloads.y!enumelt.1: y_dest, case #OnlyPayloads.z!enumelt.1: z_dest |
| |
| x_dest: |
| br end |
| y_dest: |
| br end |
| z_dest: |
| br end |
| |
| end: |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // Should not use spare bits, because T may be a tagged ObjC pointer. |
| enum MultiPayloadClassGeneric<T: AnyObject> { |
| case A(C, Builtin.Word) |
| case B(T) |
| } |
| |
| // CHECK-64-LABEL: define{{( protected)?}} { i64, i64, i1 } @multi_payload_class_generic_no_spare_bits(i64, i64, i1, %swift.type* %T) |
| // CHECK-32-LABEL: define{{( protected)?}} { i32, i32, i1 } @multi_payload_class_generic_no_spare_bits(i32, i32, i1, %swift.type* %T) |
| sil @multi_payload_class_generic_no_spare_bits : $@convention(thin) <T: AnyObject> (@owned MultiPayloadClassGeneric<T>) -> MultiPayloadClassGeneric<T> { |
| entry(%e : $MultiPayloadClassGeneric<T>): |
| return %e : $MultiPayloadClassGeneric<T> |
| } |
| |
| // CHECK-64-LABEL: define{{( protected)?}} { i64, i64, i1 } @multi_payload_class_instance_no_spare_bits(i64, i64, i1) |
| // CHECK-32-LABEL: define{{( protected)?}} { i32, i32, i1 } @multi_payload_class_instance_no_spare_bits(i32, i32, i1) |
| sil @multi_payload_class_instance_no_spare_bits : $@convention(thin) (@owned MultiPayloadClassGeneric<C>) -> MultiPayloadClassGeneric<C> { |
| entry(%e : $MultiPayloadClassGeneric<C>): |
| return %e : $MultiPayloadClassGeneric<C> |
| } |
| |
| enum MultiPayloadAddressOnlyFixed { |
| case X(Any) |
| case Y(Builtin.Int32) |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} void @multi_payload_address_only_destroy(%O4enum28MultiPayloadAddressOnlyFixed* noalias nocapture dereferenceable({{.*}})) |
| sil @multi_payload_address_only_destroy : $@convention(thin) (@in MultiPayloadAddressOnlyFixed) -> () { |
| entry(%m : $*MultiPayloadAddressOnlyFixed): |
| destroy_addr %m : $*MultiPayloadAddressOnlyFixed |
| return undef : $() |
| } |
| |
| // Even if spare bits are available in an address-only payload, |
| // we cannot use them. |
| |
| struct AddressOnlySpareBitsPayload { |
| weak var x: C? |
| var y: C |
| } |
| |
| enum MultiPayloadAddressOnlySpareBits { |
| case X(AddressOnlySpareBitsPayload) |
| case Y(AddressOnlySpareBitsPayload) |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} void @multi_payload_address_only_spare_bits(%O4enum32MultiPayloadAddressOnlySpareBits* noalias nocapture dereferenceable({{.*}})) |
| sil @multi_payload_address_only_spare_bits : $@convention(thin) (@in MultiPayloadAddressOnlySpareBits) -> () { |
| entry(%m : $*MultiPayloadAddressOnlySpareBits): |
| destroy_addr %m : $*MultiPayloadAddressOnlySpareBits |
| return undef : $() |
| } |
| |
| // Force the storage types to all be generated. |
| typealias AllConcreteTestEnums = ( |
| Empty, |
| EmptySingleton, |
| Singleton, |
| SingletonRef, |
| NoPayloads, |
| NoPayloads2, |
| SinglePayloadNoXI, |
| SinglePayloadNoXI2, |
| SinglePayloadSpareBit, |
| SinglePayloadNested, |
| SinglePayloadNestedNested, |
| MultiPayloadNoSpareBits, |
| MultiPayloadOneSpareBit, |
| MultiPayloadTwoSpareBits, |
| MultiPayloadSpareBitAggregates, |
| MultiPayloadNested, |
| MultiPayloadNestedSpareBits) |
| |
| sil_global @x : $AllConcreteTestEnums |
| |
| // CHECK: define{{( protected)?}} void @dynamic_singleton_switch_indirect([[DYNAMIC_SINGLETON]]* noalias nocapture, %swift.type* %T) {{.*}} { |
| // CHECK: bitcast [[DYNAMIC_SINGLETON]]* %0 to %swift.opaque* |
| // CHECK: ret void |
| // CHECK: } |
| sil @dynamic_singleton_switch_indirect : $<T> (@in DynamicSingleton<T>) -> () { |
| entry(%0 : $*DynamicSingleton<T>): |
| switch_enum_addr %0 : $*DynamicSingleton<T>, case #DynamicSingleton.value!enumelt.1: dest |
| |
| dest: |
| %1 = unchecked_take_enum_data_addr %0 : $*DynamicSingleton<T>, #DynamicSingleton.value!enumelt.1 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // Verify that we can instantiate generic enum instances of dynamic size. |
| sil_global @aa : $DynamicSingleton<()> |
| sil_global @bb : $DynamicSingleton<NoPayloads> |
| |
| // CHECK: define{{( protected)?}} void @dynamic_singleton_instance_arg_1() |
| sil @dynamic_singleton_instance_arg_1 : $(DynamicSingleton<()>) -> () { |
| entry(%0 : $DynamicSingleton<()>): |
| %v = tuple () |
| return %v : $() |
| } |
| // CHECK: define{{( protected)?}} void @dynamic_singleton_instance_arg_2(i8) |
| sil @dynamic_singleton_instance_arg_2 : $(DynamicSingleton<NoPayloads>) -> () { |
| entry(%0 : $DynamicSingleton<NoPayloads>): |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // Check that payloads get properly masked in nested single-payload enums. |
| // rdar://problem/18841262 |
| // CHECK-64-LABEL: define{{( protected)?}} i1 @optional_optional_class_protocol(i64, i64) |
| // CHECK-64: icmp eq i64 %0, 2 |
| // CHECK-32-LABEL: define{{( protected)?}} i1 @optional_optional_class_protocol(i32, i32) |
| // CHECK-32: icmp eq i32 %0, 1 |
| enum Optionable<T> { |
| case some(T), none |
| } |
| sil @optional_optional_class_protocol : $@convention(thin) Optionable<Optionable<PC>> -> Builtin.Int1 { |
| entry(%o : $Optionable<Optionable<PC>>): |
| %t = integer_literal $Builtin.Int1, 1 |
| %f = integer_literal $Builtin.Int1, 0 |
| %r = select_enum %o : $Optionable<Optionable<PC>>, case #Optionable.some!enumelt.1: %t, case #Optionable.none!enumelt: %f : $Builtin.Int1 |
| return %r : $Builtin.Int1 |
| } |
| |
| struct ContainsUnowned { |
| unowned let x: C |
| } |
| struct ContainsUnownedObjC { |
| unowned let x: C |
| } |
| // CHECK-LABEL: define {{.*}} @optional_unowned() {{.*}} { |
| // CHECK-objc-64: ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true } |
| // CHECK-native-64: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 2 } |
| // CHECK-objc-32: ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true } |
| // CHECK-native-32: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 } |
| sil @optional_unowned : $@convention(thin) () -> (Optionable<ContainsUnowned>, Optionable<Optionable<ContainsUnowned>>) { |
| entry: |
| %a = enum $Optionable<ContainsUnowned>, #Optionable.none!enumelt |
| %b = enum $Optionable<Optionable<ContainsUnowned>>, #Optionable.none!enumelt |
| %t = tuple (%a : $Optionable<ContainsUnowned>, %b : $Optionable<Optionable<ContainsUnowned>>) |
| return %t : $(Optionable<ContainsUnowned>, Optionable<Optionable<ContainsUnowned>>) |
| } |
| // CHECK-LABEL: define {{.*}} @optional_unowned_objc() {{.*}} { |
| // CHECK-objc-64: ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true } |
| // CHECK-native-64: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 2 } |
| // CHECK-objc-32: ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true } |
| // CHECK-native-32: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 } |
| sil @optional_unowned_objc : $@convention(thin) () -> (Optionable<ContainsUnownedObjC>, Optionable<Optionable<ContainsUnownedObjC>>) { |
| entry: |
| %a = enum $Optionable<ContainsUnownedObjC>, #Optionable.none!enumelt |
| %b = enum $Optionable<Optionable<ContainsUnownedObjC>>, #Optionable.none!enumelt |
| %t = tuple (%a : $Optionable<ContainsUnownedObjC>, %b : $Optionable<Optionable<ContainsUnownedObjC>>) |
| return %t : $(Optionable<ContainsUnownedObjC>, Optionable<Optionable<ContainsUnownedObjC>>) |
| } |
| |
| // CHECK-64-LABEL: define{{( protected)?}} { i64, i1 } @empty_payload_enum_in_enum(i32) |
| sil @empty_payload_enum_in_enum : $@convention(thin) (Int32) -> Optional<(Optional<()>, Int32)> { |
| entry(%x : $Int32): |
| %a = tuple () |
| %b = enum $Optional<()>, #Optional.some!enumelt.1, %a : $() |
| %c = tuple (%b : $Optional<()>, %x : $Int32) |
| // CHECK-64: [[INT_ZEXT:%.*]] = zext i32 %0 to i64 |
| // CHECK-64: [[INT_SHL:%.*]] = shl i64 [[INT_ZEXT]], 32 |
| // CHECK-64: [[COMBINE:%.*]] = or i64 0, [[INT_SHL]] |
| %d = enum $Optional<(Optional<()>, Int32)>, #Optional.some!enumelt.1, %c : $(Optional<()>, Int32) |
| // CHECK-64: [[BIT:%.*]] = trunc i64 [[COMBINE]] to i1 |
| // CHECK-64: [[INT_SHR:%.*]] = lshr i64 [[COMBINE]], 32 |
| // CHECK-64: [[INT:%.*]] = trunc i64 [[INT_SHR]] to i32 |
| %e = unchecked_enum_data %d : $Optional<(Optional<()>, Int32)>, #Optional.some!enumelt.1 |
| return %d : $Optional<(Optional<()>, Int32)> |
| } |
| |
| sil @optional_float80 : $@convention(thin) Float80 -> () { |
| entry(%x : $Float80): |
| %y = enum $Optional<Float80>, #Optional.some!enumelt.1, %x : $Float80 |
| return undef : $() |
| } |
| |
| // rdar://problem/21126703 |
| |
| protocol delegateProtocol : AnyObject { } |
| |
| struct StructWithWeakVar { |
| weak var delegate: delegateProtocol? |
| } |
| |
| // CHECK-64-LABEL: define{{( protected)?}} void @weak_optional(%GSqV4enum17StructWithWeakVar_* noalias nocapture dereferenceable({{.*}})) |
| sil @weak_optional : $@convention(thin) (@in StructWithWeakVar?) -> () { |
| entry(%x : $*StructWithWeakVar?): |
| // CHECK-64: icmp eq [[WORD]] {{%.*}}, 0 |
| // CHECK-64-NEXT: icmp eq [[WORD]] {{%.*}}, 1 |
| switch_enum_addr %x : $*StructWithWeakVar?, |
| case #Optional.some!enumelt.1: a, |
| case #Optional.none!enumelt: b |
| a: |
| br x |
| b: |
| // CHECK-64: store [[WORD]] 0 |
| // CHECK-64: store [[WORD]] 1 |
| inject_enum_addr %x : $*StructWithWeakVar?, #Optional.none!enumelt |
| br x |
| |
| x: |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: define{{( protected)?}} void @force_global_variables_to_materialize |
| sil @force_global_variables_to_materialize : $() -> () { |
| entry: |
| // Force the global variables to materialize. |
| %x = global_addr @x : $*AllConcreteTestEnums |
| %y = load %x : $*AllConcreteTestEnums |
| %a = global_addr @aa : $*DynamicSingleton<()> |
| %q = load %a : $*DynamicSingleton<()> |
| %b = global_addr @bb : $*DynamicSingleton<NoPayloads> |
| %r = load %b : $*DynamicSingleton<NoPayloads> |
| %z = tuple () |
| // CHECK: ret void |
| return %z : $() |
| } |
| |
| enum Target { |
| case Public |
| case Friends |
| case SomeFriends([UInt]) |
| } |
| |
| // Ensure that we generate IR that does not run into verification |
| // issues for the case where there is a single tag bit and extra |
| // inhabitants. |
| // CHECK-LABEL: define{{( protected)?}} void @generate_conditional_branch |
| sil @generate_conditional_branch : $@convention(thin) (@owned Target) -> () { |
| bb0(%0 : $Target): |
| debug_value %0 : $Target |
| retain_value %0 : $Target |
| switch_enum %0 : $Target, case #Target.Public!enumelt: bb1, default bb2 |
| |
| bb1: |
| br bb4 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| release_value %0 : $Target |
| br bb4 |
| |
| bb4: |
| release_value %0 : $Target |
| %9 = tuple () |
| // CHECK: ret void |
| return %9 : $() |
| } |
| |
| // -- Fill function for dynamic singleton. The value witness table flags just |
| // get copied over from the element. |
| // CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSingleton(%swift.type_pattern*, i8**) {{.*}} { |
| // CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type** |
| // CHECK: [[T:%T]] = load %swift.type*, %swift.type** [[T0]], |
| // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1) |
| // CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8** |
| // CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 3 |
| // CHECK: [[T0:%.*]] = bitcast %swift.type* [[T]] to i8* |
| // CHECK: store i8* [[T0]], i8** [[T1]] |
| // CHECK: [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 5 |
| // CHECK: [[T0:%.*]] = bitcast i8** [[VWT]] to i8* |
| // CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 -1 |
| // CHECK: store i8* [[T0]], i8** [[T1]] |
| // CHECK: [[T_VWTS:%.*]] = bitcast %swift.type* [[T]] to i8*** |
| // CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[T_VWTS]], [[WORD]] -1 |
| // CHECK: [[T_VWT:%.*]] = load i8**, i8*** [[T_VWT_ADDR]] |
| // CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VWT]], i32 17 |
| // CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 17 |
| // CHECK: [[T_SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 0 |
| // CHECK: [[T_SIZE:%.*]] = load i8*, i8** [[T_SIZE_ADDR]] |
| // CHECK: store i8* [[T_SIZE]], i8** [[SIZE_ADDR]] |
| // CHECK: [[STRIDE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 19 |
| // CHECK: [[T_STRIDE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 2 |
| // CHECK: [[T_STRIDE:%.*]] = load i8*, i8** [[T_STRIDE_ADDR]] |
| // CHECK: store i8* [[T_STRIDE]], i8** [[STRIDE_ADDR]] |
| // CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 18 |
| // CHECK: [[T_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 1 |
| // CHECK: [[T_FLAGS:%.*]] = load i8*, i8** [[T_FLAGS_ADDR]] |
| // CHECK: [[T_FLAGS_INT:%.*]] = ptrtoint i8* [[T_FLAGS]] to [[WORD]] |
| // CHECK: [[T_FLAGS_INT_2:%.*]] = or [[WORD]] [[T_FLAGS_INT]], 2097152 |
| // CHECK: [[T_FLAGS_2:%.*]] = inttoptr [[WORD]] [[T_FLAGS_INT_2]] to i8* |
| // CHECK: store i8* [[T_FLAGS_2]], i8** [[FLAGS_ADDR]] |
| // -- Test the 'has extra inhabitants' bit and carry over the extra inhabitants |
| // flag if set. |
| // CHECK: [[T_FLAGS_VAL:%.*]] = ptrtoint i8* [[T_FLAGS]] to [[WORD]] |
| // CHECK: [[XI_FLAG:%.*]] = and [[WORD]] [[T_FLAGS_VAL]], 262144 |
| // CHECK: [[XI_BIT:%.*]] = icmp ne [[WORD]] [[XI_FLAG]], 0 |
| // CHECK: br i1 [[XI_BIT]], label %[[HAS_XI:[0-9]+]], label %[[HAS_NO_XI:[0-9]+]] |
| // CHECK: ; <label>:[[HAS_XI]] |
| // CHECK: [[XI_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 20 |
| // CHECK: [[T_XI_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 3 |
| // CHECK: [[T_XI_FLAGS:%.*]] = load i8*, i8** [[T_XI_FLAGS_ADDR]] |
| // CHECK: store i8* [[T_XI_FLAGS]], i8** [[XI_FLAGS_ADDR]] |
| // CHECK: br label %[[HAS_NO_XI]] |
| // CHECK: ; <label>:[[HAS_NO_XI]] |
| // CHECK: ret %swift.type* [[METADATA]] |
| |
| // -- Fill function for dynamic single-payload. Call into the runtime to |
| // calculate the size. |
| // CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} { |
| // CHECK: call void @swift_initEnumValueWitnessTableSinglePayload |
| |
| // CHECK-64-LABEL: define linkonce_odr hidden void @_TwxsV4enum17StructWithWeakVar(%swift.opaque* %dest, i32 %index, %swift.type* %StructWithWeakVar) |
| // -- TODO: some pointless masking here. |
| // -- TODO: should use EnumPayload word-chunking. |
| // CHECK-64: %1 = zext i32 %index to i128 |
| // -- 0xFFFF_FFFF_FFFF_FFFF |
| // CHECK-64: %2 = and i128 %1, 18446744073709551615 |
| // CHECK-64: %3 = shl i128 %1, 3 |
| // -- 0xFFFF_FFFF_FFFF_FFF8__0000_0000_0000_0000 |
| // CHECK-64: %4 = and i128 %3, 1329227995784915725329854470603931648 |
| // CHECK-64: %5 = or i128 %2, %4 |
| // -- 0x1__0000_0000_0000_0000 |
| // CHECK-64: %6 = or i128 %5, 18446744073709551616 |
| |
| // CHECK-LABEL: define linkonce_odr hidden i32 @_TwugO4enum40MultiPayloadLessThan32BitsWithEmptyCases(%swift.opaque* %value |
| // CHECK: [[VAL00:%.*]] = bitcast %swift.opaque* %value to %O4enum40MultiPayloadLessThan32BitsWithEmptyCases* |
| // CHECK: [[VAL01:%.*]] = bitcast %O4enum40MultiPayloadLessThan32BitsWithEmptyCases* [[VAL00]] to i8* |
| // CHECK: [[VAL02:%.*]] = load {{.*}} [[VAL01]] |
| // CHECK: [[VAL03:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1 |
| // CHECK: [[VAL04:%.*]] = bitcast {{.*}} [[VAL03]] to i8* |
| // CHECK: [[VAL05:%.*]] = load {{.*}} [[VAL04]] |
| // CHECK: [[VAL06:%.*]] = zext i8 [[VAL05]] to i32 |
| // CHECK: [[VAL07:%.*]] = sub i32 [[VAL06]], 2 |
| // CHECK: [[VAL08:%.*]] = zext i8 [[VAL02]] to i32 |
| // CHECK: [[VAL09:%.*]] = and i32 [[VAL08]], 255 |
| // CHECK: [[VAL10:%.*]] = icmp sge i32 [[VAL07]], 0 |
| // CHECK: [[VAL11:%.*]] = select i1 [[VAL10]], i32 [[VAL09]], i32 [[VAL07]] |
| // CHECK: ret i32 [[VAL11]] |
| |
| // CHECK-LABEL: define linkonce_odr hidden void @_TwuiO4enum40MultiPayloadLessThan32BitsWithEmptyCases(%swift.opaque* %value, i32 %tag |
| // CHECK: entry: |
| // CHECK: [[VAL00:%.*]] = bitcast %swift.opaque* %value |
| // CHECK: [[VAL01:%.*]] = icmp sge i32 %tag, 0 |
| // CHECK: br i1 [[VAL01]], label %[[TLABEL:.*]], label %[[FLABEL:.*]] |
| |
| // CHECK: <label>:[[TLABEL]] |
| // CHECK: [[VAL03:%.*]] = trunc i32 %tag to i8 |
| // CHECK: [[VAL04:%.*]] = bitcast %O4enum40MultiPayloadLessThan32BitsWithEmptyCases* [[VAL00]] to i8* |
| // CHECK: store i8 [[VAL03]], i8* [[VAL04]] |
| // CHECK: [[VAL05:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1 |
| // CHECK: [[VAL06:%.*]] = bitcast [1 x i8]* [[VAL05]] to i8* |
| // CHECK: store i8 2, i8* [[VAL06]] |
| // CHECK: br label %[[RLABEL:.*]] |
| |
| // CHECK: <label>:[[FLABEL]] |
| // CHECK: [[VAL08:%.*]] = add i32 %tag, 2 |
| // CHECK: [[VAL09:%.*]] = trunc i32 [[VAL08]] to i8 |
| // CHECK: [[VAL10:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1 |
| // CHECK: [[VAL11:%.*]] = bitcast [1 x i8]* [[VAL10]] to i8* |
| // CHECK: store i8 [[VAL09]], i8* [[VAL11]] |
| // CHECK: br label %[[RLABEL]] |
| |
| // CHECK: <label>:[[RLABEL]] |
| // CHECK: ret void |
| |
| enum MultiPayloadLessThan32BitsWithEmptyCases { |
| case A |
| case B |
| case C(Builtin.Int8) |
| case D(Builtin.Int8) |
| } |