Files
swift-mirror/test/IRGen/enum.sil
John McCall c57dac63ae Use the first element of structs and tuples as a source
for extra inhabitants.

For structs in particular, this eliminates a major source
of abstraction penatlies.  For example, an optional struct
containing an object pointer is now represented the same
way as an optional object pointer, which is critical for
correctly importing CF types as Unmanaged<T>!.

In time, we should generalize this to consider all elements
as sources for extra inhabitants, as well as exploiting
spare bits in the representation, but getting the
single-element case right really provides the bulk of the
benefit.

This commit restores r17242 and r17243 with a fix to use
value witnesses that actually forward the right type metadata
down.  We were already generating these value witnesses in
the dependent struct VWT pattern, but I was being too clever
and trying to use the underlying value witness directly.

Swift SVN r17267
2014-05-02 20:17:14 +00:00

2357 lines
82 KiB
Plaintext

// RUN: %swift -target x86_64-apple-darwin10 %s -emit-ir -enable-dynamic-value-type-layout | FileCheck %s
sil_stage canonical
import Builtin
// -- 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: %O4enum17SinglePayloadNoXI = type <{ [8 x i8], [1 x i8] }>
// CHECK: %O4enum18SinglePayloadNoXI2 = type <{ [8 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: %O4enum15StringOwnerLike = type <{ [8 x i8] }>
// CHECK: %O4enum30MultiPayloadSpareBitAggregates = type <{ [16 x i8] }>
// CHECK: %O4enum18MultiPayloadNested = type <{ [9 x i8] }>
// CHECK: %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:%O4enum20DynamicSinglePayload\.[0-9]+]] = type <{ [1 x i8] }>
// CHECK: %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.
// CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private unnamed_addr constant [25 x i8] c"O4enum16DynamicSingleton\00"
// CHECK: @_TMnO4enum16DynamicSingleton = constant { {{.*}} i32 } {
// -- 2 = enum
// CHECK: i64 2,
// CHECK: i8* getelementptr inbounds ([25 x i8]* [[DYNAMICSINGLETON_NAME]], i64 0, i64 0),
// -- FIXME
// CHECK: i32 0, i32 0, i64 0,
// -- generic parameter vector offset
// CHECK: i32 3,
// -- generic parameter vector length; witness table counts
// CHECK: i32 1, i32 0
// CHECK: }
// CHECK: @_TMPdO4enum16DynamicSingleton = global { {{.*}}* } {
// CHECK: void (i8*, i8*)* [[DYNAMIC_SINGLETON_FILL:@fill_generic_metadata[0-9]*]]
// CHECK: @_TMnO4enum16DynamicSingleton
// CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum16DynamicSingleton to i8*),
// CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum16DynamicSingleton to i8*),
// CHECK: i8* null
// -- No-payload enums have extra inhabitants in
// their value witness table.
// CHECK: @_TWVO4enum10NoPayloads = constant [23 x i8*] [
// -- ...
// -- size
// CHECK: i8* inttoptr (i64 1 to i8*),
// -- flags 0x4_0000 - alignment 1, has extra inhabitants
// CHECK: i8* inttoptr (i64 262144 to i8*),
// -- stride
// CHECK: i8* inttoptr (i64 1 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*),
// -- num extra inhabitants (256 - 3 valid states)
// CHECK: i8* inttoptr (i64 253 to i8*)
// CHECK: ]
// -- Single-payload enums take unused extra inhabitants from their payload
// as their own.
// CHECK: @_TWVO4enum19SinglePayloadNested = constant [23 x i8*] [
// -- ...
// -- size
// CHECK: i8* inttoptr (i64 1 to i8*),
// -- flags 0x4_0000 - alignment 1, has extra inhabitants
// CHECK: i8* inttoptr (i64 262144 to i8*),
// -- stride
// CHECK: i8* inttoptr (i64 1 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*),
// -- num extra inhabitants (253 from payload - 3 empty cases)
// CHECK: i8* inttoptr (i64 250 to i8*)
// CHECK: ]
// CHECK: @_TMPdO4enum20DynamicSinglePayload = global { {{.*}}* } {
// CHECK: void (i8*, i8*)* [[DYNAMIC_SINGLE_PAYLOAD_FILL:@fill_generic_metadata[0-9]*]]
// CHECK: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum20DynamicSinglePayload to i8*),
// CHECK: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum20DynamicSinglePayload to i8*),
// CHECK: i8* null
// CHECK: @_TWVO4enum18MultiPayloadNested = constant [20 x i8*] [
// CHECK: i8* inttoptr (i64 9 to i8*),
// CHECK: i8* inttoptr (i64 7 to i8*),
// CHECK: i8* inttoptr (i64 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 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 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 void @singleton_switch_indirect(%O4enum9Singleton* noalias) {
// 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 { 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 void @singleton_inject_indirect(i64, i64, %O4enum9Singleton* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum9Singleton* %2 to <{ i64, i64 }>*
// CHECK: [[DATA_0_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 0
// CHECK: store i64 %0, i64* [[DATA_0_ADDR]], align 8
// CHECK: [[DATA_1_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 1
// CHECK: store i64 %1, i64* [[DATA_1_ADDR]], align 8
// 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 : $@thin () -> ()
sil @b : $@thin () -> ()
sil @c : $@thin () -> ()
sil @d : $@thin () -> ()
sil @e : $@thin () -> ()
sil @f : $@thin () -> ()
// CHECK: define void @no_payload_switch(i2) {
sil @no_payload_switch : $@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 : $@thin () -> ()
apply %a() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Y_DEST]]
// CHECK: call void @b()
// CHECK: br label %[[END]]
y_dest:
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Z_DEST]]
// CHECK: call void @c()
// CHECK: br label %[[END]]
z_dest:
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
br end
// CHECK: ; <label>:[[END]]
// CHECK: ret void
end:
%x = tuple ()
return %x : $()
}
// CHECK: define void @no_payload_switch_indirect(%O4enum10NoPayloads* noalias) {
sil @no_payload_switch_indirect : $@thin (@inout NoPayloads) -> () {
entry(%u : $*NoPayloads):
// CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads* %0, i32 0, i32 0
// CHECK: [[TAG:%.*]] = load 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 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 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 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 void @no_payload_inject_z_indirect(%O4enum10NoPayloads* noalias) {
// CHECK: entry:
// CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads* %0, i32 0, i32 0
// CHECK: store i2 -2, i2* [[TAG_ADDR]], align 1
// 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 void @no_payload_switch_2(i3) {
sil @no_payload_switch_2 : $@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 : $@thin () -> ()
apply %a() : $@thin () -> ()
// CHECK: br label %[[END:[0-9]+]]
br end
// CHECK: ; <label>:[[DEFAULT_DEST]]
default_dest:
// CHECK: call void @b()
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
// CHECK: br label %[[END]]
br end
// CHECK: ; <label>:[[END]]
end:
// CHECK: ret void
%x = tuple ()
return %x : $()
}
enum SinglePayloadNoXI {
case x(Builtin.Int64)
case y
}
enum SinglePayloadNoXI2 {
case x(Builtin.Int64)
case y
case z
}
// CHECK: define void @single_payload_no_xi_switch(i64, i1) {
sil @single_payload_no_xi_switch : $@thin (SinglePayloadNoXI2) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadNoXI2):
// CHECK: switch i1 %1, label %[[DFLT:[0-9]+]] [
// CHECK: i1 false, label %[[X_DEST:[0-9]+]]
// CHECK: i1 true, label %[[TAGS:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[TAGS]]
// CHECK: switch i64 %0, label %[[DFLT]] [
// CHECK: i64 0, label %[[Y_DEST:[0-9]+]]
// CHECK: i64 1, label %[[Z_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
// CHECK: ; <label>:[[X_DEST]]
// CHECK: call void @a()
// CHECK: br label %[[END:[0-9]+]]
x_dest:
%a = function_ref @a : $@thin () -> ()
apply %a() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Y_DEST]]
// CHECK: call void @b()
// CHECK: br label %[[END]]
y_dest:
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Z_DEST]]
// CHECK: call void @c()
// CHECK: br label %[[END]]
z_dest:
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
br end
// CHECK: ; <label>:[[END]]
// CHECK: ret void
end:
%x = tuple ()
return %x : $()
}
// CHECK: define void @single_payload_no_xi_switch_arg(i64, i1) {
sil @single_payload_no_xi_switch_arg : $@thin (SinglePayloadNoXI2) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadNoXI2):
// CHECK: switch i1 %1, label %[[DFLT:[0-9]+]] [
// CHECK: i1 false, label %[[X_PREDEST:[0-9]+]]
// CHECK: i1 true, label %[[TAGS:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[TAGS]]
// CHECK: switch i64 %0, label %[[DFLT]] [
// CHECK: i64 0, label %[[Y_DEST:[0-9]+]]
// CHECK: i64 1, label %[[Z_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
// CHECK: ; <label>:[[X_PREDEST]]
// CHECK: br label %[[X_DEST:[0-9]+]]
// CHECK: ; <label>:[[X_DEST]]
// CHECK: {{%.*}} = phi i64 [ %0, %[[X_PREDEST]] ]
x_dest(%u2 : $Builtin.Int64):
// CHECK: call void @a()
// CHECK: br label %[[END:[0-9]+]]
%a = function_ref @a : $@thin () -> ()
apply %a() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Y_DEST]]
y_dest:
// CHECK: call void @b()
// CHECK: br label %[[END]]
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Z_DEST]]
z_dest:
// CHECK: call void @c()
// CHECK: br label %[[END]]
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
br end
// CHECK: ; <label>:[[END]]
// CHECK: ret void
end:
%x = tuple ()
return %x : $()
}
// CHECK: define { i64, i1 } @single_payload_no_xi_inject_x(i64) {
// CHECK: entry:
// CHECK: [[A:%.*]] = insertvalue { i64, i1 } undef, i64 %0, 0
// CHECK: [[B:%.*]] = insertvalue { i64, i1 } [[A]], i1 false, 1
// CHECK: ret { i64, i1 } [[B]]
// CHECK: }
sil @single_payload_no_xi_inject_x : $(Builtin.Int64) -> SinglePayloadNoXI2 {
entry(%0 : $Builtin.Int64):
%u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1, %0 : $Builtin.Int64
return %u : $SinglePayloadNoXI2
}
// CHECK: define void @single_payload_no_xi_inject_x_indirect(i64, %O4enum18SinglePayloadNoXI2* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %1 to i64*
// CHECK: store i64 %0, i64* [[DATA_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2* %1, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK: store i1 false, i1* [[TAG_ADDR]], align 8
// CHECK: ret void
// CHECK: }
sil @single_payload_no_xi_inject_x_indirect : $(Builtin.Int64, @inout SinglePayloadNoXI2) -> () {
entry(%0 : $Builtin.Int64, %1 : $*SinglePayloadNoXI2):
%a = init_enum_data_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1
store %0 to %a : $*Builtin.Int64
inject_enum_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1
%v = tuple ()
return %v : $()
}
// CHECK: define { i64, i1 } @single_payload_no_xi_inject_y() {
// CHECK: entry:
// CHECK: ret { i64, i1 } { i64 0, i1 true }
// CHECK: }
sil @single_payload_no_xi_inject_y : $() -> SinglePayloadNoXI2 {
entry:
%u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt
return %u : $SinglePayloadNoXI2
}
// CHECK: define void @single_payload_no_xi_inject_y_indirect(%O4enum18SinglePayloadNoXI2* noalias) {
// CHECK: entry:
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %0 to i64*
// CHECK: store i64 0, i64* [[PAYLOAD_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2* %0, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK: store i1 true, i1* [[TAG_ADDR]], align 8
// 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-LABEL: define { i64, i1 } @single_payload_no_xi_inject_z() {
// CHECK: entry:
// CHECK: ret { i64, i1 } { i64 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.Int64, Builtin.Int64)
case y
case z
}
// CHECK-LABEL: define void @aggregate_single_payload_unpack(i128, i1) {
sil @aggregate_single_payload_unpack : $@thin (AggregateSinglePayload) -> () {
entry(%u : $AggregateSinglePayload):
switch_enum %u : $AggregateSinglePayload, case #AggregateSinglePayload.x!enumelt.1: x_dest, default end
// CHECK: {{%.*}} = trunc i128 %0 to i64
// CHECK: [[SHIFT_1:%.*]] = lshr i128 %0, 64
// CHECK: {{%.*}} = trunc i128 [[SHIFT_1]] to i64
x_dest(%v : $(Builtin.Int64, Builtin.Int64)):
br end
end:
%x = tuple ()
return %x : $()
}
// CHECK-LABEL: define { i64, i64 } @aggregate_single_payload_unsafe_unpack(i128, i1) {
// CHECK: %2 = trunc i128 %0 to i64
// CHECK: %3 = lshr i128 %0, 64
// CHECK: %4 = trunc i128 %3 to i64
// CHECK: %5 = insertvalue { i64, i64 } undef, i64 %2, 0
// CHECK: %6 = insertvalue { i64, i64 } %5, i64 %4, 1
// CHECK: ret { i64, i64 } %6
sil @aggregate_single_payload_unsafe_unpack : $@thin (AggregateSinglePayload) -> (Builtin.Int64, Builtin.Int64) {
entry(%u : $AggregateSinglePayload):
%x = unchecked_enum_data %u : $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1
return %x : $(Builtin.Int64, Builtin.Int64)
}
// CHECK-LABEL: define { i128, i1 } @aggregate_single_payload_inject(i64, i64) {
// CHECK: entry:
// CHECK: [[ZEXT_0:%.*]] = zext i64 %0 to i128
// CHECK: [[ZEXT_1:%.*]] = zext i64 %1 to i128
// CHECK: [[SHIFT_1:%.*]] = shl i128 [[ZEXT_1]], 64
// CHECK: [[PAYLOAD:%.*]] = or i128 [[ZEXT_0]], [[SHIFT_1]]
// CHECK: [[RES_0:%.*]] = insertvalue { i128, i1 } undef, i128 [[PAYLOAD]], 0
// CHECK: [[RES:%.*]] = insertvalue { i128, i1 } [[RES_0]], i1 false, 1
// CHECK: ret { i128, i1 } [[RES]]
// CHECK: }
sil @aggregate_single_payload_inject : $(Builtin.Int64, Builtin.Int64) -> AggregateSinglePayload {
entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
%t = tuple (%0 : $Builtin.Int64, %1 : $Builtin.Int64)
%u = enum $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1, %t : $(Builtin.Int64, Builtin.Int64)
return %u : $AggregateSinglePayload
}
struct CharLike { var value : Builtin.Int21 }
struct IntLike { var value : Builtin.Int64 }
struct RangeLike { var from, to : Builtin.Int64 }
enum AggregateSinglePayload2 {
case x(CharLike, IntLike, RangeLike)
case y
case z
}
// CHECK: define void @aggregate_single_payload_unpack_2(i256) {
sil @aggregate_single_payload_unpack_2 : $@thin (AggregateSinglePayload2) -> () {
entry(%u : $AggregateSinglePayload2):
switch_enum %u : $AggregateSinglePayload2, case #AggregateSinglePayload2.x!enumelt.1: x_dest, default end
// CHECK: {{%.*}} = trunc i256 %0 to i21
// CHECK: [[SHIFT_1:%.*]] = lshr i256 %0, 64
// CHECK: {{%.*}} = trunc i256 [[SHIFT_1]] to i64
// CHECK: [[SHIFT_2_FROM:%.*]] = lshr i256 %0, 128
// CHECK: {{%.*}} = trunc i256 [[SHIFT_2_FROM]] to i64
// CHECK: [[SHIFT_2_TO:%.*]] = lshr i256 %0, 192
// CHECK: {{%.*}} = trunc i256 [[SHIFT_2_TO]] to i64
x_dest(%v : $(CharLike, IntLike, RangeLike)):
br end
end:
%x = tuple ()
return %x : $()
}
// CHECK: define i256 @aggregate_single_payload_2_inject(i21, i64, i64, i64) {
// CHECK: entry:
// CHECK: [[ZEXT_0:%.*]] = zext i21 %0 to i256
// CHECK: [[ZEXT_1:%.*]] = zext i64 %1 to i256
// CHECK: [[SHIFT_1:%.*]] = shl i256 [[ZEXT_1]], 64
// CHECK: [[PAYLOAD_0_1:%.*]] = or i256 [[ZEXT_0]], [[SHIFT_1]]
// CHECK: [[ZEXT_2_FROM:%.*]] = zext i64 %2 to i256
// CHECK: [[SHIFT_2_FROM:%.*]] = shl i256 [[ZEXT_2_FROM]], 128
// CHECK: [[ZEXT_2_TO:%.*]] = zext i64 %3 to i256
// CHECK: [[SHIFT_2_TO:%.*]] = shl i256 [[ZEXT_2_TO]], 192
// CHECK: [[PAYLOAD_2:%.*]] = or i256 [[SHIFT_2_FROM]], [[SHIFT_2_TO]]
// CHECK: [[PAYLOAD:%.*]] = or i256 [[PAYLOAD_0_1]], [[PAYLOAD_2]]
// CHECK: ret i256 [[PAYLOAD]]
// 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.Int64)
case y
case z
}
// CHECK-LABEL: define void @aggregate_single_payload_unpack_3(i128) {
sil @aggregate_single_payload_unpack_3 : $@thin (AggregateSinglePayload3) -> () {
entry(%u : $AggregateSinglePayload3):
switch_enum %u : $AggregateSinglePayload3, case #AggregateSinglePayload3.x!enumelt.1: x_dest, default end
// CHECK: {{%.*}} = trunc i128 %0 to i21
// CHECK: [[SHIFT_1:%.*]] = lshr i128 %0, 64
// CHECK: {{%.*}} = trunc i128 [[SHIFT_1]] to i64
x_dest(%v : $(Builtin.Int21, Builtin.Int64)):
br end
end:
%x = tuple ()
return %x : $()
}
// CHECK-LABEL: define i128 @aggregate_single_payload_inject_x3(i21, i64) {
// CHECK: entry:
// CHECK: [[ZEXT_0:%.*]] = zext i21 %0 to i128
// CHECK: [[ZEXT_1:%.*]] = zext i64 %1 to i128
// CHECK: [[SHIFT_1:%.*]] = shl i128 [[ZEXT_1]], 64
// CHECK: [[PAYLOAD:%.*]] = or i128 [[ZEXT_0]], [[SHIFT_1]]
// CHECK: ret i128 [[PAYLOAD]]
// CHECK: }
sil @aggregate_single_payload_inject_x3 : $(Builtin.Int21, Builtin.Int64) -> AggregateSinglePayload3 {
entry(%0 : $Builtin.Int21, %1 : $Builtin.Int64):
%t = tuple (%0 : $Builtin.Int21, %1 : $Builtin.Int64)
%u = enum $AggregateSinglePayload3, #AggregateSinglePayload3.x!enumelt.1, %t : $(Builtin.Int21, Builtin.Int64)
return %u : $AggregateSinglePayload3
}
// CHECK-LABEL: define i128 @aggregate_single_payload_inject_y3() {
// CHECK: entry:
// CHECK: ret i128 2097152
// 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: define void @single_payload_spare_bit_switch(i64) {
sil @single_payload_spare_bit_switch : $@thin (SinglePayloadSpareBit) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadSpareBit):
// CHECK: switch i64 %0, label %[[X_DEST:[0-9]+]] [
// -- 0x8000_0000_0000_0000
// CHECK: i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]]
// -- 0x8000_0000_0000_0001
// CHECK: i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]]
// CHECK: ]
switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.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 : $@thin () -> ()
apply %a() : $@thin () -> ()
// CHECK: br label %[[END:[0-9]+]]
br end
// CHECK: ; <label>:[[Y_DEST]]
y_dest:
// CHECK: call void @b()
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
// CHECK: br label %[[END]]
br end
// CHECK: ; <label>:[[Z_DEST]]
z_dest:
// CHECK: call void @c()
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
// CHECK: br label %[[END]]
br end
// CHECK: ; <label>:[[END]]
end:
// CHECK: ret void
%x = tuple ()
return %x : $()
}
// CHECK: define void @single_payload_spare_bit_switch_arg(i64) {
sil @single_payload_spare_bit_switch_arg : $@thin (SinglePayloadSpareBit) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadSpareBit):
// CHECK: switch i64 %0, label %[[X_PREDEST:[0-9]+]] [
// -- 0x8000_0000_0000_0000
// CHECK: i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]]
// -- 0x8000_0000_0000_0001
// CHECK: i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]]
// CHECK: ]
switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest
// CHECK: ; <label>:[[X_PREDEST]]
// CHECK: [[TRUNC_PAYLOAD:%.*]] = trunc i64 %0 to i63
// CHECK: br label %[[X_DEST:[0-9]+]]
// CHECK: ; <label>:[[X_DEST]]
// CHECK: {{%.*}} = phi i63 [ [[TRUNC_PAYLOAD]], %[[X_PREDEST]] ]
x_dest(%u2 : $Builtin.Int63):
// CHECK: call void @a()
%a = function_ref @a : $@thin () -> ()
apply %a() : $@thin () -> ()
// CHECK: br label %[[END:[0-9]+]]
br end
// CHECK: ; <label>:[[Y_DEST]]
y_dest:
// CHECK: call void @b()
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
// CHECK: br label %[[END]]
br end
// CHECK: ; <label>:[[Z_DEST]]
z_dest:
// CHECK: call void @c()
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
// CHECK: br label %[[END]]
br end
// CHECK: ; <label>:[[END]]
end:
// CHECK: ret void
%x = tuple ()
return %x : $()
}
sil @single_payload_spare_bit_switch_indirect : $@thin (@inout SinglePayloadSpareBit) -> () {
entry(%u : $*SinglePayloadSpareBit):
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]]
// CHECK: 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: ; <label>:
// CHECK: [[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 : $@thin () -> ()
apply %a() : $@thin () -> ()
br end
y_dest:
br end
z_dest:
br end
end:
%x = tuple ()
return %x : $()
}
// CHECK: define i64 @single_payload_spare_bit_inject_x(i63) {
// CHECK: entry:
// CHECK: [[A:%.*]] = zext i63 %0 to i64
// CHECK: ret i64 [[A]]
// CHECK: }
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: define void @single_payload_spare_bit_inject_x_indirect(i63, %O4enum21SinglePayloadSpareBit* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %1 to i63*
// CHECK: store i63 %0, i63* [[DATA_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define i64 @single_payload_spare_bit_inject_y() {
// CHECK: entry:
// -- 0x8000_0000_0000_0000
// CHECK: ret i64 -9223372036854775808
// CHECK: }
sil @single_payload_spare_bit_inject_y : $() -> SinglePayloadSpareBit {
entry:
%u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.y!enumelt
return %u : $SinglePayloadSpareBit
}
// CHECK: define void @single_payload_spare_bit_inject_y_indirect(%O4enum21SinglePayloadSpareBit* noalias) {
// CHECK: entry:
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64*
// -- 0x8000_0000_0000_0000
// CHECK: store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define i64 @single_payload_spare_bit_inject_z() {
// CHECK: entry:
// 0x8000_0000_0000_0001
// CHECK: ret i64 -9223372036854775807
// CHECK: }
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 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 @_TFC4enum1CD : $@cc(method) @thin (C) -> ()
enum SinglePayloadClass {
case x(C)
case y
case z
case w
}
// CHECK: define void @single_payload_class_switch(i64) {
// CHECK: entry:
// CHECK: switch i64 %0, label {{%.*}} [
// CHECK: i64 0, label {{%.*}}
// CHECK: i64 2, label {{%.*}}
// CHECK: i64 4, label {{%.*}}
// CHECK: ]
// CHECK: ; <label>
// CHECK: inttoptr i64 %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 : $()
}
@class_protocol protocol PC {}
@objc @class_protocol protocol PO {}
enum SinglePayloadClassProtocol {
case x(PC)
case y, z, w
}
enum SinglePayloadObjCProtocol {
case x(PO)
case y, z, w
}
// CHECK: define void @single_payload_class_protocol_switch(i128) {
// CHECK: switch i128 %0, label {{%.*}} [
// CHECK: i128 0, label {{%.*}}
// -- 0x2_0000_0000_0000_0000
// CHECK: i128 2, label {{%.*}}
// -- 0x4_0000_0000_0000_0000
// CHECK: i128 4, label {{%.*}}
// CHECK: ]
// CHECK: [[OBJECT_INT:%.*]] = trunc i128 %0 to i64
// CHECK: inttoptr i64 [[OBJECT_INT]] to %objc_object*
// CHECK: [[WITNESS_SHR:%.*]] = lshr i128 %0, 64
// CHECK: [[WITNESS_INT:%.*]] = trunc i128 [[WITNESS_SHR]] to i64
// CHECK: inttoptr i64 [[WITNESS_INT]] 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: define void @single_payload_objc_protocol_switch(i64) {
// CHECK: switch i64 %0, label {{%.*}}
// CHECK: i64 0, label {{%.*}}
// CHECK: i64 2, label {{%.*}}
// CHECK: i64 4, label {{%.*}}
// CHECK: ]
// CHECK: inttoptr i64 %0 to %objc_object*
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 void @dynamic_single_payload_switch(%O4enum20DynamicSinglePayload* noalias, %swift.type* %T) {
// CHECK: [[OPAQUE_ENUM:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
// CHECK: [[CASE_INDEX:%.*]] = call i32 @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 void @dynamic_single_payload_inject_x(%O4enum20DynamicSinglePayload* noalias sret, %swift.opaque* noalias, %swift.type* %T) {
// CHECK: [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
// CHECK: call void @swift_storeEnumTagSinglePayload(%swift.opaque* [[ADDR]], %swift.type* %T, i32 -1, i32 3)
sil @dynamic_single_payload_inject_x : $<T> (@out DynamicSinglePayload<T>, @in T) -> () {
entry(%r : $*DynamicSinglePayload<T>, %t : $*T):
inject_enum_addr %r : $*DynamicSinglePayload<T>, #DynamicSinglePayload.x!enumelt.1
%v = tuple ()
return %v : $()
}
// CHECK: define void @dynamic_single_payload_inject_y(%O4enum20DynamicSinglePayload* noalias sret, %swift.type* %T) {
// CHECK: [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
// CHECK: call void @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 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 i2 @dynamic_single_payload_empty_payload_load([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* noalias) {
// CHECK: entry:
// CHECK: %1 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i2*
// CHECK: %2 = load i2* %1, align 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 void @dynamic_single_payload_empty_payload_store([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* noalias, i2) {
// CHECK: entry:
// CHECK: %2 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i2*
// CHECK: store i2 %1, i2* %2, align 1
// 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 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 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 void @dynamic_single_payload_generic_destroy
// CHECK: br i1
// CHECK: <label>
// CHECK: call void %destroy
// CHECK: <label>
sil @dynamic_single_payload_generic_destroy : $@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: define void @multi_payload_no_spare_bits_switch(i64, i2) {
sil @multi_payload_no_spare_bits_switch : $(MultiPayloadNoSpareBits) -> () {
entry(%u : $MultiPayloadNoSpareBits):
// CHECK: switch i2 %1, label %[[UNREACHABLE:[0-9]+]] [
// CHECK: i2 0, label %[[X_PREDEST:[0-9]+]]
// CHECK: i2 1, label %[[Y_PREDEST:[0-9]+]]
// CHECK: i2 -2, label %[[Z_PREDEST:[0-9]+]]
// CHECK: i2 -1, label %[[EMPTY:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[EMPTY]]
// CHECK: switch i64 %0, label %[[UNREACHABLE]] [
// CHECK: i64 0, label %[[A_DEST:[0-9]+]]
// CHECK: i64 1, label %[[B_DEST:[0-9]+]]
// CHECK: i64 2, label %[[C_DEST:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[UNREACHABLE]]
// CHECK: 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: ; <label>:[[X_PREDEST]]
// CHECK: br label %[[X_DEST:[0-9]+]]
// CHECK: ; <label>:[[Y_PREDEST]]
// CHECK: [[Y_VALUE:%.*]] = trunc i64 %0 to i32
// CHECK: br label %[[Y_DEST:[0-9]+]]
// CHECK: ; <label>:[[Z_PREDEST]]
// CHECK: [[Z_VALUE:%.*]] = trunc i64 %0 to i63
// CHECK: br label %[[Z_DEST:[0-9]+]]
// CHECK: ; <label>:[[X_DEST]]
// CHECK: phi i64 [ %0, %[[X_PREDEST]] ]
x_dest(%x : $Builtin.Int64):
%a = function_ref @a : $@thin () -> ()
apply %a() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Y_DEST]]
// CHECK: phi i32 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
y_dest(%y : $Builtin.Int32):
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Z_DEST]]
// CHECK: phi i63 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
z_dest(%z : $Builtin.Int63):
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
br end
// CHECK: ; <label>:[[A_DEST]]
a_dest:
%d = function_ref @d : $@thin () -> ()
apply %d() : $@thin () -> ()
br end
// CHECK: ; <label>:[[B_DEST]]
b_dest:
%e = function_ref @e : $@thin () -> ()
apply %e() : $@thin () -> ()
br end
// CHECK: ; <label>:[[C_DEST]]
c_dest:
%f = function_ref @f : $@thin () -> ()
apply %f() : $@thin () -> ()
br end
end:
%v = tuple ()
return %v : $()
}
// CHECK: define void @multi_payload_no_spare_bits_switch_indirect(%O4enum23MultiPayloadNoSpareBits* noalias) {
sil @multi_payload_no_spare_bits_switch_indirect : $(@inout MultiPayloadNoSpareBits) -> () {
entry(%u : $*MultiPayloadNoSpareBits):
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i2*
// CHECK: [[TAG:%.*]] = load i2* [[TAG_ADDR]], align 8
// CHECK: switch i2 [[TAG]]
// CHECK: switch i64 [[PAYLOAD]]
// CHECK: ; <label>:
// CHECK: 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: ; <label>:[[X_DEST:[0-9]+]]
// CHECK: bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
// CHECK: ; <label>:[[Y_DEST:[0-9]+]]
// CHECK: bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i32*
// CHECK: ; <label>:[[Z_DEST:[0-9]+]]
// CHECK: 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: define { i64, i2 } @multi_payload_no_spare_bit_inject_x(i64) {
// CHECK: entry:
// CHECK: [[RES_0:%.*]] = insertvalue { i64, i2 } undef, i64 %0, 0
// CHECK: [[RES:%.*]] = insertvalue { i64, i2 } [[RES_0]], i2 0, 1
// CHECK: ret { i64, i2 } [[RES]]
// CHECK: }
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: define void @multi_payload_no_spare_bit_inject_x_indirect(i64, %O4enum23MultiPayloadNoSpareBits* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %1 to i64*
// CHECK: store i64 %0, i64* [[DATA_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits* %1, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i2*
// CHECK: store i2 0, i2* [[TAG_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define { i64, i2 } @multi_payload_no_spare_bit_inject_y(i32) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i32 %0 to i64
// CHECK: [[RES_0:%.*]] = insertvalue { i64, i2 } undef, i64 [[ZEXT]], 0
// CHECK: [[RES:%.*]] = insertvalue { i64, i2 } [[RES_0]], i2 1, 1
// CHECK: ret { i64, i2 } [[RES]]
// CHECK: }
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: define { i64, i2 } @multi_payload_no_spare_bit_inject_z(i63) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i63 %0 to i64
// CHECK: [[RES_0:%.*]] = insertvalue { i64, i2 } undef, i64 [[ZEXT]], 0
// CHECK: [[RES:%.*]] = insertvalue { i64, i2 } [[RES_0]], i2 -2, 1
// CHECK: ret { i64, i2 } [[RES]]
// CHECK: }
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: define { i64, i2 } @multi_payload_no_spare_bit_inject_a() {
// CHECK: entry:
// CHECK: ret { i64, i2 } { i64 0, i2 -1 }
// CHECK: }
sil @multi_payload_no_spare_bit_inject_a : $() -> MultiPayloadNoSpareBits {
entry:
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.a!enumelt
return %u : $MultiPayloadNoSpareBits
}
// CHECK: define void @multi_payload_no_spare_bit_inject_a_indirect(%O4enum23MultiPayloadNoSpareBits* noalias) {
// CHECK: entry:
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
// CHECK: store i64 0, i64* [[PAYLOAD_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i2*
// CHECK: store i2 -1, i2* [[TAG_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define { i64, i2 } @multi_payload_no_spare_bit_inject_b() {
// CHECK: entry:
// CHECK: ret { i64, i2 } { i64 1, i2 -1 }
// CHECK: }
sil @multi_payload_no_spare_bit_inject_b : $() -> MultiPayloadNoSpareBits {
entry:
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.b!enumelt
return %u : $MultiPayloadNoSpareBits
}
// CHECK: define { i64, i2 } @multi_payload_no_spare_bit_inject_c() {
// CHECK: entry:
// CHECK: ret { i64, i2 } { i64 2, i2 -1 }
// CHECK: }
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: define void @multi_payload_one_spare_bit_switch(i64, i1) {
sil @multi_payload_one_spare_bit_switch : $(MultiPayloadOneSpareBit) -> () {
entry(%u : $MultiPayloadOneSpareBit):
// CHECK: [[SPARE_TAG_LSHR:%.*]] = lshr i64 %0, 63
// CHECK: [[SPARE_TAG_TRUNC:%.*]] = trunc i64 [[SPARE_TAG_LSHR]] to i2
// CHECK: [[SPARE_TAG:%.*]] = and i2 [[SPARE_TAG_TRUNC]], 1
// CHECK: [[EXTRA_TAG_ZEXT:%.*]] = zext i1 %1 to i2
// CHECK: [[EXTRA_TAG:%.*]] = shl i2 [[EXTRA_TAG_ZEXT]], 1
// CHECK: [[TAG:%.*]] = or i2 [[SPARE_TAG]], [[EXTRA_TAG]]
// CHECK: switch i2 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [
// CHECK: i2 0, label %[[X_PREDEST:[0-9]+]]
// CHECK: i2 1, label %[[Y_PREDEST:[0-9]+]]
// CHECK: i2 -2, label %[[Z_PREDEST:[0-9]+]]
// CHECK: i2 -1, label %[[EMPTY_DEST:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[EMPTY_DEST]]
// CHECK: switch i64 %0, label %[[UNREACHABLE]] [
// -- 0x8000_0000_0000_0000
// CHECK: i64 -9223372036854775808, label %[[A_DEST:[0-9]+]]
// -- 0x8000_0000_0000_0001
// CHECK: i64 -9223372036854775807, label %[[B_DEST:[0-9]+]]
// -- 0x8000_0000_0000_0002
// CHECK: i64 -9223372036854775806, label %[[C_DEST:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[UNREACHABLE]]
// CHECK: 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: ; <label>:[[X_PREDEST]]
// CHECK: [[X_VALUE:%.*]] = trunc i64 %0 to i62
// CHECK: br label %[[X_DEST:[0-9]+]]
// CHECK: ; <label>:[[Y_PREDEST]]
// -- 0x7FFF_FFFF_FFFF_FFFF
// CHECK: [[Y_MASKED:%.*]] = and i64 %0, 9223372036854775807
// CHECK: [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i63
// CHECK: br label %[[Y_DEST:[0-9]+]]
// CHECK: ; <label>:[[Z_PREDEST]]
// CHECK: [[Z_VALUE:%.*]] = trunc i64 %0 to i61
// CHECK: br label %[[Z_DEST:[0-9]+]]
// CHECK: ; <label>:[[X_DEST]]
// CHECK: phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ]
x_dest(%x : $Builtin.Int62):
%a = function_ref @a : $@thin () -> ()
apply %a() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Y_DEST]]
// CHECK: phi i63 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
y_dest(%y : $Builtin.Int63):
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Z_DEST]]
// CHECK: phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
z_dest(%z : $Builtin.Int61):
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
br end
// CHECK: ; <label>:[[A_DEST]]
a_dest:
%d = function_ref @d : $@thin () -> ()
apply %d() : $@thin () -> ()
br end
// CHECK: ; <label>:[[B_DEST]]
b_dest:
%e = function_ref @e : $@thin () -> ()
apply %e() : $@thin () -> ()
br end
// CHECK: ; <label>:[[C_DEST]]
c_dest:
%f = function_ref @f : $@thin () -> ()
apply %f() : $@thin () -> ()
br end
end:
%v = tuple ()
return %v : $()
}
sil @multi_payload_one_spare_bit_switch_indirect : $(@inout MultiPayloadOneSpareBit) -> () {
entry(%u : $*MultiPayloadOneSpareBit):
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK: [[TAG:%.*]] = load i1* [[TAG_ADDR]], align 8
// CHECK: switch i2 {{%.*}}
// CHECK: switch i64 [[PAYLOAD]]
// CHECK: ; <label>:
// CHECK: 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: ; <label>:[[X_PREDEST:[0-9]+]]
// CHECK: bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i62*
// CHECK: ; <label>:[[Y_PREDEST:[0-9]+]]
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]]
// -- 0x7FFF_FFFF_FFFF_FFFF
// CHECK: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
// CHECK: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]], align 8
// CHECK: bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i63*
// CHECK: ; <label>:[[Z_PREDEST:[0-9]+]]
// CHECK: 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: define { i64, i1 } @multi_payload_one_spare_bit_inject_x(i62) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i62 %0 to i64
// CHECK: [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[ZEXT]], 0
// CHECK: [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 false, 1
// CHECK: ret { i64, i1 } [[RES]]
// CHECK: }
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: define void @multi_payload_one_spare_bit_inject_x_indirect(i62, %O4enum23MultiPayloadOneSpareBit* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i62*
// CHECK: store i62 %0, i62* [[DATA_ADDR]], align 8
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]], align 8
// -- 0x7FFF_FFFF_FFFF_FFFF
// CHECK: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
// CHECK: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK: store i1 false, i1* [[TAG_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define { i64, i1 } @multi_payload_one_spare_bit_inject_y(i63) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i63 %0 to i64
// -- 0x8000_0000_0000_0000
// CHECK: [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808
// CHECK: [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[TAGGED]], 0
// CHECK: [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 false, 1
// CHECK: ret { i64, i1 } [[RES]]
// CHECK: }
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: define void @multi_payload_one_spare_bit_inject_y_indirect(i63, %O4enum23MultiPayloadOneSpareBit* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i63*
// CHECK: store i63 %0, i63* [[DATA_ADDR]], align 8
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]], align 8
// -- 0x7FFF_FFFF_FFFF_FFFF
// CHECK: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
// -- 0x8000_0000_0000_0000
// CHECK: [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], -9223372036854775808
// CHECK: store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK: store i1 false, i1* [[TAG_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define { i64, i1 } @multi_payload_one_spare_bit_inject_z(i61) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i61 %0 to i64
// CHECK: [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[ZEXT]], 0
// CHECK: [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 true, 1
// CHECK: ret { i64, i1 } [[RES]]
// CHECK: }
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: define { i64, i1 } @multi_payload_one_spare_bit_inject_a() {
// CHECK: entry:
// -- 0x8000_0000_0000_0000
// CHECK: ret { i64, i1 } { i64 -9223372036854775808, i1 true }
// CHECK: }
sil @multi_payload_one_spare_bit_inject_a : $() -> MultiPayloadOneSpareBit {
entry:
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt
return %u : $MultiPayloadOneSpareBit
}
// CHECK: define void @multi_payload_one_spare_bit_inject_a_indirect(%O4enum23MultiPayloadOneSpareBit* noalias) {
// CHECK: entry:
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
// -- 0x8000_0000_0000_0000
// CHECK: store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]], align 8
// CHECK: [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK: store i1 true, i1* [[TAG_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define { i64, i1 } @multi_payload_one_spare_bit_inject_b() {
// CHECK: entry:
// -- 0x8000_0000_0000_0001
// CHECK: ret { i64, i1 } { i64 -9223372036854775807, i1 true }
// CHECK: }
sil @multi_payload_one_spare_bit_inject_b : $() -> MultiPayloadOneSpareBit {
entry:
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.b!enumelt
return %u : $MultiPayloadOneSpareBit
}
// CHECK: define { i64, i1 } @multi_payload_one_spare_bit_inject_c() {
// CHECK: entry:
// -- 0x8000_0000_0000_0002
// CHECK: ret { i64, i1 } { i64 -9223372036854775806, i1 true }
// CHECK: }
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: define void @multi_payload_two_spare_bits_switch(i64) {
sil @multi_payload_two_spare_bits_switch : $(MultiPayloadTwoSpareBits) -> () {
entry(%u : $MultiPayloadTwoSpareBits):
// CHECK: [[TAG_LSHR:%.*]] = lshr i64 %0, 62
// CHECK: [[TAG:%.*]] = trunc i64 [[TAG_LSHR]] to i2
// CHECK: switch i2 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [
// CHECK: i2 0, label %[[X_PREDEST:[0-9]+]]
// CHECK: i2 1, label %[[Y_PREDEST:[0-9]+]]
// CHECK: i2 -2, label %[[Z_PREDEST:[0-9]+]]
// CHECK: i2 -1, label %[[EMPTY_DEST:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[EMPTY_DEST]]
// CHECK: switch i64 %0, label %[[UNREACHABLE]] [
// -- 0xC000_0000_0000_0000
// CHECK: i64 -4611686018427387904, label %[[A_DEST:[0-9]+]]
// -- 0xC000_0000_0000_0001
// CHECK: i64 -4611686018427387903, label %[[B_DEST:[0-9]+]]
// -- 0xC000_0000_0000_0002
// CHECK: i64 -4611686018427387902, label %[[C_DEST:[0-9]+]]
// CHECK: ]
// CHECK: ; <label>:[[UNREACHABLE]]
// CHECK: 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: ; <label>:[[X_PREDEST]]
// CHECK: [[X_VALUE:%.*]] = trunc i64 %0 to i62
// CHECK: br label %[[X_DEST:[0-9]+]]
// CHECK: ; <label>:[[Y_PREDEST]]
// -- 0x3FFF_FFFF_FFFF_FFFF
// CHECK: [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903
// CHECK: [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i60
// CHECK: br label %[[Y_DEST:[0-9]+]]
// CHECK: ; <label>:[[Z_PREDEST]]
// -- 0x3FFF_FFFF_FFFF_FFFF
// CHECK: [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903
// CHECK: [[Z_VALUE:%.*]] = trunc i64 [[Z_MASKED]] to i61
// CHECK: br label %[[Z_DEST:[0-9]+]]
// CHECK: ; <label>:[[X_DEST]]
// CHECK: phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ]
x_dest(%x : $Builtin.Int62):
%a = function_ref @a : $@thin () -> ()
apply %a() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Y_DEST]]
// CHECK: phi i60 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
y_dest(%y : $Builtin.Int60):
%b = function_ref @b : $@thin () -> ()
apply %b() : $@thin () -> ()
br end
// CHECK: ; <label>:[[Z_DEST]]
// CHECK: phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
z_dest(%z : $Builtin.Int61):
%c = function_ref @c : $@thin () -> ()
apply %c() : $@thin () -> ()
br end
// CHECK: ; <label>:[[A_DEST]]
a_dest:
%d = function_ref @d : $@thin () -> ()
apply %d() : $@thin () -> ()
br end
// CHECK: ; <label>:[[B_DEST]]
b_dest:
%e = function_ref @e : $@thin () -> ()
apply %e() : $@thin () -> ()
br end
// CHECK: ; <label>:[[C_DEST]]
c_dest:
%f = function_ref @f : $@thin () -> ()
apply %f() : $@thin () -> ()
br end
end:
%v = tuple ()
return %v : $()
}
// CHECK: define i64 @multi_payload_two_spare_bits_inject_x(i62) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i62 %0 to i64
// CHECK: ret i64 [[ZEXT]]
// CHECK: }
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: define void @multi_payload_two_spare_bits_inject_x_indirect(i62, %O4enum24MultiPayloadTwoSpareBits* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i62*
// CHECK: store i62 %0, i62* [[DATA_ADDR]], align 8
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]], align 8
// -- 0x3FFF_FFFF_FFFF_FFFF
// CHECK: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
// CHECK: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define i64 @multi_payload_two_spare_bits_inject_y(i60) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i60 %0 to i64
// -- 0x4000_0000_0000_0000
// CHECK: [[TAGGED:%.*]] = or i64 [[ZEXT]], 4611686018427387904
// CHECK: ret i64 [[TAGGED]]
// CHECK: }
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: define void @multi_payload_two_spare_bits_inject_y_indirect(i60, %O4enum24MultiPayloadTwoSpareBits* noalias) {
// CHECK: entry:
// CHECK: [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i60*
// CHECK: store i60 %0, i60* [[DATA_ADDR]], align 8
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
// CHECK: [[PAYLOAD:%.*]] = load i64* [[PAYLOAD_ADDR]], align 8
// -- 0x3FFF_FFFF_FFFF_FFFF
// CHECK: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
// -- 0x4000_0000_0000_0000
// CHECK: [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], 4611686018427387904
// CHECK: store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define i64 @multi_payload_two_spare_bits_inject_z(i61) {
// CHECK: entry:
// CHECK: [[ZEXT:%.*]] = zext i61 %0 to i64
// -- 0x8000_0000_0000_0000
// CHECK: [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808
// CHECK: ret i64 [[TAGGED]]
// CHECK: }
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: define i64 @multi_payload_two_spare_bits_inject_a() {
// CHECK: entry:
// -- 0xC000_0000_0000_0000
// CHECK: ret i64 -4611686018427387904
// CHECK: }
sil @multi_payload_two_spare_bits_inject_a : $() -> MultiPayloadTwoSpareBits {
entry:
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.a!enumelt
return %u : $MultiPayloadTwoSpareBits
}
// CHECK: define void @multi_payload_two_spare_bits_inject_a_indirect(%O4enum24MultiPayloadTwoSpareBits* noalias) {
// CHECK: entry:
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %0 to i64*
// -- 0xC000_0000_0000_0000
// CHECK: store i64 -4611686018427387904, i64* [[PAYLOAD_ADDR]], align 8
// CHECK: ret void
// CHECK: }
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: define i64 @multi_payload_two_spare_bits_inject_b() {
// CHECK: entry:
// -- 0xC000_0000_0000_0001
// CHECK: ret i64 -4611686018427387903
// CHECK: }
sil @multi_payload_two_spare_bits_inject_b : $() -> MultiPayloadTwoSpareBits {
entry:
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.b!enumelt
return %u : $MultiPayloadTwoSpareBits
}
// CHECK: define i64 @multi_payload_two_spare_bits_inject_c() {
// CHECK: entry:
// -- 0xC000_0000_0000_0002
// CHECK: ret i64 -4611686018427387902
// CHECK: }
sil @multi_payload_two_spare_bits_inject_c : $() -> MultiPayloadTwoSpareBits {
entry:
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.c!enumelt
return %u : $MultiPayloadTwoSpareBits
}
class D {}
sil @_TFC4enum1DD : $@cc(method) @thin (D) -> ()
enum MultiPayloadClasses {
case x(C)
case y(D)
case z
case w
}
// CHECK-LABEL: define void @multi_payload_classes_switch(i64) {
// CHECK: %1 = lshr i64 %0, 61
// CHECK: %2 = trunc i64 %1 to i2
// CHECK: switch i2 %2, label {{%.*}} [
// CHECK: i2 0, label {{%.*}}
// CHECK: i2 1, label {{%.*}}
// CHECK: i2 -2, label {{%.*}}
// CHECK: ]
// CHECK: switch i64 %0, label {{%.*}} [
// -- 0x4000000000000000
// CHECK: i64 4611686018427387904, label {{%.*}}
// -- 0x4000000000000001
// CHECK: i64 4611686018427387905, label {{%.*}}
// CHECK: ]
// -- Extract x(C)
// CHECK: inttoptr i64 %0 to %C4enum1C*
// -- Extract y(D)
// -- 0x9fffffffffffffff
// CHECK: [[MASKED:%.*]] = and i64 %0, -6917529027641081857
// CHECK: inttoptr i64 [[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 : $()
}
// <rdar://problem/15787975> part 1: Make sure String's Owner union is
// efficiently packed. It comprises a class existential, a class handle, and
// an empty case.
@objc @class_protocol protocol CP {}
enum StringOwnerLike {
case x(C)
case y(CP)
case z
case w
}
// CHECK-LABEL: define void @string_owner_like_switch(i64) {
// CHECK: %1 = lshr i64 %0, 61
// CHECK: %2 = trunc i64 %1 to i2
// CHECK: switch i2 %2, label {{%.*}} [
// CHECK: i2 0, label {{%.*}}
// CHECK: i2 1, label {{%.*}}
// CHECK: i2 -2, label {{%.*}}
// CHECK: ]
// CHECK: switch i64 %0, label {{%.*}} [
// -- 0x4000000000000000
// CHECK: i64 4611686018427387904, label {{%.*}}
// -- 0x4000000000000001
// CHECK: i64 4611686018427387905, label {{%.*}}
// CHECK: ]
// -- Extract x(C)
// CHECK: inttoptr i64 %0 to %C4enum1C*
// -- Extract y(CP)
// -- 0x9fffffffffffffff
// CHECK: [[MASKED:%.*]] = and i64 %0, -6917529027641081857
// CHECK: inttoptr i64 [[MASKED]] to %objc_object*
sil @string_owner_like_switch : $(StringOwnerLike) -> () {
entry(%c : $StringOwnerLike):
switch_enum %c : $StringOwnerLike, case #StringOwnerLike.x!enumelt.1: x_dest, case #StringOwnerLike.y!enumelt.1: y_dest, case #StringOwnerLike.z!enumelt: z_dest, case #StringOwnerLike.w!enumelt: w_dest
x_dest(%x : $C):
br end
y_dest(%y : $CP):
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-LABEL: define void @multi_payload_spare_bit_aggregate_switch(i128) {
// CHECK: [[T0:%.*]] = lshr i128 %0, 61
// CHECK: [[TAG:%.*]] = trunc i128 [[T0]] to i2
// CHECK: switch i2 [[TAG]], label {{%.*}} [
// 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>:[[X_DEST]]
// CHECK: [[X_0:%.*]] = trunc i128 %0 to i32
// CHECK: [[T1:%.*]] = lshr i128 %0, 64
// CHECK: [[X_1:%.*]] = trunc i128 [[T1]] to i64
// CHECK: ; <label>:[[Y_DEST]]
// -- 0x9fffffffffffffff
// CHECK: [[Y_MASKED:%.*]] = and i128 %0, -6917529027641081857
// CHECK: [[T2:%.*]] = trunc i128 [[Y_MASKED]] to i64
// CHECK: [[Y_0:%.*]] = inttoptr i64 [[T2]] to %C4enum1C*
// CHECK: [[T3:%.*]] = lshr i128 [[Y_MASKED]], 64
// CHECK: [[T4:%.*]] = trunc i128 [[T3]] to i64
// CHECK: [[Y_1:%.*]] = inttoptr i64 [[T4]] to %C4enum1C*
// CHECK: ; <label>:[[Z_DEST]]
// -- 0x9fffffffffffffff
// CHECK: [[Z_MASKED:%.*]] = and i128 %0, -6917529027641081857
// CHECK: [[Z_A:%.*]] = trunc i128 [[Z_MASKED]] to i21
// CHECK: [[T5:%.*]] = lshr i128 [[Z_MASKED]], 64
// CHECK: [[Z_B:%.*]] = trunc i128 [[T5]] to i64
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.Int64)
case B(Builtin.Int64)
}
enum MultiPayloadNested {
case A(MultiPayloadInner)
case B(MultiPayloadInner)
}
// CHECK-LABEL: define void @multi_payload_nested_switch
// CHECK: %1 = bitcast %O4enum18MultiPayloadNested* %0 to i72*
// CHECK: %2 = load i72* %1, align 8
// CHECK: %3 = lshr i72 %2, 71
// CHECK: %4 = trunc i72 %3 to i1
// CHECK: switch i1 %4, 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-LABEL: define void @multi_payload_nested_spare_bits_switch(%O4enum27MultiPayloadNestedSpareBits* noalias) {
// CHECK: entry:
// CHECK: %1 = bitcast %O4enum27MultiPayloadNestedSpareBits* %0 to i64*
// CHECK: %2 = load i64* %1, align 8
// CHECK: %3 = lshr i64 %2, 60
// CHECK: %4 = trunc i64 %3 to i1
// CHECK: switch i1 %4, label {{%.*}} [
// CHECK: i1 false, label {{%.*}}
// CHECK: i1 true, label {{%.*}}
// CHECK: ]
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 : $()
}
// Force the storage types to all be generated.
typealias AllConcreteTestEnums = (
Empty,
EmptySingleton,
Singleton,
SingletonRef,
NoPayloads,
NoPayloads2,
SinglePayloadNoXI,
SinglePayloadNoXI2,
SinglePayloadSpareBit,
SinglePayloadNested,
SinglePayloadNestedNested,
MultiPayloadNoSpareBits,
MultiPayloadOneSpareBit,
MultiPayloadTwoSpareBits,
StringOwnerLike,
MultiPayloadSpareBitAggregates,
MultiPayloadNested,
MultiPayloadNestedSpareBits)
var x : AllConcreteTestEnums
// CHECK: define void @dynamic_singleton_switch_indirect(%O4enum16DynamicSingleton* noalias, %swift.type* %T) {
// CHECK: bitcast %O4enum16DynamicSingleton* %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.
var a : DynamicSingleton<()>
var b : DynamicSingleton<NoPayloads>
// CHECK: define void @dynamic_singleton_instance_arg_1()
sil @dynamic_singleton_instance_arg_1 : $(DynamicSingleton<()>) -> () {
entry(%0 : $DynamicSingleton<()>):
%v = tuple ()
return %v : $()
}
// CHECK: define void @dynamic_singleton_instance_arg_2(i2)
sil @dynamic_singleton_instance_arg_2 : $(DynamicSingleton<NoPayloads>) -> () {
entry(%0 : $DynamicSingleton<NoPayloads>):
%v = tuple ()
return %v : $()
}
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 #a : $*DynamicSingleton<()>
%q = load %a : $*DynamicSingleton<()>
%b = global_addr #b : $*DynamicSingleton<NoPayloads>
%r = load %b : $*DynamicSingleton<NoPayloads>
%z = tuple ()
return %z : $()
}
// -- Fill function for dynamic singleton. The value witness table flags just
// get copied over from the element.
// CHECK: define internal void [[DYNAMIC_SINGLETON_FILL]](i8*, i8*) {
// CHECK: [[FULL_ADDR:%.*]] = bitcast i8* %0 to i64*
// CHECK: [[METADATA_ADDR:%.*]] = getelementptr inbounds i64* [[FULL_ADDR]], i32 1
// CHECK: [[METADATA:%.*]] = bitcast i64* [[METADATA_ADDR]] to %swift.type*
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i64* [[FULL_ADDR]], i32 6
// CHECK: [[VWT:%.*]] = bitcast i64* [[VWT_ADDR]] to i8**
// CHECK: [[METADATA_PARAMS:%.*]] = bitcast %swift.type* [[METADATA]] to %swift.type**
// CHECK: [[METADATA_PARAM_ADDR:%.*]] = getelementptr inbounds %swift.type** [[METADATA_PARAMS]], i64 3
// CHECK: [[T:%.*]] = load %swift.type** [[METADATA_PARAM_ADDR]], align 8
// CHECK: [[T_VWTS:%.*]] = bitcast %swift.type* [[T]] to i8***
// CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds i8*** [[T_VWTS]], i64 -1
// CHECK: [[T_VWT:%.*]] = load i8*** [[T_VWT_ADDR]], align 8
// CHECK: [[SIZE_ADDR:%.*]] = getelementptr inbounds i8** [[VWT]], i32 17
// CHECK: [[T_SIZE_ADDR:%.*]] = getelementptr inbounds i8** [[T_VWT]], i32 17
// CHECK: [[T_SIZE:%.*]] = load i8** [[T_SIZE_ADDR]], align 8
// CHECK: store i8* [[T_SIZE]], i8** [[SIZE_ADDR]], align 8
// CHECK: [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8** [[VWT]], i32 18
// CHECK: [[T_FLAGS_ADDR:%.*]] = getelementptr inbounds i8** [[T_VWT]], i32 18
// CHECK: [[T_FLAGS:%.*]] = load i8** [[T_FLAGS_ADDR]], align 8
// CHECK: store i8* [[T_FLAGS]], i8** [[FLAGS_ADDR]], align 8
// CHECK: [[STRIDE_ADDR:%.*]] = getelementptr inbounds i8** [[VWT]], i32 19
// CHECK: [[T_STRIDE_ADDR:%.*]] = getelementptr inbounds i8** [[T_VWT]], i32 19
// CHECK: [[T_STRIDE:%.*]] = load i8** [[T_STRIDE_ADDR]], align 8
// CHECK: store i8* [[T_STRIDE]], i8** [[STRIDE_ADDR]], align 8
// -- Test the 'has extra inhabitants' bit and carry over the extra inhabitants
// flag if set.
// CHECK: [[T_FLAGS_VAL:%.*]] = ptrtoint i8* [[T_FLAGS]] to i64
// CHECK: [[XI_FLAG:%.*]] = and i64 [[T_FLAGS_VAL]], 262144
// CHECK: [[XI_BIT:%.*]] = icmp ne i64 [[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** [[VWT]], i32 22
// CHECK: [[T_XI_FLAGS_ADDR:%.*]] = getelementptr inbounds i8** [[T_VWT]], i32 22
// CHECK: [[T_XI_FLAGS:%.*]] = load i8** [[T_XI_FLAGS_ADDR]], align 8
// CHECK: store i8* [[T_XI_FLAGS]], i8** [[XI_FLAGS_ADDR]], align 8
// CHECK: br label %[[HAS_NO_XI]]
// CHECK: ; <label>:[[HAS_NO_XI]]
// -- Fill function for dynamic single-payload. Call into the runtime to
// calculate the size.
// CHECK: define internal void [[DYNAMIC_SINGLE_PAYLOAD_FILL]](i8*, i8*) {
// CHECK: call void @swift_initEnumValueWitnessTableSinglePayload