Files
swift-mirror/test/IRGen/enum.sil
John McCall 857489c2f6 When a generic type has dependent IR and thus requires each
specialization to be separately lowered in IRGen, use the mangling
of the specialized type as the name of the llvm::StructType instead
of the base, unspecialized type.

This tends to produce fewer collisions between IR type names.
LLVM does unique the names on its own, so that's not strictly
necessary, but it's still a good idea because it makes the test
output more reliable and somewhat easier to read (modulo the
impact of bigger type names).  Collisions will still occur if
the type is specialized at an archetype, since in this case we
will fall back on the unspecialized type.
2016-04-29 16:39:16 -07:00

2631 lines
100 KiB
Plaintext

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