mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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
2357 lines
82 KiB
Plaintext
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
|