// #if directives don't work with SIL keywords, therefore please put ObjC tests // in `enum_objc.sil`. // RUN: %target-swift-frontend %s -Xllvm -sil-disable-pass=simplification -disable-type-layout -disable-generic-metadata-prespecialization -disable-generic-metadata-prespecialization -gnone -emit-ir -disable-diagnostic-passes -enable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-objc --check-prefix=CHECK-objc-%target-ptrsize --check-prefix=CHECK-objc-%target-ptrsize-simulator-%target-is-simulator -DWORD=i%target-ptrsize // RUN: %target-swift-frontend %s -Xllvm -sil-disable-pass=simplification -disable-type-layout -disable-generic-metadata-prespecialization -gnone -emit-ir -disable-diagnostic-passes -disable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-native --check-prefix=CHECK-native-%target-ptrsize -DWORD=i%target-ptrsize // REQUIRES: CPU=i386 || CPU=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: %T4enum9SingletonO = type <{ <{ i64, i64 }> }> // -- Singleton enum with heap object ref payload. // CHECK: %T4enum12SingletonRefO = type <{ ptr }> // -- No-payload enums. The representation is just an enum tag. // CHECK: %T4enum10NoPayloadsO = type <{ i8 }> // CHECK: %T4enum11NoPayloads2O = 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: %T4enum17SinglePayloadNoXIO = type <{ [8 x i8], [1 x i8] }> // CHECK-64: %T4enum18SinglePayloadNoXI2O = type <{ [8 x i8], [1 x i8] }> // CHECK-32: %T4enum17SinglePayloadNoXIO = type <{ [4 x i8], [1 x i8] }> // CHECK-32: %T4enum18SinglePayloadNoXI2O = 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: %T4enum21SinglePayloadSpareBitO = 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: %T4enum19SinglePayloadNestedO = 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: %T4enum019SinglePayloadNestedD0O = 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: %T4enum23MultiPayloadNoSpareBitsO = 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: %T4enum23MultiPayloadOneSpareBitO = 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: %T4enum24MultiPayloadTwoSpareBitsO = type <{ [8 x i8] }> // CHECK-64: %T4enum30MultiPayloadSpareBitAggregatesO = type <{ [16 x i8] }> // CHECK-64: %T4enum18MultiPayloadNestedO = type <{ [9 x i8] }> // CHECK-32: %T4enum18MultiPayloadNestedO = type <{ [5 x i8] }> // 32-bit object references don't have enough spare bits. // CHECK-64: %T4enum27MultiPayloadNestedSpareBitsO = type <{ [8 x i8] }> // -- Dynamic enums. The type layout is opaque; we dynamically bitcast to // the element type. // -- Address-only multi-payload enums. We can't use spare bits. // CHECK-64: %T4enum32MultiPayloadAddressOnlySpareBitsO = type <{ [16 x i8], [1 x i8] }> // CHECK-32: %T4enum32MultiPayloadAddressOnlySpareBitsO = type <{ [8 x i8], [1 x i8] }> // CHECK: %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO = type <{ [1 x i8], [1 x i8] }> // -- Dynamic metadata template carries a value witness table pattern // we fill in on instantiation. // FIXME: Strings should be unnamed_addr. rdar://problem/22674524 // CHECK: @"$s4enum16DynamicSingletonOWV" = // CHECK-SAME: [[WORD]] 0, // CHECK-SAME: [[WORD]] 0, // 6291456 == 0x600000 (enum, incomplete) // CHECK-SAME: i32 6291456, // CHECK-SAME: i32 0, // Enum witnesses. // CHECK-SAME: ptr @"$s4enum16DynamicSingletonOwug" // CHECK-SAME: ptr @"$s4enum16DynamicSingletonOwup" // CHECK-SAME: ptr @"$s4enum16DynamicSingletonOwui" // CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [17 x i8] c"DynamicSingleton\00" // CHECK: @"$s4enum16DynamicSingletonOMn" = hidden constant <{ // CHECK-SAME: ptr [[DYNAMICSINGLETON_NAME]] // -- One payload // CHECK-SAME: i32 1, // -- No empty cases // CHECK-SAME: i32 0, // -- generic instantiation pattern // CHECK-SAME: @"$s4enum16DynamicSingletonOMP" // -- generic parameters, requirements, key, extra // CHECK-SAME: i16 1, i16 0, i16 1, i16 0 // -- generic param // CHECK-SAME: i8 -128, // CHECK-SAME: }> // CHECK: @"$s4enum16DynamicSingletonOMP" = internal constant <{ {{.*}} }> <{ // CHECK-SAME: @"$s4enum16DynamicSingletonOMi" // CHECK-SAME: ptr @"$s4enum16DynamicSingletonOWV" // -- No-payload enums have extra inhabitants in // their value witness table. // CHECK: @"$s4enum10NoPayloadsOWV" = internal constant %swift.enum_vwtable { // -- ... // -- size // CHECK-SAME: [[WORD]] 1, // -- stride // CHECK-SAME: [[WORD]] 1, // -- flags (0x20_0000: alignment 1 and enum witnesses) // CHECK-SAME: i32 2097152, // -- num extra inhabitants (256 - 3 valid states) // CHECK-SAME: i32 253, // CHECK-SAME: }, align // -- Single-payload enums take unused extra inhabitants from their payload // as their own. // CHECK: @"$s4enum19SinglePayloadNestedOWV" = internal constant %swift.enum_vwtable { // -- ... // -- size // CHECK-SAME: [[WORD]] 1, // -- stride // CHECK-SAME: [[WORD]] 1, // -- flags (0x20_0000: alignment 1 and enum witnesses) // CHECK-SAME: i32 2097152, // -- num extra inhabitants (253 from payload - 3 empty cases) // CHECK-SAME: i32 250, // CHECK-SAME: } // CHECK: @"$s4enum20DynamicSinglePayloadOWV" = internal constant %swift.enum_vwtable { // -- flags (0x60_0000: alignment 1, incomplete, enum witnesses) // CHECK-SAME: i32 6291456, // -- num extra inhabitants (253 from payload - 3 empty cases) // CHECK-SAME: i32 0, // CHECK: @"$s4enum20DynamicSinglePayloadOMP" = internal constant <{ {{.*}} }> <{ // CHECK-SAME: @"$s4enum20DynamicSinglePayloadOMi" // CHECK-SAME: ptr @"$s4enum20DynamicSinglePayloadOWV" // CHECK: @"$s4enum18MultiPayloadNestedOWV" = internal constant %swift.enum_vwtable { // -- size // CHECK-32-SAME: [[WORD]] 5, // CHECK-64-SAME: [[WORD]] 9, // -- flags (0x250003: alignment 4, enum) // -- flags (0x200007: alignment 8, enum) // CHECK-32-SAME: i32 2097155, // CHECK-64-SAME: i32 2097159, // CHECK-SAME: } enum Empty {} enum EmptySingleton { case foo } enum Singleton { case value(Builtin.Int64, Builtin.Int64) } enum SingletonRef { case value(Builtin.NativeObject) } enum DynamicSingleton { case value(T) } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch(i64 %0, i64 %1) {{.*}} { // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch(ptr noalias dereferenceable(16) %0) {{.*}} { sil @singleton_switch : $(Singleton) -> () { // CHECK-64: entry: // CHECK-32: entry: entry(%u : $Singleton): // CHECK-64: br label %[[DEST:[0-9]+]] // CHECK-32: br label %[[DEST:[0-9]+]] switch_enum %u : $Singleton, case #Singleton.value!enumelt: dest // CHECK-64: [[DEST]]: // CHECK-32: [[DEST]]: dest: // CHECK-64: ret void // CHECK-32: ret void %x = tuple () return %x : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch_arg(i64 %0, i64 %1) {{.*}} { // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch_arg(ptr noalias dereferenceable(16) %0) {{.*}} { sil @singleton_switch_arg : $(Singleton) -> () { // CHECK-64: entry: // CHECK-32: entry: entry(%u : $Singleton): // CHECK-32: call ptr @"$s4enum9SingletonOWOb" // CHECK-64: br label %[[PREDEST:[0-9]+]] // CHECK-32: br label %[[PREDEST:[0-9]+]] switch_enum %u : $Singleton, case #Singleton.value!enumelt: dest // CHECK-64: [[PREDEST]]: // CHECK-64: br label %[[DEST:[0-9]+]] // CHECK-64: [[DEST]]: dest(%u2 : $(Builtin.Int64, Builtin.Int64)): // CHECK-64: {{%.*}} = phi i64 [ %0, %[[PREDEST]] ] // CHECK-64: {{%.*}} = phi i64 [ %1, %[[PREDEST]] ] // CHECK-64: ret void %x = tuple () return %x : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK: entry: // CHECK: br label %[[DEST:[0-9]+]] // CHECK: [[DEST]]: // CHECK: ret void // CHECK: } sil @singleton_switch_indirect : $(@inout Singleton) -> () { entry(%u : $*Singleton): switch_enum_addr %u : $*Singleton, case #Singleton.value!enumelt: dest dest: %u2 = unchecked_take_enum_data_addr %u : $*Singleton, #Singleton.value!enumelt %x = tuple () return %x : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i64 } @singleton_inject(i64 %0, i64 %1) {{.*}} { // CHECK-64: entry: // CHECK-64: [[A:%.*]] = insertvalue { i64, i64 } undef, i64 %0, 0 // CHECK-64: [[B:%.*]] = insertvalue { i64, i64 } [[A]], i64 %1, 1 // CHECK-64: ret { i64, i64 } [[B]] // CHECK-64: } // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_inject(ptr noalias sret({{.*}}) %0, i64 %1, i64 %2) {{.*}} { // CHECK-32: entry: // CHECK-32: [[GEP1:%.*]] = getelementptr inbounds <{ i64, i64 }>, ptr %0, i32 0, i32 0 // CHECK-32: store i64 %1, ptr [[GEP1]] // CHECK-32: [[GEP2:%.*]] = getelementptr inbounds <{ i64, i64 }>, ptr %0, i32 0, i32 1 // CHECK-32: store i64 %2, ptr [[GEP2]] // CHECK-32: ret void // CHECK-32: } 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, %t : $(Builtin.Int64, Builtin.Int64) return %u : $Singleton } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_inject_indirect(i64 %0, i64 %1, ptr captures(none) dereferenceable({{.*}}) %2) {{.*}} { // CHECK: entry: // CHECK: [[DATA_0_ADDR:%.*]] = getelementptr inbounds{{.*}} <{ i64, i64 }>, ptr %2, i32 0, i32 0 // CHECK: store i64 %0, ptr [[DATA_0_ADDR]] // CHECK: [[DATA_1_ADDR:%.*]] = getelementptr inbounds{{.*}} <{ i64, i64 }>, ptr %2, i32 0, i32 1 // CHECK: store i64 %1, ptr [[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 store %t to %a : $*(Builtin.Int64, Builtin.Int64) inject_enum_addr %2 : $*Singleton, #Singleton.value!enumelt %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{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_switch(i8 %0) {{.*}} { 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: [[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: [[X_DEST]]: // CHECK: call swiftcc void @a() // CHECK: br label %[[END:[0-9]+]] x_dest: %a = function_ref @a : $@convention(thin) () -> () apply %a() : $@convention(thin) () -> () br end // CHECK: [[Y_DEST]]: // CHECK: call swiftcc void @b() // CHECK: br label %[[END]] y_dest: %b = function_ref @b : $@convention(thin) () -> () apply %b() : $@convention(thin) () -> () br end // CHECK: [[Z_DEST]]: // CHECK: call swiftcc void @c() // CHECK: br label %[[END]] z_dest: %c = function_ref @c : $@convention(thin) () -> () apply %c() : $@convention(thin) () -> () br end // CHECK: [[END]]: // CHECK: ret void end: %x = tuple () return %x : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_switch_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { sil @no_payload_switch_indirect : $@convention(thin) (@inout NoPayloads) -> () { entry(%u : $*NoPayloads): // CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds{{.*}} %T4enum10NoPayloadsO, ptr %0, i32 0, i32 0 // CHECK: [[TAG:%.*]] = load i8, ptr [[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{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_inject_z_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK: entry: // CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds{{.*}} %T4enum10NoPayloadsO, ptr %0, i32 0, i32 0 // CHECK: store i8 2, ptr [[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{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_switch_2(i8 %0) {{.*}} { 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: [[U_DEST]]: u_dest: // CHECK: call swiftcc void @a() %a = function_ref @a : $@convention(thin) () -> () apply %a() : $@convention(thin) () -> () // CHECK: br label %[[END:[0-9]+]] br end // CHECK: [[DEFAULT_DEST]]: default_dest: // CHECK: call swiftcc void @b() %b = function_ref @b : $@convention(thin) () -> () apply %b() : $@convention(thin) () -> () // CHECK: br label %[[END]] br end // CHECK: [[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-32: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @select_enum([[WORD:i32]] %0, i8 %1) // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @select_enum([[WORD:i64]] %0, i8 %1) // CHECK: entry: // CHECK: [[PAYLOAD:%.*]] = icmp eq [[WORD]] %0, 1 // CHECK: [[TAG:%.*]] = icmp eq i8 %1, 1 // CHECK: [[COMBINED:%.*]] = and i1 [[TAG]], [[PAYLOAD]] // CHECK: [[RES:%.*]] = select i1 [[COMBINED]], i1 false, i1 true // CHECK: ret i1 [[RES]] // CHECK: } sil @select_enum : $@convention(method) (SinglePayloadNoXI2) -> Builtin.Int1 { bb0(%0 : $SinglePayloadNoXI2): %2 = integer_literal $Builtin.Int1, 0 %3 = integer_literal $Builtin.Int1, -1 %4 = select_enum %0 : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.z!enumelt: %2, default %3 : $Builtin.Int1 return %4 : $Builtin.Int1 } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_switch([[WORD:i64]] %0, i8 %1) {{.*}} { // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_switch([[WORD:i32]] %0, i8 %1) {{.*}} { sil @single_payload_no_xi_switch : $@convention(thin) (SinglePayloadNoXI2) -> () { // CHECK: entry: entry(%u : $SinglePayloadNoXI2): // CHECK: %2 = icmp eq i8 %1, 1 // CHECK: br i1 %2, label %[[TAGS:[0-9]+]], label %[[X_DEST:[0-9]+]] // CHECK: [[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: [[DFLT]]: // CHECK: unreachable switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt: 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: [[X_DEST]]: // CHECK: call swiftcc void @a() // CHECK: br label %[[END:[0-9]+]] x_dest: %a = function_ref @a : $@convention(thin) () -> () apply %a() : $@convention(thin) () -> () br end // CHECK: [[Y_DEST]]: // CHECK: call swiftcc void @b() // CHECK: br label %[[END]] y_dest: %b = function_ref @b : $@convention(thin) () -> () apply %b() : $@convention(thin) () -> () br end // CHECK: [[Z_DEST]]: // CHECK: call swiftcc void @c() // CHECK: br label %[[END]] z_dest: %c = function_ref @c : $@convention(thin) () -> () apply %c() : $@convention(thin) () -> () br end // CHECK: [[W_DEST]]: // CHECK: call swiftcc void @a() // CHECK: br label %[[END:[0-9]+]] w_dest: %d = function_ref @a : $@convention(thin) () -> () apply %d() : $@convention(thin) () -> () br end // CHECK: [[V_DEST]]: // CHECK: call swiftcc void @b() // CHECK: br label %[[END]] v_dest: %e = function_ref @b : $@convention(thin) () -> () apply %e() : $@convention(thin) () -> () br end // CHECK: [[U_DEST]]: // CHECK: call swiftcc void @c() // CHECK: br label %[[END]] u_dest: %f = function_ref @c : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> () br end // CHECK: [[END]]: // CHECK: ret void end: %x = tuple () return %x : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_switch_arg([[WORD]] %0, i8 %1) {{.*}} { sil @single_payload_no_xi_switch_arg : $@convention(thin) (SinglePayloadNoXI2) -> () { // CHECK: entry: entry(%u : $SinglePayloadNoXI2): // CHECK: %2 = icmp eq i8 %1, 1 // CHECK: br i1 %2, label %[[TAGS:[0-9]+]], label %[[X_PREDEST:[0-9]+]] // CHECK: [[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: [[DFLT]]: // CHECK: unreachable switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt: x_dest, case #SinglePayloadNoXI2.y!enumelt: y_dest, case #SinglePayloadNoXI2.z!enumelt: z_dest, default default_dest // CHECK: [[X_PREDEST]]: // CHECK: br label %[[X_DEST:[0-9]+]] // CHECK: [[X_DEST]]: // CHECK: {{%.*}} = phi [[WORD]] [ %0, %[[X_PREDEST]] ] x_dest(%u2 : $Builtin.Word): // CHECK: call swiftcc void @a() // CHECK: br label %[[END]] %a = function_ref @a : $@convention(thin) () -> () apply %a() : $@convention(thin) () -> () br end // CHECK: [[Y_DEST]]: y_dest: // CHECK: call swiftcc void @b() // CHECK: br label %[[END]] %b = function_ref @b : $@convention(thin) () -> () apply %b() : $@convention(thin) () -> () br end // CHECK: [[Z_DEST]]: z_dest: // CHECK: call swiftcc void @c() // CHECK: br label %[[END]] %c = function_ref @c : $@convention(thin) () -> () apply %c() : $@convention(thin) () -> () br end // CHECK: [[SPLITEDGE]]: // CHECK: br label %[[END:[0-9]+]] default_dest: br end // CHECK: [[END]]: // CHECK: ret void end: %x = tuple () return %x : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], i8 } @single_payload_no_xi_inject_x([[WORD]] %0) {{.*}} { // CHECK: entry: // CHECK: [[A:%.*]] = insertvalue { [[WORD]], i8 } undef, [[WORD]] %0, 0 // CHECK: [[B:%.*]] = insertvalue { [[WORD]], i8 } [[A]], i8 0, 1 // CHECK: ret { [[WORD]], i8 } [[B]] // CHECK: } sil @single_payload_no_xi_inject_x : $(Builtin.Word) -> SinglePayloadNoXI2 { entry(%0 : $Builtin.Word): %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt, %0 : $Builtin.Word return %u : $SinglePayloadNoXI2 } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_inject_x_indirect([[WORD]] %0, ptr captures(none) dereferenceable({{.*}}) %1) {{.*}} { // CHECK: entry: // CHECK: store [[WORD]] %0, ptr %1 // CHECK: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum18SinglePayloadNoXI2O, ptr %1, i32 0, i32 1 // CHECK: store i8 0, ptr [[T0]] // 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 store %0 to %a : $*Builtin.Word inject_enum_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt %v = tuple () return %v : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], i8 } @single_payload_no_xi_inject_y() {{.*}} { // CHECK: entry: // CHECK: ret { [[WORD]], i8 } { [[WORD]] 0, i8 1 } // CHECK: } sil @single_payload_no_xi_inject_y : $() -> SinglePayloadNoXI2 { entry: %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt return %u : $SinglePayloadNoXI2 } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_inject_y_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK: entry: // CHECK: store [[WORD]] 0, ptr %0 // CHECK: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum18SinglePayloadNoXI2O, ptr %0, i32 0, i32 1 // CHECK: store i8 1, ptr [[T0]] // 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{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], i8 } @single_payload_no_xi_inject_z() {{.*}} { // CHECK: entry: // CHECK: ret { [[WORD]], i8 } { [[WORD]] 1, i8 1 } // 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{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack // CHECK: ([[WORD]] %0, [[WORD]] %1, i8 %2) {{.*}} { sil @aggregate_single_payload_unpack : $@convention(thin) (AggregateSinglePayload) -> () { entry(%u : $AggregateSinglePayload): switch_enum %u : $AggregateSinglePayload, case #AggregateSinglePayload.x!enumelt: x_dest, default default_dest // CHECK: [[FIRST:%.*]] = phi [[WORD]] [ %0 // CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1 // CHECK: call swiftcc void @int64_sink([[WORD]] [[FIRST]]) // CHECK: call swiftcc 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 default_dest: br end end: %x = tuple () return %x : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]] } @aggregate_single_payload_unsafe_unpack([[WORD]] %0, [[WORD]] %1, i8 %2) {{.*}} { // 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 return %x : $(Builtin.Word, Builtin.Word) } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]], i8 } @aggregate_single_payload_inject([[WORD]] %0, [[WORD]] %1) {{.*}} { // CHECK: entry: // CHECK: [[RES_0:%.*]] = insertvalue { [[WORD]], [[WORD]], i8 } undef, [[WORD]] %0, 0 // CHECK: [[RES_1:%.*]] = insertvalue { [[WORD]], [[WORD]], i8 } [[RES_0]], [[WORD]] %1, 1 // CHECK: [[RES:%.*]] = insertvalue { [[WORD]], [[WORD]], i8 } [[RES_1]], i8 0, 2 // CHECK: ret { [[WORD]], [[WORD]], i8 } [[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, %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-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack_2([[WORD]] %0, [[WORD]] %1, [[WORD]] %2, [[WORD]] %3) {{.*}} { // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack_2(ptr noalias dereferenceable(16) %0) {{.*}} { sil @aggregate_single_payload_unpack_2 : $@convention(thin) (AggregateSinglePayload2) -> () { entry(%u : $AggregateSinglePayload2): switch_enum %u : $AggregateSinglePayload2, case #AggregateSinglePayload2.x!enumelt: x_dest, default default_dest // CHECK-64: [[TRUNC:%.*]] = trunc [[WORD]] %0 to i21 // CHECK-64: phi i21 [ [[TRUNC]] // CHECK-64: phi [[WORD]] [ %1 // CHECK-64: phi [[WORD]] [ %2 // CHECK-64: phi [[WORD]] [ %3 x_dest(%v : $(CharLike, IntLike, RangeLike)): br end default_dest: br end end: %x = tuple () return %x : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } @aggregate_single_payload_2_inject(i32 %0, [[WORD]] %1, [[WORD]] %2, [[WORD]] %3) {{.*}} { // CHECK-64: entry: // CHECK-64: %4 = trunc i32 %0 to i21 // CHECK-64: %5 = zext i21 %4 to [[WORD]] // CHECK-64: %6 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } undef, [[WORD]] %5, 0 // CHECK-64: %7 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %6, [[WORD]] %1, 1 // CHECK-64: %8 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %7, [[WORD]] %2, 2 // CHECK-64: %9 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %8, [[WORD]] %3, 3 // CHECK-64: ret { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %9 // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_2_inject(ptr noalias sret({{.*}}) %0, i32 %1, i32 %2, i32 %3, i32 %4) {{.*}} { // CHECK-32: [[TRUNC:%.*]] = trunc i32 %1 to i21 // CHECK-32: [[ZEXT:%.*]] = zext i21 [[TRUNC]] to i32 // CHECK-32: [[GEP:%.*]] = getelementptr inbounds {{.*}} %0, i32 0, i32 0 // CHECK-32: store i32 [[ZEXT]], ptr [[GEP]] // CHECK-32: store i32 %2, ptr // CHECK-32: store i32 %3, ptr // CHECK-32: store i32 %4, ptr // CHECK-32: ret void 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, %t : $(CharLike, IntLike, RangeLike) return %u : $AggregateSinglePayload2 } enum AggregateSinglePayload3 { case x(Builtin.Int21, Builtin.Word) case y case z } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack_3([[WORD]] %0, [[WORD]] %1) {{.*}} { sil @aggregate_single_payload_unpack_3 : $@convention(thin) (AggregateSinglePayload3) -> () { entry(%u : $AggregateSinglePayload3): switch_enum %u : $AggregateSinglePayload3, case #AggregateSinglePayload3.x!enumelt: x_dest, default default_dest // CHECK: [[TRUNC:%.*]] = trunc [[WORD]] %0 to i21 // CHECK: [[FIRST:%.*]] = phi i21 [ [[TRUNC]] // CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1 // CHECK: [[ZEXT:%.*]] = zext i21 [[FIRST]] to i32 // CHECK: call swiftcc void @int21_sink(i32 [[ZEXT]]) // CHECK: call swiftcc 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 default_dest: br end end: %x = tuple () return %x : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]] } @aggregate_single_payload_inject_x3(i32 %0, [[WORD]] %1) {{.*}} { // CHECK: entry: // CHECK: [[TRUNC:%.*]] = trunc i32 %0 to i21 // CHECK: [[ZEXT:%.*]] = zext i21 [[TRUNC]] to [[WORD]] // CHECK: [[A:%.*]] = insertvalue { [[WORD]], [[WORD]] } undef, [[WORD]] [[ZEXT]], 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, %t : $(Builtin.Int21, Builtin.Word) return %u : $AggregateSinglePayload3 } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[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{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_switch(i64 %0) {{.*}} { // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_switch(i32 %0, i32 %1) {{.*}} { sil @single_payload_spare_bit_switch : $@convention(thin) (SinglePayloadSpareBit) -> () { // CHECK: entry: entry(%u : $SinglePayloadSpareBit): // CHECK: switch i64 %{{[0-9]+}}, label %[[X_DEST:[0-9]+]] [ // -- 0x8000_0000_0000_0000 // CHECK: i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]] // -- 0x8000_0000_0000_0001 // CHECK: i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]] // CHECK: ] switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest // CHECK: [[X_DEST]]: x_dest: // CHECK: call swiftcc void @a() %a = function_ref @a : $@convention(thin) () -> () apply %a() : $@convention(thin) () -> () // CHECK: br label %[[END:[0-9]+]] br end // CHECK: [[Y_DEST]]: y_dest: // CHECK: call swiftcc void @b() %b = function_ref @b : $@convention(thin) () -> () apply %b() : $@convention(thin) () -> () // CHECK: br label %[[END]] br end // CHECK: [[Z_DEST]]: z_dest: // CHECK: call swiftcc void @c() %c = function_ref @c : $@convention(thin) () -> () apply %c() : $@convention(thin) () -> () // CHECK: br label %[[END]] br end // CHECK: [[END]]: end: // CHECK: ret void %x = tuple () return %x : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_switch_arg(i64 %0) {{.*}} { 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: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest // CHECK-64: [[X_PREDEST]]: // CHECK-64: [[TRUNC_PAYLOAD:%.*]] = trunc i64 %0 to i63 // CHECK-64: br label %[[X_DEST:[0-9]+]] // CHECK-64: [[X_DEST]]: // CHECK-64: {{%.*}} = phi i63 [ [[TRUNC_PAYLOAD]], %[[X_PREDEST]] ] x_dest(%u2 : $Builtin.Int63): // CHECK-64: call swiftcc void @a() %a = function_ref @a : $@convention(thin) () -> () apply %a() : $@convention(thin) () -> () // CHECK-64: br label %[[END:[0-9]+]] br end // CHECK-64: [[Y_DEST]]: y_dest: // CHECK-64: call swiftcc void @b() %b = function_ref @b : $@convention(thin) () -> () apply %b() : $@convention(thin) () -> () // CHECK-64: br label %[[END]] br end // CHECK-64: [[Z_DEST]]: z_dest: // CHECK-64: call swiftcc void @c() %c = function_ref @c : $@convention(thin) () -> () apply %c() : $@convention(thin) () -> () // CHECK-64: br label %[[END]] br end // CHECK-64: [[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:%.*]] = load i64, ptr %0 // CHECK-64: switch i64 [[PAYLOAD]], label %[[DFLT:[0-9]+]] [ switch_enum_addr %u : $*SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest // CHECK-64: [[DFLT]]: x_dest: %u2 = unchecked_take_enum_data_addr %u : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt %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{{( dllexport)?}}{{( protected)?}} swiftcc i64 @single_payload_spare_bit_inject_x(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[T:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[A:%.*]] = zext i63 [[T]] 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, %0 : $Builtin.Int63 return %u : $SinglePayloadSpareBit } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_x_indirect(i64 %0, ptr captures(none) dereferenceable({{.*}}) %1) {{.*}} { // CHECK-64: entry: // CHECK-64: [[T:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[BYTE:%.*]] = zext i63 [[T]] to i64 // CHECK-64: store i64 [[BYTE]], ptr %1 // 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 store %0 to %a : $*Builtin.Int63 inject_enum_addr %1 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_y_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK-64: entry: // -- 0x8000_0000_0000_0000 // CHECK-64: store i64 -9223372036854775808, ptr %0 // 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{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_nested_switch(i8 %0) {{.*}} { 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: 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: 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 @$s4enum1CCfD : $@convention(method) (C) -> () enum SinglePayloadClass { case x(C) case y case z case w } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_switch(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: switch i64 %0, label %[[DFLT:[0-9]+]] [ // CHECK-64: i64 0, label {{%.*}} // CHECK-objc-64-simulator-false: i64 2, label {{%.*}} // CHECK-objc-64-simulator-false: i64 4, label {{%.*}} // CHECK-objc-64-simulator-true: i64 1, label {{%.*}} // CHECK-objc-64-simulator-true: i64 2, label {{%.*}} // CHECK-native-64: i64 1, label {{%.*}} // CHECK-native-64: i64 2, label {{%.*}} // CHECK-64: ] // CHECK-64: [[DFLT]]: // CHECK-64: inttoptr [[WORD]] %0 to ptr // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_switch(i32 %0) {{.*}} { // CHECK-32: entry: // CHECK-32: switch i32 %0, label %[[DFLT:[0-9]+]] [ // CHECK-32: i32 0, label {{%.*}} // CHECK-32: i32 1, label {{%.*}} // CHECK-32: i32 2, label {{%.*}} // CHECK-32: ] // CHECK-32: [[DFLT]]: // CHECK-32: inttoptr [[WORD]] %0 to ptr sil @single_payload_class_switch : $(SinglePayloadClass) -> () { entry(%c : $SinglePayloadClass): switch_enum %c : $SinglePayloadClass, case #SinglePayloadClass.x!enumelt: 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 {} enum SinglePayloadClassProtocol { case x(PC) case y, z, w } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_protocol_switch(i64 %0, i64 %1) {{.*}} { // CHECK-64: switch i64 %0, label {{%.*}} [ // CHECK-64: i64 0, label {{%.*}} // CHECK-objc-64-simulator-false: i64 2, label {{%.*}} // CHECK-objc-64-simulator-false: i64 4, label {{%.*}} // CHECK-objc-64-simulator-true: i64 1, label {{%.*}} // CHECK-objc-64-simulator-true: i64 2, label {{%.*}} // CHECK-native-64: i64 1, label {{%.*}} // CHECK-native-64: i64 2, label {{%.*}} // CHECK-64: ] // CHECK-objc-64: inttoptr i64 %0 to ptr // CHECK-native-64: inttoptr i64 %0 to ptr // CHECK-64: inttoptr i64 %1 to ptr // CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_protocol_switch(i32 %0, i32 %1) {{.*}} { // 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 ptr // CHECK-native-32: inttoptr i32 %0 to ptr // CHECK-32: inttoptr i32 %1 to ptr sil @single_payload_class_protocol_switch : $(SinglePayloadClassProtocol) -> () { entry(%c : $SinglePayloadClassProtocol): switch_enum %c : $SinglePayloadClassProtocol, case #SinglePayloadClassProtocol.x!enumelt: 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 : $() } enum DynamicSinglePayload { case x(T) case y case z case w } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_switch(ptr noalias %0, ptr %T) {{.*}} { // CHECK: [[TMP2:%.*]] = getelementptr inbounds ptr, ptr %T, i{{.*}} -1 // CHECK: [[VWT:%.*]] = load ptr, ptr [[TMP2]] // CHECK: [[ENUMADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 6 // CHECK: [[WITNESS:%.*]] = load ptr, ptr [[ENUMADDR]] // CHECK: [[CASE_INDEX:%.*]] = call i32 [[WITNESS]](ptr noalias %0, i32 3, ptr %T) // CHECK: switch i32 [[CASE_INDEX]], label {{%.*}} [ // CHECK: i32 0, label {{%.*}} // CHECK: i32 3, label {{%.*}} // CHECK: ] sil @dynamic_single_payload_switch : $ (@in DynamicSinglePayload) -> () { entry(%u : $*DynamicSinglePayload): switch_enum_addr %u : $*DynamicSinglePayload, case #DynamicSinglePayload.x!enumelt: 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{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_inject_x(ptr noalias sret({{.*}}) %0, ptr noalias %1, ptr %T) {{.*}} { // CHECK: [[TMP2:%.*]] = getelementptr inbounds ptr, ptr %T, i{{.*}} -1 // CHECK: [[VWT:%.*]] = load ptr, ptr [[TMP2]] // CHECK: [[ENUMADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 7 // CHECK: [[WITNESS:%.*]] = load ptr, ptr [[ENUMADDR]] // CHECK: call void [[WITNESS]](ptr noalias %0, i32 0, i32 3, ptr %T) sil @dynamic_single_payload_inject_x : $ (@in T) -> @out DynamicSinglePayload { entry(%r : $*DynamicSinglePayload, %t : $*T): inject_enum_addr %r : $*DynamicSinglePayload, #DynamicSinglePayload.x!enumelt %v = tuple () return %v : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_inject_y(ptr noalias sret({{.*}}) %0, ptr %T) {{.*}} { // CHECK: [[TMP2:%.*]] = getelementptr inbounds ptr, ptr %T, i{{.*}} -1 // CHECK: [[VWT:%.*]] = load ptr, ptr [[TMP2]] // CHECK: [[ENUMADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 7 // CHECK: [[WITNESS:%.*]] = load ptr, ptr [[ENUMADDR]] // CHECK: call void [[WITNESS]](ptr noalias %0, i32 1, i32 3, ptr %T) sil @dynamic_single_payload_inject_y : $ () -> @out DynamicSinglePayload { entry(%r : $*DynamicSinglePayload): inject_enum_addr %r : $*DynamicSinglePayload, #DynamicSinglePayload.y!enumelt %v = tuple () return %v : $() } // -- Ensure instantiations of single-payload types with empty payloads work. // Bug discovered by Greg Parker. // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_empty_payload_switch(i8 %0) {{.*}} { // 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: 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{{( dllexport)?}}{{( protected)?}} swiftcc i8 @dynamic_single_payload_empty_payload_load(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK: entry: // CHECK: %1 = load i8, ptr %0 // CHECK: ret i8 %1 // CHECK: } sil @dynamic_single_payload_empty_payload_load : $(@inout DynamicSinglePayload<()>) -> DynamicSinglePayload<()> { entry(%p : $*DynamicSinglePayload<()>): %x = load %p : $*DynamicSinglePayload<()> return %x : $DynamicSinglePayload<()> } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_empty_payload_store(ptr captures(none) dereferenceable({{.*}}) %0, i8 %1) {{.*}} { // CHECK: entry: // CHECK: store i8 %1, ptr %0 // 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{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc 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<()> } // // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_generic_destroy // CHECK: br i1 // CHECK: {{[0-9]+}}: // CHECK: call void // CHECK: {{[0-9]+}}: sil @dynamic_single_payload_generic_destroy : $@convention(thin) (@in DynamicSinglePayload) -> () { entry(%x : $*DynamicSinglePayload): destroy_addr %x : $*DynamicSinglePayload %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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bits_switch(i64 %0, i8 %1) {{.*}} { 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: [[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: [[UNREACHABLE]]: // CHECK-64: unreachable switch_enum %u : $MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt: x_dest, case #MultiPayloadNoSpareBits.y!enumelt: y_dest, case #MultiPayloadNoSpareBits.z!enumelt: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest // CHECK-64: [[X_PREDEST]]: // CHECK-64: br label %[[X_DEST:[0-9]+]] // CHECK-64: [[Y_PREDEST]]: // CHECK-64: [[Y_VALUE:%.*]] = trunc i64 %0 to i32 // CHECK-64: br label %[[Y_DEST:[0-9]+]] // CHECK-64: [[Z_PREDEST]]: // CHECK-64: [[Z_VALUE:%.*]] = trunc i64 %0 to i63 // CHECK-64: br label %[[Z_DEST:[0-9]+]] // CHECK-64: [[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: [[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: [[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: [[A_DEST]]: a_dest: %d = function_ref @d : $@convention(thin) () -> () apply %d() : $@convention(thin) () -> () br end // CHECK-64: [[B_DEST]]: b_dest: %e = function_ref @e : $@convention(thin) () -> () apply %e() : $@convention(thin) () -> () br end // CHECK-64: [[C_DEST]]: c_dest: %f = function_ref @f : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> () br end end: %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bits_switch_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { sil @multi_payload_no_spare_bits_switch_indirect : $(@inout MultiPayloadNoSpareBits) -> () { entry(%u : $*MultiPayloadNoSpareBits): // CHECK-64: [[PAYLOAD:%.*]] = load i64, ptr %0 // CHECK-64: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum23MultiPayloadNoSpareBitsO, ptr %0, i32 0, i32 1 // CHECK-64: [[TAG:%.*]] = load i8, ptr [[T0]] // CHECK-64: switch i8 [[TAG]] // CHECK-64: switch i64 [[PAYLOAD]] // CHECK-64: {{[0-9]+}}: // CHECK-64: unreachable switch_enum_addr %u : $*MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt: x_dest, case #MultiPayloadNoSpareBits.y!enumelt: y_dest, case #MultiPayloadNoSpareBits.z!enumelt: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest // CHECK-64: [[X_DEST:[0-9]+]]: // CHECK-64: [[Y_DEST:[0-9]+]]: // CHECK-64: [[Z_DEST:[0-9]+]]: x_dest: %x = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt br end y_dest: %y = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.y!enumelt br end z_dest: %z = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.z!enumelt br end a_dest: br end b_dest: br end c_dest: br end end: %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_x(i64 %0) {{.*}} { // 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, %0 : $Builtin.Int64 return %u : $MultiPayloadNoSpareBits } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_x_indirect(i64 %0, ptr captures(none) dereferenceable({{.*}}) %1) {{.*}} { // CHECK-64: entry: // CHECK-64: store i64 %0, ptr %1 // CHECK-64: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum23MultiPayloadNoSpareBitsO, ptr %1, i32 0, i32 1 // CHECK-64: store i8 0, ptr [[T0]] // 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 store %0 to %a : $*Builtin.Int64 inject_enum_addr %1 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_y(i32 %0) {{.*}} { // 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, %0 : $Builtin.Int32 return %u : $MultiPayloadNoSpareBits } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_z(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[ZEXT:%.*]] = zext i63 [[NATIVECC_TRUNC]] 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, %0 : $Builtin.Int63 return %u : $MultiPayloadNoSpareBits } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { 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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_a_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK-64: entry: // CHECK-64: store i64 0, ptr %0 // CHECK-64: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum23MultiPayloadNoSpareBitsO, ptr %0, i32 0, i32 1 // CHECK-64: store i8 3, ptr [[T0]] // 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{{( dllexport)?}}{{( protected)?}} swiftcc { 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{{( dllexport)?}}{{( protected)?}} swiftcc { 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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_switch(i64 %0, i8 %1) {{.*}} { 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:%.*]] = shl i8 %1, 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: [[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: [[UNREACHABLE]]: // CHECK-64: unreachable switch_enum %u : $MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt: x_dest, case #MultiPayloadOneSpareBit.y!enumelt: y_dest, case #MultiPayloadOneSpareBit.z!enumelt: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest // CHECK-64: [[X_PREDEST]]: // CHECK-64: [[X_VALUE:%.*]] = trunc i64 %0 to i62 // CHECK-64: br label %[[X_DEST:[0-9]+]] // CHECK-64: [[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: [[Z_PREDEST]]: // CHECK-64: [[Z_VALUE:%.*]] = trunc i64 %0 to i61 // CHECK-64: br label %[[Z_DEST:[0-9]+]] // CHECK-64: [[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: [[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: [[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: [[A_DEST]]: a_dest: %d = function_ref @d : $@convention(thin) () -> () apply %d() : $@convention(thin) () -> () br end // CHECK-64: [[B_DEST]]: b_dest: %e = function_ref @e : $@convention(thin) () -> () apply %e() : $@convention(thin) () -> () br end // CHECK-64: [[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:%.*]] = load i64, ptr %0 // CHECK-64: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum23MultiPayloadOneSpareBitO, ptr %0, i32 0, i32 1 // CHECK-64: [[TAG:%.*]] = load i8, ptr [[T0]] // CHECK-64: switch i8 {{%.*}} // CHECK-64: switch i64 [[PAYLOAD]] // CHECK-64: {{[0-9]+}}: // CHECK-64: unreachable switch_enum_addr %u : $*MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt: x_dest, case #MultiPayloadOneSpareBit.y!enumelt: y_dest, case #MultiPayloadOneSpareBit.z!enumelt: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest // CHECK-64: [[X_PREDEST:[0-9]+]]: // CHECK-64: [[Y_PREDEST:[0-9]+]]: // CHECK-64: [[PAYLOAD:%.*]] = load i64, ptr %0 // -- 0x7FFF_FFFF_FFFF_FFFF // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807 // CHECK-64: store i64 [[PAYLOAD_MASKED]], ptr %0 // CHECK-64: [[Z_PREDEST:[0-9]+]]: x_dest: %x = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt br end y_dest: %y = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt br end z_dest: %z = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt br end a_dest: br end b_dest: br end c_dest: br end end: %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_x(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[ZEXT:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[ZEXT]], 0 // CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 0, 1 // CHECK-64: ret { i64, i8 } [[RES]] // CHECK-64: } sil @multi_payload_one_spare_bit_inject_x : $(Builtin.Int62) -> MultiPayloadOneSpareBit { entry(%0 : $Builtin.Int62): %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt, %0 : $Builtin.Int62 return %u : $MultiPayloadOneSpareBit } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_x_indirect(i64 %0, ptr captures(none) dereferenceable({{.*}}) %1) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 // CHECK-64: store i64 [[BYTE]], ptr %1 // CHECK-64: [[PAYLOAD:%.*]] = load i64, ptr %1 // -- 0x7FFF_FFFF_FFFF_FFFF // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807 // CHECK-64: store i64 [[PAYLOAD_MASKED]], ptr %1 // CHECK-64: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum23MultiPayloadOneSpareBitO, ptr %1, i32 0, i32 1 // CHECK-64: store i8 0, ptr [[T0]] // 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 store %0 to %a : $*Builtin.Int62 inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_y(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[ZEXT:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64 // -- 0x8000_0000_0000_0000 // CHECK-64: [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808 // CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[TAGGED]], 0 // CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 0, 1 // CHECK-64: ret { i64, i8 } [[RES]] // CHECK-64: } sil @multi_payload_one_spare_bit_inject_y : $(Builtin.Int63) -> MultiPayloadOneSpareBit { entry(%0 : $Builtin.Int63): %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt, %0 : $Builtin.Int63 return %u : $MultiPayloadOneSpareBit } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_y_indirect(i64 %0, ptr captures(none) dereferenceable({{.*}}) %1) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63 // CHECK-64: [[BYTE:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64 // CHECK-64: store i64 [[BYTE]], ptr %1 // CHECK-64: [[PAYLOAD:%.*]] = load i64, ptr %1 // -- 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: store i64 [[PAYLOAD_TAGGED]], ptr %1 // CHECK-64: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum23MultiPayloadOneSpareBitO, ptr %1, i32 0, i32 1 // CHECK-64: store i8 0, ptr [[T0]] // 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 store %0 to %a : $*Builtin.Int63 inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_z(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i61 // CHECK-64: [[ZEXT:%.*]] = zext i61 [[NATIVECC_TRUNC]] 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_one_spare_bit_inject_z : $(Builtin.Int61) -> MultiPayloadOneSpareBit { entry(%0 : $Builtin.Int61): %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt, %0 : $Builtin.Int61 return %u : $MultiPayloadOneSpareBit } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_a() {{.*}} { // CHECK-64: entry: // -- 0x8000_0000_0000_0000 // CHECK-64: ret { i64, i8 } { i64 -9223372036854775808, i8 1 } // CHECK-64: } sil @multi_payload_one_spare_bit_inject_a : $() -> MultiPayloadOneSpareBit { entry: %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt return %u : $MultiPayloadOneSpareBit } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_a_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK-64: entry: // -- 0x8000_0000_0000_0000 // CHECK-64: store i64 -9223372036854775808, ptr %0 // CHECK-64: [[T0:%.*]] = getelementptr inbounds{{.*}} %T4enum23MultiPayloadOneSpareBitO, ptr %0, i32 0, i32 1 // CHECK-64: store i8 1, ptr [[T0]] // 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{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_b() {{.*}} { // CHECK-64: entry: // -- 0x8000_0000_0000_0001 // CHECK-64: ret { i64, i8 } { i64 -9223372036854775807, i8 1 } // CHECK-64: } sil @multi_payload_one_spare_bit_inject_b : $() -> MultiPayloadOneSpareBit { entry: %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.b!enumelt return %u : $MultiPayloadOneSpareBit } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_c() {{.*}} { // CHECK-64: entry: // -- 0x8000_0000_0000_0002 // CHECK-64: ret { i64, i8 } { i64 -9223372036854775806, i8 1 } // 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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_switch(i64 %0) {{.*}} { 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: [[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: [[UNREACHABLE]]: // CHECK-64: unreachable switch_enum %u : $MultiPayloadTwoSpareBits, case #MultiPayloadTwoSpareBits.x!enumelt: x_dest, case #MultiPayloadTwoSpareBits.y!enumelt: y_dest, case #MultiPayloadTwoSpareBits.z!enumelt: z_dest, case #MultiPayloadTwoSpareBits.a!enumelt: a_dest, case #MultiPayloadTwoSpareBits.b!enumelt: b_dest, case #MultiPayloadTwoSpareBits.c!enumelt: c_dest // CHECK-64: [[X_PREDEST]]: // CHECK-64: [[X_VALUE:%.*]] = trunc i64 %0 to i62 // CHECK-64: br label %[[X_DEST:[0-9]+]] // CHECK-64: [[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: [[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: [[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: [[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: [[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: [[A_DEST]]: a_dest: %d = function_ref @d : $@convention(thin) () -> () apply %d() : $@convention(thin) () -> () br end // CHECK-64: [[B_DEST]]: b_dest: %e = function_ref @e : $@convention(thin) () -> () apply %e() : $@convention(thin) () -> () br end // CHECK-64: [[C_DEST]]: c_dest: %f = function_ref @f : $@convention(thin) () -> () apply %f() : $@convention(thin) () -> () br end end: %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_x(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[ZEXT:%.*]] = zext i62 [[NATIVECC_TRUNC]] 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, %0 : $Builtin.Int62 return %u : $MultiPayloadTwoSpareBits } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_x_indirect(i64 %0, ptr captures(none) dereferenceable({{.*}}) %1) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62 // CHECK-64: [[BYTE:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64 // CHECK-64: store i64 [[BYTE]], ptr %1 // CHECK-64: [[PAYLOAD:%.*]] = load i64, ptr %1 // -- 0x3FFF_FFFF_FFFF_FFFF // CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903 // CHECK-64: store i64 [[PAYLOAD_MASKED]], ptr %1 // 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 store %0 to %a : $*Builtin.Int62 inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_y(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60 // CHECK-64: [[ZEXT:%.*]] = zext i60 [[NATIVECC_TRUNC]] 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, %0 : $Builtin.Int60 return %u : $MultiPayloadTwoSpareBits } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_y_indirect(i64 %0, ptr captures(none) dereferenceable({{.*}}) %1) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60 // CHECK-64: [[BYTE:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64 // CHECK-64: store i64 [[BYTE]], ptr %1 // CHECK-64: [[PAYLOAD:%.*]] = load i64, ptr %1 // -- 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: store i64 [[PAYLOAD_TAGGED]], ptr %1 // 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 store %0 to %a : $*Builtin.Int60 inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt %v = tuple () return %v : $() } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_z(i64 %0) {{.*}} { // CHECK-64: entry: // CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i61 // CHECK-64: [[ZEXT:%.*]] = zext i61 [[NATIVECC_TRUNC]] 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, %0 : $Builtin.Int61 return %u : $MultiPayloadTwoSpareBits } // CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_a_indirect(ptr captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK-64: entry: // -- 0xC000_0000_0000_0000 // CHECK-64: store i64 -4611686018427387904, ptr %0 // 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{{( dllexport)?}}{{( protected)?}} swiftcc 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{{( dllexport)?}}{{( protected)?}} swiftcc 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 @$s4enum1DCfD : $@convention(method) (D) -> () enum MultiPayloadClasses { case x(C) case y(D) case z case w } // CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_classes_switch(i64 %0) {{.*}} { // 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 ptr // -- Extract y(D) // -- 0x3fffffffffffffff // CHECK-64: [[MASKED:%.*]] = and i64 %0, 4611686018427387903 // CHECK-64: inttoptr i64 [[MASKED]] to ptr // CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_classes_switch(i32 %0) {{.*}} { // 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 ptr // -- Extract y(D) // CHECK-32: [[MASKED:%.*]] = and i32 %0, -4 // CHECK-32: inttoptr i32 [[MASKED]] to ptr sil @multi_payload_classes_switch : $(MultiPayloadClasses) -> () { entry(%c : $MultiPayloadClasses): switch_enum %c : $MultiPayloadClasses, case #MultiPayloadClasses.x!enumelt: x_dest, case #MultiPayloadClasses.y!enumelt: 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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_spare_bit_aggregate_switch(i64 %0, i64 %1) {{.*}} { // 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: [[X_DEST]]: // CHECK-64: [[X_0:%.*]] = trunc i64 %0 to i32 // CHECK-64: [[Y_DEST]]: // -- 0x3fffffffffffffff // CHECK-64: [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903 // CHECK-64: [[Y_0:%.*]] = inttoptr i64 [[Y_MASKED]] to ptr // CHECK-64: [[Y_1:%.*]] = inttoptr i64 %1 to ptr // CHECK-64: [[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: x_dest, case #MultiPayloadSpareBitAggregates.y!enumelt: y_dest, case #MultiPayloadSpareBitAggregates.z!enumelt: 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 : $() } // enum MultiPayloadInner { case A(Builtin.Word) case B(Builtin.Word) } enum MultiPayloadNested { case A(MultiPayloadInner) case B(MultiPayloadInner) } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_nested_switch // CHECK: %1 = getelementptr // CHECK: %2 = load [[WORD]], ptr %1 // CHECK: %3 = getelementptr // CHECK: %4 = load i8, ptr %3 // CHECK: %5 = lshr i8 %4, 7 // CHECK: %6 = and i8 %5, 1 // CHECK: %7 = icmp ne i8 %6, 1 // CHECK: br i1 %7 sil @multi_payload_nested_switch : $(@in MultiPayloadNested) -> () { entry(%c : $*MultiPayloadNested): switch_enum_addr %c : $*MultiPayloadNested, case #MultiPayloadNested.A!enumelt: a_dest, case #MultiPayloadNested.B!enumelt: 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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_nested_spare_bits_switch(ptr noalias captures(none) dereferenceable({{.*}}) %0) {{.*}} { // CHECK-64: entry: // CHECK-64: %1 = load [[WORD]], ptr %0 // CHECK-64: %2 = lshr [[WORD]] %1, 61 // CHECK-64: %3 = trunc [[WORD]] %2 to i8 // CHECK-64: %4 = and i8 %3, 1 // CHECK-64: %5 = icmp ne i8 %4, 1 // CHECK-64: br i1 %5 sil @multi_payload_nested_spare_bits_switch : $(@in MultiPayloadNestedSpareBits) -> () { entry(%c : $*MultiPayloadNestedSpareBits): switch_enum_addr %c : $*MultiPayloadNestedSpareBits, case #MultiPayloadNestedSpareBits.A!enumelt: a_dest, case #MultiPayloadNestedSpareBits.B!enumelt: 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: x_dest, case #OnlyPayloads.y!enumelt: y_dest, case #OnlyPayloads.z!enumelt: 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 { case A(C, Builtin.Word) case B(T) } // CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i64, i8 } @multi_payload_class_generic_no_spare_bits(i64 %0, i64 %1, i8 %2, ptr %T) // CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i32, i32, i8 } @multi_payload_class_generic_no_spare_bits(i32 %0, i32 %1, i8 %2, ptr %T) sil @multi_payload_class_generic_no_spare_bits : $@convention(thin) (@owned MultiPayloadClassGeneric) -> MultiPayloadClassGeneric { entry(%e : $MultiPayloadClassGeneric): return %e : $MultiPayloadClassGeneric } // CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i64, i8 } @multi_payload_class_instance_no_spare_bits(i64 %0, i64 %1, i8 %2) // CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i32, i32, i8 } @multi_payload_class_instance_no_spare_bits(i32 %0, i32 %1, i8 %2) sil @multi_payload_class_instance_no_spare_bits : $@convention(thin) (@owned MultiPayloadClassGeneric) -> MultiPayloadClassGeneric { entry(%e : $MultiPayloadClassGeneric): return %e : $MultiPayloadClassGeneric } enum MultiPayloadAddressOnlyFixed { case X(Any) case Y(Builtin.Int32) } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_address_only_destroy(ptr noalias captures(none) dereferenceable({{.*}}) %0) 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{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_address_only_spare_bits(ptr noalias dereferenceable({{.*}}) %0) 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{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_singleton_switch_indirect(ptr noalias %0, ptr %T) {{.*}} { // CHECK: ret void // CHECK: } sil @dynamic_singleton_switch_indirect : $ (@in DynamicSingleton) -> () { entry(%0 : $*DynamicSingleton): switch_enum_addr %0 : $*DynamicSingleton, case #DynamicSingleton.value!enumelt: dest dest: %1 = unchecked_take_enum_data_addr %0 : $*DynamicSingleton, #DynamicSingleton.value!enumelt %v = tuple () return %v : $() } // Verify that we can instantiate generic enum instances of dynamic size. sil_global @aa : $DynamicSingleton<()> sil_global @bb : $DynamicSingleton // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_singleton_instance_arg_1() sil @dynamic_singleton_instance_arg_1 : $(DynamicSingleton<()>) -> () { entry(%0 : $DynamicSingleton<()>): %v = tuple () return %v : $() } // CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_singleton_instance_arg_2(i8 %0) sil @dynamic_singleton_instance_arg_2 : $(DynamicSingleton) -> () { entry(%0 : $DynamicSingleton): %v = tuple () return %v : $() } // Check that payloads get properly masked in nested single-payload enums. // rdar://problem/18841262 // CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @optional_optional_class_protocol(i64 %0, i64 %1) // CHECK-objc-64-simulator-false: icmp eq i64 %0, 2 // CHECK-objc-64-simulator-true: icmp eq i64 %0, 1 // CHECK-native-64: icmp eq i64 %0, 1 // CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @optional_optional_class_protocol(i32 %0, i32 %1) // CHECK-32: icmp eq i32 %0, 1 enum Optionable { case some(T), none } sil @optional_optional_class_protocol : $@convention(thin) (Optionable>) -> Builtin.Int1 { entry(%o : $Optionable>): %t = integer_literal $Builtin.Int1, 1 %f = integer_literal $Builtin.Int1, 0 %r = select_enum %o : $Optionable>, case #Optionable.some!enumelt: %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: ret { [[WORD]], [[WORD]], i8 } { [[WORD]] 0, [[WORD]] 0, i8 1 } // CHECK-native: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 } sil @optional_unowned : $@convention(thin) () -> (Optionable, Optionable>) { entry: %a = enum $Optionable, #Optionable.none!enumelt %b = enum $Optionable>, #Optionable.none!enumelt %t = tuple (%a : $Optionable, %b : $Optionable>) return %t : $(Optionable, Optionable>) } // CHECK-LABEL: define {{.*}} @optional_unowned_objc() {{.*}} { // CHECK-objc: ret { [[WORD]], [[WORD]], i8 } { [[WORD]] 0, [[WORD]] 0, i8 1 } // CHECK-native: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 } sil @optional_unowned_objc : $@convention(thin) () -> (Optionable, Optionable>) { entry: %a = enum $Optionable, #Optionable.none!enumelt %b = enum $Optionable>, #Optionable.none!enumelt %t = tuple (%a : $Optionable, %b : $Optionable>) return %t : $(Optionable, Optionable>) } // CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @empty_payload_enum_in_enum(i32 %0) sil @empty_payload_enum_in_enum : $@convention(thin) (Int32) -> Optional<(Optional<()>, Int32)> { entry(%x : $Int32): %a = tuple () %b = enum $Optional<()>, #Optional.some!enumelt, %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 %d = enum $Optional<(Optional<()>, Int32)>, #Optional.some!enumelt, %c : $(Optional<()>, Int32) // CHECK-64: [[BIT:%.*]] = trunc i64 [[INT_SHL]] to i8 // CHECK-64: [[INT_SHR:%.*]] = lshr i64 [[INT_SHL]], 32 // CHECK-64: [[INT:%.*]] = trunc i64 [[INT_SHR]] to i32 %e = unchecked_enum_data %d : $Optional<(Optional<()>, Int32)>, #Optional.some!enumelt return %d : $Optional<(Optional<()>, Int32)> } sil @optional_float80 : $@convention(thin) (Float80) -> () { entry(%x : $Float80): %y = enum $Optional, #Optional.some!enumelt, %x : $Float80 return undef : $() } // rdar://problem/21126703 protocol delegateProtocol : AnyObject { } struct StructWithWeakVar { weak var delegate: delegateProtocol? } // CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @weak_optional(ptr noalias dereferenceable({{.*}}) %0) 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: 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 : $() } public struct AnyError : Swift.Error { } public enum Result { case success(T) case failure(Error) } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_inject_enum_addr_with_bound_generic sil @test_inject_enum_addr_with_bound_generic : $@convention(thin) () -> @out Result { bb0(%0 : $*Result): // CHECK: call {{.*}} @"$s4enum6ResultOMa" // CHECK: call void @swift_storeEnumTagMultiPayload inject_enum_addr %0 : $*Result, #Result.success!enumelt %r = tuple () // CHECK: ret void return %r : $() } // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc 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 %r = load %b : $*DynamicSingleton %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{{( dllexport)?}}{{( protected)?}} swiftcc 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 : $() } struct LargeStruct { var x: Builtin.Int64 var x2: Builtin.Int64 var x3: Builtin.Int64 var x4: Builtin.Int64 var x5: Builtin.Int64 var x6: Builtin.NativeObject } enum MyOptional { case None case Some(LargeStruct) } // Make sure we use a memcpy for the none branch of the enum copy. // CHECK-LABEL: define{{.*}} @test_large_optional // CHECK: llvm.memcpy // CHECK: ret void sil @test_large_optional : $@convention(thin) (@in MyOptional) -> () { entry(%x : $*MyOptional): %stk = alloc_stack $MyOptional copy_addr %x to [init] %stk : $*MyOptional dealloc_stack %stk: $*MyOptional %tuple = tuple () return %tuple : $() } // -- Fill function for dynamic singleton. // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal ptr @"$s4enum16DynamicSingletonOMi"(ptr %0, ptr %1, ptr %2) {{.*}} { // CHECK: [[T:%T]] = load ptr, ptr %1, // CHECK: [[METADATA:%.*]] = call ptr @swift_allocateGenericValueMetadata(ptr %0, ptr %1, ptr %2, [[WORD]] {{4|8}}) // CHECK-NEXT: ret ptr [[METADATA]] // CHECK-LABEL: define{{( protected)?}} internal swiftcc %swift.metadata_response @"$s4enum16DynamicSingletonOMr" // CHECK-SAME: (ptr [[METADATA:%.*]], ptr %0, ptr %1) {{.*}} { // CHECK: [[T0:%.*]] = call{{( tail)?}} swiftcc %swift.metadata_response @swift_checkMetadataState([[WORD]] 319, ptr [[T]]) // CHECK: [[T_CHECKED:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 // CHECK: [[T_STATUS:%.*]] = extractvalue %swift.metadata_response [[T0]], 1 // CHECK: [[T_OK:%.*]] = icmp ule [[WORD]] [[T_STATUS]], 63 // CHECK: br i1 [[T_OK]], // CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[T_CHECKED]], [[WORD]] -1 // CHECK: [[T_VWT:%.*]] = load ptr, ptr [[T_VWT_ADDR]] // CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds ptr, ptr [[T_VWT]], i32 8 // CHECK: call void @swift_initEnumMetadataSingleCase(ptr [[METADATA]], [[WORD]] 0, ptr [[T_LAYOUT]]) // CHECK: [[PAYLOAD_EXTRAINHABITANTCNT:%.*]] = getelementptr inbounds{{.*}} %swift.type_layout, ptr [[T_LAYOUT]], i32 0, i32 3 // CHECK: [[CNT:%.*]] = load i32, ptr [[PAYLOAD_EXTRAINHABITANTCNT]] // CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[METADATA]], [[WORD]] -1 // CHECK: [[VWT:%.*]] = load ptr, ptr [[VWT_ADDR]] // CHECK: [[XIC_ADDR:%.*]] = getelementptr inbounds{{.*}} %swift.vwtable, ptr [[VWT]], i32 0, i32 11 // CHECK: store i32 [[CNT]], ptr [[XIC_ADDR]] // CHECK: ret %swift.metadata_response // -- Fill function for dynamic single-payload. Call into the runtime to // calculate the size. // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal ptr @"$s4enum20DynamicSinglePayloadOMi" // CHECK: [[METADATA:%.*]] = call ptr @swift_allocateGenericValueMetadata // CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal swiftcc %swift.metadata_response @"$s4enum20DynamicSinglePayloadOMr" // CHECK-SAME: (ptr [[METADATA:%.*]], ptr %0, ptr %1) {{.*}} { // CHECK: [[T0:%.*]] = call{{( tail)?}} swiftcc %swift.metadata_response @swift_checkMetadataState([[WORD]] 319, ptr [[T]]) // CHECK: [[T_CHECKED:%.*]] = extractvalue %swift.metadata_response [[T0]], 0 // CHECK: [[T_STATUS:%.*]] = extractvalue %swift.metadata_response [[T0]], 1 // CHECK: [[T_OK:%.*]] = icmp ule [[WORD]] [[T_STATUS]], 63 // CHECK: br i1 [[T_OK]], // CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[T_CHECKED]], [[WORD]] -1 // CHECK: [[T_VWT:%.*]] = load ptr, ptr [[T_VWT_ADDR]] // CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds ptr, ptr [[T_VWT]], i32 8 // CHECK: call void @swift_initEnumMetadataSinglePayload(ptr [[METADATA]], [[WORD]] 0, ptr [[T_LAYOUT]], i32 3) // CHECK-64-LABEL: define internal void @"$s4enum17StructWithWeakVarVwst"(ptr noalias %value, i32 %whichCase, i32 %numEmptyCases, ptr %StructWithWeakVar) // -- TODO: some pointless masking here. // -- TODO: should use EnumPayload word-chunking. // CHECK-64: [[INDEX:%.*]] = sub i32 %whichCase, 1 // CHECK-64: [[T0:%.*]] = zext i32 [[INDEX]] to i128 // -- 0xFFFF_FFFF_FFFF_FFFF // CHECK-64: [[T1:%.*]] = and i128 [[T0]], 18446744073709551615 // CHECK-64: [[T2:%.*]] = shl i128 [[T0]], 3 // -- 0xFFFF_FFFF_FFFF_FFF8__0000_0000_0000_0000 // CHECK-64: [[T3:%.*]] = and i128 [[T2]], 1329227995784915725329854470603931648 // CHECK-64: [[T4:%.*]] = or i128 [[T1]], [[T3]] // -- 0x1__0000_0000_0000_0000 // CHECK-64: [[T5:%.*]] = or i128 [[T4]], 18446744073709551616 // CHECK-LABEL: define internal i32 @"$s4enum40MultiPayloadLessThan32BitsWithEmptyCasesOwug"(ptr noalias %value // CHECK: [[VAL02:%.*]] = load {{.*}} %value // CHECK: [[VAL03:%.*]] = getelementptr inbounds {{.*}} %value, i32 0, i32 1 // CHECK: [[VAL05:%.*]] = load {{.*}} [[VAL03]] // CHECK: [[VAL06:%.*]] = zext i8 [[VAL05]] to i32 // CHECK: [[VAL07:%.*]] = zext i8 [[VAL02]] to i32 // CHECK: [[VAL08:%.*]] = and i32 [[VAL07]], 255 // CHECK: [[VAL09:%.*]] = add i32 [[VAL08]], 2 // CHECK: [[VAL10:%.*]] = icmp uge i32 [[VAL06]], 2 // CHECK: [[VAL11:%.*]] = select i1 [[VAL10]], i32 [[VAL09]], i32 [[VAL06]] // CHECK: ret i32 [[VAL11]] // CHECK-LABEL: define internal void @"$s4enum40MultiPayloadLessThan32BitsWithEmptyCasesOwui"(ptr noalias %value, i32 %tag // CHECK: entry: // CHECK: [[VAL01:%.*]] = icmp uge i32 %tag, 2 // CHECK: br i1 [[VAL01]], label %[[TLABEL:.*]], label %[[FLABEL:.*]] // CHECK: [[TLABEL]]: // CHECK: [[VAL02:%.*]] = sub i32 %tag, 2 // CHECK: [[VAL03:%.*]] = trunc i32 [[VAL02]] to i8 // CHECK: store i8 [[VAL03]], ptr %value // CHECK: [[VAL05:%.*]] = getelementptr inbounds {{.*}} %value, i32 0, i32 1 // CHECK: store i8 2, ptr [[VAL05]] // CHECK: br label %[[RLABEL:.*]] // CHECK: [[FLABEL]]: // CHECK: [[VAL09:%.*]] = trunc i32 %tag to i8 // CHECK: [[VAL10:%.*]] = getelementptr inbounds {{.*}} %value, i32 0, i32 1 // CHECK: store i8 [[VAL09]], ptr [[VAL10]] // CHECK: br label %[[RLABEL]] // CHECK: [[RLABEL]]: // CHECK: ret void enum MultiPayloadLessThan32BitsWithEmptyCases { case A case B case C(Builtin.Int8) case D(Builtin.Int8) }