mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This change uses the 'gather bits' functionality of enum payloads to create a contiguous value to switch over. This allows us to remove the code that currently attempts to build a switch statement by comparing each element in the payload in turn. The downside of this technique is that we may do more work up front gathering bits and we may also need to compare larger values in some situations. The upside is that we can remove a lot of complicated code from IRGen. Also, we pass the responsibility for multi-way branch generation to LLVM which can make use of a wider range of switch lowering strategies than IRGen can sensibly support.
2765 lines
111 KiB
Plaintext
2765 lines
111 KiB
Plaintext
// #if directives don't work with SIL keywords, therefore please put ObjC tests
|
|
// in `enum_objc.sil`.
|
|
// RUN: %target-swift-frontend %s -gnone -emit-ir -disable-diagnostic-passes -enable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-objc --check-prefix=CHECK-objc-%target-ptrsize --check-prefix=CHECK-objc-%target-ptrsize-simulator-%target-is-simulator -DWORD=i%target-ptrsize
|
|
// RUN: %target-swift-frontend %s -gnone -emit-ir -disable-diagnostic-passes -disable-objc-interop | %FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-native --check-prefix=CHECK-native-%target-ptrsize -DWORD=i%target-ptrsize
|
|
|
|
// REQUIRES: CPU=i386 || CPU=x86_64
|
|
|
|
// We have to claim this is raw SIL because there are critical edges from non
|
|
// cond_br instructions.
|
|
sil_stage raw
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
// -- Singleton enum. The representation is just the singleton payload.
|
|
// CHECK: %T4enum9SingletonO = type <{ <{ i64, i64 }> }>
|
|
|
|
// -- Singleton enum with heap object ref payload. <rdar://problem/15679353>
|
|
// CHECK: %T4enum12SingletonRefO = type <{ %swift.refcounted* }>
|
|
|
|
// -- No-payload enums. The representation is just an enum tag.
|
|
// CHECK: %T4enum10NoPayloadsO = type <{ i8 }>
|
|
// CHECK: %T4enum11NoPayloads2O = type <{ i8 }>
|
|
|
|
// -- Single-payload enum, no extra inhabitants in the payload type. The
|
|
// representation adds a tag bit to distinguish payload from enum tag:
|
|
// case x(i64): X0 X1 X2 ... X63 | 0, where X0...X63 are the payload bits
|
|
// case y: 0 0 0 ... 0 | 1
|
|
// case z: 1 0 0 ... 0 | 1
|
|
// CHECK-64: %T4enum17SinglePayloadNoXIO = type <{ [8 x i8], [1 x i8] }>
|
|
// CHECK-64: %T4enum18SinglePayloadNoXI2O = type <{ [8 x i8], [1 x i8] }>
|
|
// CHECK-32: %T4enum17SinglePayloadNoXIO = type <{ [4 x i8], [1 x i8] }>
|
|
// CHECK-32: %T4enum18SinglePayloadNoXI2O = type <{ [4 x i8], [1 x i8] }>
|
|
|
|
// -- Single-payload enum, spare bits. The representation uses a tag bit
|
|
// out of the payload to distinguish payload from enum tag:
|
|
// case x(i3): X0 X1 X2 0 0 0 0 0
|
|
// case y: 0 0 0 1 0 0 0 0
|
|
// case z: 1 0 0 1 0 0 0 0
|
|
// CHECK: %T4enum21SinglePayloadSpareBitO = type <{ [8 x i8] }>
|
|
|
|
// -- Single-payload enum containing a no-payload enum as its payload.
|
|
// The representation takes extra inhabitants starting after the greatest
|
|
// discriminator value used by the nested no-payload enum.
|
|
// CHECK: %T4enum19SinglePayloadNestedO = type <{ [1 x i8] }>
|
|
|
|
// -- Single-payload enum containing another single-payload enum as its
|
|
// payload.
|
|
// The representation takes extra inhabitants from the nested enum's payload
|
|
// that were unused by the nested enum.
|
|
// CHECK: %T4enum019SinglePayloadNestedD0O = type <{ [1 x i8] }>
|
|
|
|
// -- Multi-payload enum, no spare bits. The representation adds tag bits
|
|
// to discriminate payloads. No-payload cases all share a tag.
|
|
// case x(i8): X0 X1 X2 ... X7 X8 | 0 0
|
|
// case y(i7): Y0 Y1 Y2 ... Y7 0 | 1 0
|
|
// case z(i2): Z0 Z1 0 ... 0 0 | 0 1
|
|
// case a: 0 0 0 ... 0 0 | 1 1
|
|
// case b: 1 0 0 ... 0 0 | 1 1
|
|
// case c: 0 1 0 ... 0 0 | 1 1
|
|
// CHECK: %T4enum23MultiPayloadNoSpareBitsO = type <{ [8 x i8], [1 x i8] }>
|
|
|
|
// -- Multi-payload enum, one spare bit. The representation uses spare bits
|
|
// common to all payloads to partially discriminate payloads, with added
|
|
// tag bits to cover the gap. No-payload cases all share a tag.
|
|
// case x(i7): X0 X1 X2 X3 X4 X5 X6 0 | 0
|
|
// case y(i1): Y 0 0 0 0 0 0 1 | 0
|
|
// case z(i5): Z0 Z1 Z2 Z3 Z4 0 0 0 | 1
|
|
// case a: 0 0 0 0 0 0 0 1 | 1
|
|
// case b: 1 0 0 0 0 0 0 1 | 1
|
|
// case c: 0 1 0 0 0 0 0 1 | 1
|
|
// CHECK: %T4enum23MultiPayloadOneSpareBitO = type <{ [8 x i8], [1 x i8] }>
|
|
|
|
// -- Multi-payload enum, two spare bits. Same as above, except we have enough
|
|
// spare bits not to require any added tag bits.
|
|
// case x(i6): X0 X1 X2 X3 X4 X5 0 0
|
|
// case y(i1): Y 0 0 0 0 0 1 0
|
|
// case z(i5): Z0 Z1 Z2 Z3 Z4 0 0 1
|
|
// case a: 0 0 0 0 0 0 1 1
|
|
// case b: 1 0 0 0 0 0 1 1
|
|
// case c: 0 1 0 0 0 0 1 1
|
|
// CHECK: %T4enum24MultiPayloadTwoSpareBitsO = type <{ [8 x i8] }>
|
|
|
|
// CHECK-64: %T4enum30MultiPayloadSpareBitAggregatesO = type <{ [16 x i8] }>
|
|
|
|
// CHECK-64: %T4enum18MultiPayloadNestedO = type <{ [9 x i8] }>
|
|
// CHECK-32: %T4enum18MultiPayloadNestedO = type <{ [5 x i8] }>
|
|
|
|
// 32-bit object references don't have enough spare bits.
|
|
// CHECK-64: %T4enum27MultiPayloadNestedSpareBitsO = type <{ [8 x i8] }>
|
|
|
|
// -- Dynamic enums. The type layout is opaque; we dynamically bitcast to
|
|
// the element type.
|
|
// CHECK: %T4enum20DynamicSinglePayloadO = type <{}>
|
|
// CHECK: [[DYNAMIC_SINGLE_EMPTY_PAYLOAD:%T4enum20DynamicSinglePayloadOyytG]] = type <{ [1 x i8] }>
|
|
|
|
// -- Address-only multi-payload enums. We can't use spare bits.
|
|
// CHECK-64: %T4enum32MultiPayloadAddressOnlySpareBitsO = type <{ [16 x i8], [1 x i8] }>
|
|
// CHECK-32: %T4enum32MultiPayloadAddressOnlySpareBitsO = type <{ [8 x i8], [1 x i8] }>
|
|
|
|
// CHECK: [[DYNAMIC_SINGLETON:%T4enum16DynamicSingletonO.*]] = type <{}>
|
|
|
|
// CHECK: %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO = type <{ [1 x i8], [1 x i8] }>
|
|
|
|
// -- Dynamic metadata template carries a value witness table pattern
|
|
// we fill in on instantiation.
|
|
// FIXME: Strings should be unnamed_addr. rdar://problem/22674524
|
|
// CHECK: @"$s4enum16DynamicSingletonOWV" =
|
|
// CHECK-SAME: [[WORD]] 0,
|
|
// CHECK-SAME: [[WORD]] 0,
|
|
// 6291456 == 0x600000 (enum, incomplete)
|
|
// CHECK-SAME: i32 6291456,
|
|
// CHECK-SAME: i32 0,
|
|
// Enum witnesses.
|
|
// CHECK-SAME: i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwug" to i8*)
|
|
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, %swift.type*)* @"$s4enum16DynamicSingletonOwup" to i8*)
|
|
// CHECK-SAME: i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @"$s4enum16DynamicSingletonOwui" to i8*)
|
|
|
|
// CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private constant [17 x i8] c"DynamicSingleton\00"
|
|
// CHECK: @"$s4enum16DynamicSingletonOMn" = hidden constant <{
|
|
// CHECK-SAME: [17 x i8]* [[DYNAMICSINGLETON_NAME]]
|
|
// -- One payload
|
|
// CHECK-SAME: i32 1,
|
|
// -- No empty cases
|
|
// CHECK-SAME: i32 0,
|
|
// -- generic instantiation pattern
|
|
// CHECK-SAME: @"$s4enum16DynamicSingletonOMP"
|
|
// -- generic parameters, requirements, key, extra
|
|
// CHECK-SAME: i16 1, i16 0, i16 1, i16 0
|
|
// -- generic param
|
|
// CHECK-SAME: i8 -128,
|
|
// CHECK-SAME: }>
|
|
|
|
// CHECK: @"$s4enum16DynamicSingletonOMP" = internal constant <{ {{.*}} }> <{
|
|
// CHECK-SAME: @"$s4enum16DynamicSingletonOMi"
|
|
// CHECK-SAME: %swift.enum_vwtable* @"$s4enum16DynamicSingletonOWV"
|
|
|
|
// -- No-payload enums have extra inhabitants in
|
|
// their value witness table.
|
|
// CHECK: @"$s4enum10NoPayloadsOWV" = internal constant %swift.enum_vwtable {
|
|
// -- ...
|
|
// -- size
|
|
// CHECK-SAME: [[WORD]] 1,
|
|
// -- stride
|
|
// CHECK-SAME: [[WORD]] 1,
|
|
// -- flags (0x20_0000: alignment 1 and enum witnesses)
|
|
// CHECK-SAME: i32 2097152,
|
|
// -- num extra inhabitants (256 - 3 valid states)
|
|
// CHECK-SAME: i32 253,
|
|
// CHECK-SAME: }, align
|
|
|
|
// -- Single-payload enums take unused extra inhabitants from their payload
|
|
// as their own.
|
|
// CHECK: @"$s4enum19SinglePayloadNestedOWV" = internal constant %swift.enum_vwtable {
|
|
// -- ...
|
|
// -- size
|
|
// CHECK-SAME: [[WORD]] 1,
|
|
// -- stride
|
|
// CHECK-SAME: [[WORD]] 1,
|
|
// -- flags (0x20_0000: alignment 1 and enum witnesses)
|
|
// CHECK-SAME: i32 2097152,
|
|
// -- num extra inhabitants (253 from payload - 3 empty cases)
|
|
// CHECK-SAME: i32 250,
|
|
// CHECK-SAME: }
|
|
|
|
// CHECK: @"$s4enum20DynamicSinglePayloadOWV" = internal constant %swift.enum_vwtable {
|
|
// -- flags (0x60_0000: alignment 1, incomplete, enum witnesses)
|
|
// CHECK-SAME: i32 6291456,
|
|
// -- num extra inhabitants (253 from payload - 3 empty cases)
|
|
// CHECK-SAME: i32 0,
|
|
|
|
// CHECK: @"$s4enum20DynamicSinglePayloadOMP" = internal constant <{ {{.*}} }> <{
|
|
// CHECK-SAME: @"$s4enum20DynamicSinglePayloadOMi"
|
|
// CHECK-SAME: %swift.enum_vwtable* @"$s4enum20DynamicSinglePayloadOWV"
|
|
|
|
// CHECK: @"$s4enum18MultiPayloadNestedOWV" = internal constant %swift.enum_vwtable {
|
|
// -- size
|
|
// CHECK-32-SAME: [[WORD]] 5,
|
|
// CHECK-64-SAME: [[WORD]] 9,
|
|
// -- flags (0x250003: alignment 4, enum)
|
|
// -- flags (0x200007: alignment 8, enum)
|
|
// CHECK-32-SAME: i32 2097155,
|
|
// CHECK-64-SAME: i32 2097159,
|
|
// CHECK-SAME: }
|
|
|
|
enum Empty {}
|
|
|
|
enum EmptySingleton {
|
|
case foo
|
|
}
|
|
|
|
enum Singleton {
|
|
case value(Builtin.Int64, Builtin.Int64)
|
|
}
|
|
|
|
enum SingletonRef {
|
|
case value(Builtin.NativeObject)
|
|
}
|
|
|
|
enum DynamicSingleton<T> {
|
|
case value(T)
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch(i64, i64) {{.*}} {
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch(%T4enum9SingletonO* noalias nocapture dereferenceable(16)) {{.*}} {
|
|
sil @singleton_switch : $(Singleton) -> () {
|
|
// CHECK-64: entry:
|
|
// CHECK-32: entry:
|
|
entry(%u : $Singleton):
|
|
// CHECK-64: br label %[[DEST:[0-9]+]]
|
|
// CHECK-32: br label %[[DEST:[0-9]+]]
|
|
switch_enum %u : $Singleton, case #Singleton.value!enumelt.1: dest
|
|
|
|
// CHECK-64: ; <label>:[[DEST]]
|
|
// CHECK-32: ; <label>:[[DEST]]
|
|
dest:
|
|
// CHECK-64: ret void
|
|
// CHECK-32: ret void
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch_arg(i64, i64) {{.*}} {
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch_arg(%T4enum9SingletonO* noalias nocapture dereferenceable(16)) {{.*}} {
|
|
sil @singleton_switch_arg : $(Singleton) -> () {
|
|
// CHECK-64: entry:
|
|
// CHECK-32: entry:
|
|
entry(%u : $Singleton):
|
|
// CHECK-32: call %T4enum9SingletonO* @"$s4enum9SingletonOWOb"
|
|
// CHECK-64: br label %[[PREDEST:[0-9]+]]
|
|
// CHECK-32: br label %[[PREDEST:[0-9]+]]
|
|
switch_enum %u : $Singleton, case #Singleton.value!enumelt.1: dest
|
|
|
|
// CHECK-64: ; <label>:[[PREDEST]]
|
|
// CHECK-64: br label %[[DEST:[0-9]+]]
|
|
// CHECK-64: ; <label>:[[DEST]]
|
|
dest(%u2 : $(Builtin.Int64, Builtin.Int64)):
|
|
// CHECK-64: {{%.*}} = phi i64 [ %0, %[[PREDEST]] ]
|
|
// CHECK-64: {{%.*}} = phi i64 [ %1, %[[PREDEST]] ]
|
|
// CHECK-64: ret void
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_switch_indirect(%T4enum9SingletonO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: br label %[[DEST:[0-9]+]]
|
|
// CHECK: ; <label>:[[DEST]]
|
|
// CHECK: [[ADDR:%.*]] = bitcast %T4enum9SingletonO* %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-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i64 } @singleton_inject(i64, i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[A:%.*]] = insertvalue { i64, i64 } undef, i64 %0, 0
|
|
// CHECK-64: [[B:%.*]] = insertvalue { i64, i64 } [[A]], i64 %1, 1
|
|
// CHECK-64: ret { i64, i64 } [[B]]
|
|
// CHECK-64: }
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_inject(%T4enum9SingletonO* noalias nocapture sret, i64, i64) {{.*}} {
|
|
// CHECK-32: entry:
|
|
// CHECK-32: [[CAST:%.*]] = bitcast %T4enum9SingletonO* %0 to <{ i64, i64 }>*
|
|
// CHECK-32: [[GEP1:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[CAST]], i32 0, i32 0
|
|
// CHECK-32: store i64 %1, i64* [[GEP1]]
|
|
// CHECK-32: [[GEP2:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[CAST]], i32 0, i32 1
|
|
// CHECK-32: store i64 %2, i64* [[GEP2]]
|
|
// CHECK-32: ret void
|
|
// CHECK-32: }
|
|
sil @singleton_inject : $(Builtin.Int64, Builtin.Int64) -> Singleton {
|
|
entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
|
|
%t = tuple (%0 : $Builtin.Int64, %1 : $Builtin.Int64)
|
|
%u = enum $Singleton, #Singleton.value!enumelt.1, %t : $(Builtin.Int64, Builtin.Int64)
|
|
return %u : $Singleton
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @singleton_inject_indirect(i64, i64, %T4enum9SingletonO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: [[DATA_ADDR:%.*]] = bitcast %T4enum9SingletonO* %2 to <{ i64, i64 }>*
|
|
// CHECK: [[DATA_0_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 0
|
|
// CHECK: store i64 %0, i64* [[DATA_0_ADDR]]
|
|
// CHECK: [[DATA_1_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 1
|
|
// CHECK: store i64 %1, i64* [[DATA_1_ADDR]]
|
|
// CHECK: ret void
|
|
// CHECK: }
|
|
sil @singleton_inject_indirect : $(Builtin.Int64, Builtin.Int64, @inout Singleton) -> () {
|
|
entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64, %2 : $*Singleton):
|
|
%t = tuple (%0 : $Builtin.Int64, %1 : $Builtin.Int64)
|
|
%a = init_enum_data_addr %2 : $*Singleton, #Singleton.value!enumelt.1
|
|
store %t to %a : $*(Builtin.Int64, Builtin.Int64)
|
|
inject_enum_addr %2 : $*Singleton, #Singleton.value!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
|
|
enum NoPayloads {
|
|
case x
|
|
case y
|
|
case z
|
|
}
|
|
|
|
sil @a : $@convention(thin) () -> ()
|
|
sil @b : $@convention(thin) () -> ()
|
|
sil @c : $@convention(thin) () -> ()
|
|
sil @d : $@convention(thin) () -> ()
|
|
sil @e : $@convention(thin) () -> ()
|
|
sil @f : $@convention(thin) () -> ()
|
|
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_switch(i8) {{.*}} {
|
|
sil @no_payload_switch : $@convention(thin) (NoPayloads) -> () {
|
|
// CHECK: entry:
|
|
entry(%u : $NoPayloads):
|
|
// CHECK: switch i8 %0, label %[[DFLT:[0-9]+]] [
|
|
// CHECK: i8 0, label %[[X_DEST:[0-9]+]]
|
|
// CHECK: i8 1, label %[[Y_DEST:[0-9]+]]
|
|
// CHECK: i8 2, label %[[Z_DEST:[0-9]+]]
|
|
// CHECK: ]
|
|
// CHECK: ; <label>:[[DFLT]]
|
|
// CHECK: unreachable
|
|
switch_enum %u : $NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest
|
|
|
|
// CHECK: ; <label>:[[X_DEST]]
|
|
// CHECK: call swiftcc void @a()
|
|
// CHECK: br label %[[END:[0-9]+]]
|
|
x_dest:
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
br end
|
|
// CHECK: ; <label>:[[Y_DEST]]
|
|
// CHECK: call swiftcc void @b()
|
|
// CHECK: br label %[[END]]
|
|
y_dest:
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
br end
|
|
// CHECK: ; <label>:[[Z_DEST]]
|
|
// CHECK: call swiftcc void @c()
|
|
// CHECK: br label %[[END]]
|
|
z_dest:
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[END]]
|
|
// CHECK: ret void
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_switch_indirect(%T4enum10NoPayloadsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
sil @no_payload_switch_indirect : $@convention(thin) (@inout NoPayloads) -> () {
|
|
entry(%u : $*NoPayloads):
|
|
// CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds %T4enum10NoPayloadsO, %T4enum10NoPayloadsO* %0, i32 0, i32 0
|
|
// CHECK: [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]]
|
|
// CHECK: switch i8 [[TAG]]
|
|
switch_enum_addr %u : $*NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest
|
|
|
|
x_dest:
|
|
br end
|
|
y_dest:
|
|
br end
|
|
z_dest:
|
|
br end
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8 @no_payload_inject_x() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret i8 0
|
|
// CHECK: }
|
|
sil @no_payload_inject_x : $() -> NoPayloads {
|
|
entry:
|
|
%u = enum $NoPayloads, #NoPayloads.x!enumelt
|
|
return %u : $NoPayloads
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8 @no_payload_inject_y() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret i8 1
|
|
// CHECK: }
|
|
sil @no_payload_inject_y : $() -> NoPayloads {
|
|
entry:
|
|
%u = enum $NoPayloads, #NoPayloads.y!enumelt
|
|
return %u : $NoPayloads
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8 @no_payload_inject_z() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret i8 2
|
|
// CHECK: }
|
|
sil @no_payload_inject_z : $() -> NoPayloads {
|
|
entry:
|
|
%u = enum $NoPayloads, #NoPayloads.z!enumelt
|
|
return %u : $NoPayloads
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_inject_z_indirect(%T4enum10NoPayloadsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: [[TAG_ADDR:%.*]] = getelementptr inbounds %T4enum10NoPayloadsO, %T4enum10NoPayloadsO* %0, i32 0, i32 0
|
|
// CHECK: store i8 2, i8* [[TAG_ADDR]]
|
|
// CHECK: ret void
|
|
// CHECK: }
|
|
sil @no_payload_inject_z_indirect : $(@inout NoPayloads) -> () {
|
|
entry(%0 : $*NoPayloads):
|
|
inject_enum_addr %0 : $*NoPayloads, #NoPayloads.z!enumelt
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
|
|
enum NoPayloads2 {
|
|
case a
|
|
case e
|
|
case i
|
|
case o
|
|
case u
|
|
case y
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @no_payload_switch_2(i8) {{.*}} {
|
|
sil @no_payload_switch_2 : $@convention(thin) (NoPayloads2) -> () {
|
|
// CHECK: entry:
|
|
entry(%u : $NoPayloads2):
|
|
// CHECK: [[COND:%.*]] = icmp ne i8 %0, 4
|
|
// CHECK: br i1 [[COND]], label %[[DEFAULT_DEST:[0-9]+]], label %[[U_DEST:[0-9]+]]
|
|
switch_enum %u : $NoPayloads2, case #NoPayloads2.u!enumelt: u_dest, default default_dest
|
|
|
|
// CHECK: ; <label>:[[U_DEST]]
|
|
u_dest:
|
|
// CHECK: call swiftcc void @a()
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
// CHECK: br label %[[END:[0-9]+]]
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[DEFAULT_DEST]]
|
|
default_dest:
|
|
// CHECK: call swiftcc void @b()
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
// CHECK: br label %[[END]]
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[END]]
|
|
end:
|
|
// CHECK: ret void
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
|
|
enum SinglePayloadNoXI {
|
|
case x(Builtin.Word)
|
|
case y
|
|
}
|
|
|
|
enum SinglePayloadNoXI2 {
|
|
case x(Builtin.Word)
|
|
case y
|
|
case z
|
|
case w
|
|
case v
|
|
case u
|
|
}
|
|
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @select_enum([[WORD:i32]], i8)
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @select_enum([[WORD:i64]], i8)
|
|
// CHECK: entry:
|
|
// CHECK: [[TAG:%.*]] = trunc i8 %1 to i1
|
|
// CHECK: [[PAYLOAD:%.*]] = icmp eq [[WORD]] %0, 1
|
|
// CHECK: [[MATCHES:%.*]] = and i1 [[TAG]], [[PAYLOAD]]
|
|
// CHECK: [[RES:%.*]] = select i1 [[MATCHES]], i1 false, i1 true
|
|
// CHECK: ret i1 [[RES]]
|
|
// CHECK: }
|
|
|
|
sil @select_enum : $@convention(method) (SinglePayloadNoXI2) -> Builtin.Int1 {
|
|
bb0(%0 : $SinglePayloadNoXI2):
|
|
%2 = integer_literal $Builtin.Int1, 0
|
|
%3 = integer_literal $Builtin.Int1, -1
|
|
%4 = select_enum %0 : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.z!enumelt: %2, default %3 : $Builtin.Int1
|
|
return %4 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_switch([[WORD:i64]], i8) {{.*}} {
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_switch([[WORD:i32]], i8) {{.*}} {
|
|
sil @single_payload_no_xi_switch : $@convention(thin) (SinglePayloadNoXI2) -> () {
|
|
// CHECK: entry:
|
|
entry(%u : $SinglePayloadNoXI2):
|
|
// CHECK; %2 = trunc i8
|
|
// CHECK: br i1 %2, label %[[TAGS:[0-9]+]], label %[[X_DEST:[0-9]+]]
|
|
// CHECK: ; <label>:[[TAGS]]
|
|
// CHECK: switch [[WORD]] %0, label %[[DFLT:[0-9]+]] [
|
|
// CHECK: [[WORD]] 0, label %[[Y_DEST:[0-9]+]]
|
|
// CHECK: [[WORD]] 1, label %[[Z_DEST:[0-9]+]]
|
|
// CHECK: [[WORD]] 2, label %[[W_DEST:[0-9]+]]
|
|
// CHECK: [[WORD]] 3, label %[[V_DEST:[0-9]+]]
|
|
// CHECK: [[WORD]] 4, label %[[U_DEST:[0-9]+]]
|
|
// CHECK: ]
|
|
// CHECK: ; <label>:[[DFLT]]
|
|
// CHECK: unreachable
|
|
switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt.1: x_dest, case #SinglePayloadNoXI2.y!enumelt: y_dest, case #SinglePayloadNoXI2.z!enumelt: z_dest, case #SinglePayloadNoXI2.w!enumelt: w_dest, case #SinglePayloadNoXI2.v!enumelt: v_dest, case #SinglePayloadNoXI2.u!enumelt: u_dest
|
|
|
|
|
|
// CHECK: ; <label>:[[X_DEST]]
|
|
// CHECK: call swiftcc void @a()
|
|
// CHECK: br label %[[END:[0-9]+]]
|
|
x_dest:
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[Y_DEST]]
|
|
// CHECK: call swiftcc void @b()
|
|
// CHECK: br label %[[END]]
|
|
y_dest:
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[Z_DEST]]
|
|
// CHECK: call swiftcc void @c()
|
|
// CHECK: br label %[[END]]
|
|
z_dest:
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[W_DEST]]
|
|
// CHECK: call swiftcc void @a()
|
|
// CHECK: br label %[[END:[0-9]+]]
|
|
w_dest:
|
|
%d = function_ref @a : $@convention(thin) () -> ()
|
|
apply %d() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[V_DEST]]
|
|
// CHECK: call swiftcc void @b()
|
|
// CHECK: br label %[[END]]
|
|
v_dest:
|
|
%e = function_ref @b : $@convention(thin) () -> ()
|
|
apply %e() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[U_DEST]]
|
|
// CHECK: call swiftcc void @c()
|
|
// CHECK: br label %[[END]]
|
|
u_dest:
|
|
%f = function_ref @c : $@convention(thin) () -> ()
|
|
apply %f() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[END]]
|
|
// CHECK: ret void
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_switch_arg([[WORD]], i8) {{.*}} {
|
|
sil @single_payload_no_xi_switch_arg : $@convention(thin) (SinglePayloadNoXI2) -> () {
|
|
// CHECK: entry:
|
|
entry(%u : $SinglePayloadNoXI2):
|
|
// CHECK: %2 = trunc i8
|
|
// CHECK: br i1 %2, label %[[TAGS:[0-9]+]], label %[[X_PREDEST:[0-9]+]]
|
|
// CHECK: ; <label>:[[TAGS]]
|
|
// CHECK: switch [[WORD]] %0, label %[[DFLT:[0-9]+]] [
|
|
// CHECK: [[WORD]] 0, label %[[Y_DEST:[0-9]+]]
|
|
// CHECK: [[WORD]] 1, label %[[Z_DEST:[0-9]+]]
|
|
// CHECK: [[WORD]] 2, label %[[SPLITEDGE:[0-9]+]]
|
|
// CHECK: [[WORD]] 3, label %[[SPLITEDGE]]
|
|
// CHECK: [[WORD]] 4, label %[[SPLITEDGE]]
|
|
// CHECK: ]
|
|
// CHECK: ; <label>:[[DFLT]]
|
|
// CHECK: unreachable
|
|
switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt.1: x_dest, case #SinglePayloadNoXI2.y!enumelt: y_dest, case #SinglePayloadNoXI2.z!enumelt: z_dest, default default_dest
|
|
|
|
// CHECK: ; <label>:[[X_PREDEST]]
|
|
// CHECK: br label %[[X_DEST:[0-9]+]]
|
|
// CHECK: ; <label>:[[X_DEST]]
|
|
// CHECK: {{%.*}} = phi [[WORD]] [ %0, %[[X_PREDEST]] ]
|
|
x_dest(%u2 : $Builtin.Word):
|
|
// CHECK: call swiftcc void @a()
|
|
// CHECK: br label %[[END]]
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[Y_DEST]]
|
|
y_dest:
|
|
// CHECK: call swiftcc void @b()
|
|
// CHECK: br label %[[END]]
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[Z_DEST]]
|
|
z_dest:
|
|
// CHECK: call swiftcc void @c()
|
|
// CHECK: br label %[[END]]
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[SPLITEDGE]]
|
|
// CHECK: br label %[[END:[0-9]+]]
|
|
default_dest:
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[END]]
|
|
// CHECK: ret void
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], i8 } @single_payload_no_xi_inject_x([[WORD]]) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: [[A:%.*]] = insertvalue { [[WORD]], i8 } undef, [[WORD]] %0, 0
|
|
// CHECK: [[B:%.*]] = insertvalue { [[WORD]], i8 } [[A]], i8 0, 1
|
|
// CHECK: ret { [[WORD]], i8 } [[B]]
|
|
// CHECK: }
|
|
sil @single_payload_no_xi_inject_x : $(Builtin.Word) -> SinglePayloadNoXI2 {
|
|
entry(%0 : $Builtin.Word):
|
|
%u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1, %0 : $Builtin.Word
|
|
return %u : $SinglePayloadNoXI2
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_inject_x_indirect([[WORD]], %T4enum18SinglePayloadNoXI2O* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: [[DATA_ADDR:%.*]] = bitcast %T4enum18SinglePayloadNoXI2O* %1 to [[WORD]]*
|
|
// CHECK: store [[WORD]] %0, [[WORD]]* [[DATA_ADDR]]
|
|
// CHECK: [[T0:%.*]] = getelementptr inbounds %T4enum18SinglePayloadNoXI2O, %T4enum18SinglePayloadNoXI2O* %1, i32 0, i32 1
|
|
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
|
|
// CHECK: store i1 false, i1* [[TAG_ADDR]]
|
|
// CHECK: ret void
|
|
// CHECK: }
|
|
sil @single_payload_no_xi_inject_x_indirect : $(Builtin.Word, @inout SinglePayloadNoXI2) -> () {
|
|
entry(%0 : $Builtin.Word, %1 : $*SinglePayloadNoXI2):
|
|
%a = init_enum_data_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1
|
|
store %0 to %a : $*Builtin.Word
|
|
inject_enum_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], i8 } @single_payload_no_xi_inject_y() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret { [[WORD]], i8 } { [[WORD]] 0, i8 1 }
|
|
// CHECK: }
|
|
sil @single_payload_no_xi_inject_y : $() -> SinglePayloadNoXI2 {
|
|
entry:
|
|
%u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt
|
|
return %u : $SinglePayloadNoXI2
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_no_xi_inject_y_indirect(%T4enum18SinglePayloadNoXI2O* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum18SinglePayloadNoXI2O* %0 to [[WORD]]*
|
|
// CHECK: store [[WORD]] 0, [[WORD]]* [[PAYLOAD_ADDR]]
|
|
// CHECK: [[T0:%.*]] = getelementptr inbounds %T4enum18SinglePayloadNoXI2O, %T4enum18SinglePayloadNoXI2O* %0, i32 0, i32 1
|
|
// CHECK: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
|
|
// CHECK: store i1 true, i1* [[TAG_ADDR]]
|
|
// CHECK: ret void
|
|
// CHECK: }
|
|
sil @single_payload_no_xi_inject_y_indirect : $(@inout SinglePayloadNoXI2) -> () {
|
|
entry(%0 : $*SinglePayloadNoXI2):
|
|
inject_enum_addr %0 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], i8 } @single_payload_no_xi_inject_z() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret { [[WORD]], i8 } { [[WORD]] 1, i8 1 }
|
|
// CHECK: }
|
|
sil @single_payload_no_xi_inject_z : $() -> SinglePayloadNoXI2 {
|
|
entry:
|
|
%u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.z!enumelt
|
|
return %u : $SinglePayloadNoXI2
|
|
}
|
|
|
|
|
|
// -- Test packing and unpacking aggregates.
|
|
|
|
enum AggregateSinglePayload {
|
|
case x(Builtin.Word, Builtin.Word)
|
|
case y
|
|
case z
|
|
}
|
|
|
|
sil @int21_sink : $@convention(thin) (Builtin.Int21) -> ()
|
|
sil @int64_sink : $@convention(thin) (Builtin.Word) -> ()
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack
|
|
// CHECK: ([[WORD]], [[WORD]], i8) {{.*}} {
|
|
sil @aggregate_single_payload_unpack : $@convention(thin) (AggregateSinglePayload) -> () {
|
|
entry(%u : $AggregateSinglePayload):
|
|
switch_enum %u : $AggregateSinglePayload, case #AggregateSinglePayload.x!enumelt.1: x_dest, default default_dest
|
|
|
|
// CHECK: [[FIRST:%.*]] = phi [[WORD]] [ %0
|
|
// CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1
|
|
// CHECK: call swiftcc void @int64_sink([[WORD]] [[FIRST]])
|
|
// CHECK: call swiftcc void @int64_sink([[WORD]] [[SECOND]])
|
|
x_dest(%v : $(Builtin.Word, Builtin.Word)):
|
|
%f = function_ref @int64_sink : $@convention(thin) (Builtin.Word) -> ()
|
|
%a = tuple_extract %v : $(Builtin.Word, Builtin.Word), 0
|
|
%b = tuple_extract %v : $(Builtin.Word, Builtin.Word), 1
|
|
%c = apply %f(%a) : $@convention(thin) (Builtin.Word) -> ()
|
|
%d = apply %f(%b) : $@convention(thin) (Builtin.Word) -> ()
|
|
br end
|
|
|
|
default_dest:
|
|
br end
|
|
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]] } @aggregate_single_payload_unsafe_unpack([[WORD]], [[WORD]], i8) {{.*}} {
|
|
// CHECK: [[A:%.*]] = insertvalue { [[WORD]], [[WORD]] } undef, [[WORD]] %0, 0
|
|
// CHECK: [[B:%.*]] = insertvalue { [[WORD]], [[WORD]] } [[A]], [[WORD]] %1, 1
|
|
// CHECK: ret { [[WORD]], [[WORD]] } [[B]]
|
|
sil @aggregate_single_payload_unsafe_unpack : $@convention(thin) (AggregateSinglePayload) -> (Builtin.Word, Builtin.Word) {
|
|
entry(%u : $AggregateSinglePayload):
|
|
%x = unchecked_enum_data %u : $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1
|
|
return %x : $(Builtin.Word, Builtin.Word)
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]], i8 } @aggregate_single_payload_inject([[WORD]], [[WORD]]) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: [[RES_0:%.*]] = insertvalue { [[WORD]], [[WORD]], i8 } undef, [[WORD]] %0, 0
|
|
// CHECK: [[RES_1:%.*]] = insertvalue { [[WORD]], [[WORD]], i8 } [[RES_0]], [[WORD]] %1, 1
|
|
// CHECK: [[RES:%.*]] = insertvalue { [[WORD]], [[WORD]], i8 } [[RES_1]], i8 0, 2
|
|
// CHECK: ret { [[WORD]], [[WORD]], i8 } [[RES]]
|
|
// CHECK: }
|
|
sil @aggregate_single_payload_inject : $(Builtin.Word, Builtin.Word) -> AggregateSinglePayload {
|
|
entry(%0 : $Builtin.Word, %1 : $Builtin.Word):
|
|
%t = tuple (%0 : $Builtin.Word, %1 : $Builtin.Word)
|
|
%u = enum $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1, %t : $(Builtin.Word, Builtin.Word)
|
|
return %u : $AggregateSinglePayload
|
|
}
|
|
|
|
struct CharLike { var value : Builtin.Int21 }
|
|
struct IntLike { var value : Builtin.Word }
|
|
struct RangeLike { var from, to : Builtin.Word }
|
|
|
|
enum AggregateSinglePayload2 {
|
|
case x(CharLike, IntLike, RangeLike)
|
|
case y
|
|
case z
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack_2([[WORD]], [[WORD]], [[WORD]], [[WORD]]) {{.*}} {
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack_2(%T4enum23AggregateSinglePayload2O* noalias nocapture dereferenceable(16)) {{.*}} {
|
|
sil @aggregate_single_payload_unpack_2 : $@convention(thin) (AggregateSinglePayload2) -> () {
|
|
entry(%u : $AggregateSinglePayload2):
|
|
switch_enum %u : $AggregateSinglePayload2, case #AggregateSinglePayload2.x!enumelt.1: x_dest, default default_dest
|
|
|
|
// CHECK-64: [[TRUNC:%.*]] = trunc [[WORD]] %0 to i21
|
|
// CHECK-64: phi i21 [ [[TRUNC]]
|
|
// CHECK-64: phi [[WORD]] [ %1
|
|
// CHECK-64: phi [[WORD]] [ %2
|
|
// CHECK-64: phi [[WORD]] [ %3
|
|
x_dest(%v : $(CharLike, IntLike, RangeLike)):
|
|
br end
|
|
|
|
default_dest:
|
|
br end
|
|
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } @aggregate_single_payload_2_inject(i32, [[WORD]], [[WORD]], [[WORD]]) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: %4 = trunc i32 %0 to i21
|
|
// CHECK-64: %5 = zext i21 %4 to [[WORD]]
|
|
// CHECK-64: %6 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } undef, [[WORD]] %5, 0
|
|
// CHECK-64: %7 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %6, [[WORD]] %1, 1
|
|
// CHECK-64: %8 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %7, [[WORD]] %2, 2
|
|
// CHECK-64: %9 = insertvalue { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %8, [[WORD]] %3, 3
|
|
// CHECK-64: ret { [[WORD]], [[WORD]], [[WORD]], [[WORD]] } %9
|
|
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_2_inject(%T4enum23AggregateSinglePayload2O* noalias nocapture sret, i32, i32, i32, i32) {{.*}} {
|
|
// CHECK-32: [[TRUNC:%.*]] = trunc i32 %1 to i21
|
|
// CHECK-32: [[ZEXT:%.*]] = zext i21 [[TRUNC]] to i32
|
|
// CHECK-32: [[CAST:%.*]] = bitcast %T4enum23AggregateSinglePayload2O* %0 to { i32, i32, i32, i32 }*
|
|
// CHECK-32: [[GEP:%.*]] = getelementptr inbounds {{.*}} [[CAST]], i32 0, i32 0
|
|
// CHECK-32: store i32 [[ZEXT]], i32* [[GEP]]
|
|
// CHECK-32: store i32 %2, i32*
|
|
// CHECK-32: store i32 %3, i32*
|
|
// CHECK-32: store i32 %4, i32*
|
|
// CHECK-32: ret void
|
|
sil @aggregate_single_payload_2_inject : $(CharLike, IntLike, RangeLike) -> AggregateSinglePayload2 {
|
|
entry(%0 : $CharLike, %1 : $IntLike, %2 : $RangeLike):
|
|
%t = tuple (%0 : $CharLike, %1 : $IntLike, %2 : $RangeLike)
|
|
%u = enum $AggregateSinglePayload2, #AggregateSinglePayload2.x!enumelt.1, %t : $(CharLike, IntLike, RangeLike)
|
|
return %u : $AggregateSinglePayload2
|
|
}
|
|
|
|
enum AggregateSinglePayload3 {
|
|
case x(Builtin.Int21, Builtin.Word)
|
|
case y
|
|
case z
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @aggregate_single_payload_unpack_3([[WORD]], [[WORD]]) {{.*}} {
|
|
sil @aggregate_single_payload_unpack_3 : $@convention(thin) (AggregateSinglePayload3) -> () {
|
|
entry(%u : $AggregateSinglePayload3):
|
|
switch_enum %u : $AggregateSinglePayload3, case #AggregateSinglePayload3.x!enumelt.1: x_dest, default default_dest
|
|
|
|
// CHECK: [[TRUNC:%.*]] = trunc [[WORD]] %0 to i21
|
|
// CHECK: [[FIRST:%.*]] = phi i21 [ [[TRUNC]]
|
|
// CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1
|
|
// CHECK: [[ZEXT:%.*]] = zext i21 [[FIRST]] to i32
|
|
// CHECK: call swiftcc void @int21_sink(i32 [[ZEXT]])
|
|
// CHECK: call swiftcc void @int64_sink([[WORD]] [[SECOND]])
|
|
x_dest(%v : $(Builtin.Int21, Builtin.Word)):
|
|
%f = function_ref @int21_sink : $@convention(thin) (Builtin.Int21) -> ()
|
|
%g = function_ref @int64_sink : $@convention(thin) (Builtin.Word) -> ()
|
|
%a = tuple_extract %v : $(Builtin.Int21, Builtin.Word), 0
|
|
%b = tuple_extract %v : $(Builtin.Int21, Builtin.Word), 1
|
|
%c = apply %f(%a) : $@convention(thin) (Builtin.Int21) -> ()
|
|
%d = apply %g(%b) : $@convention(thin) (Builtin.Word) -> ()
|
|
br end
|
|
|
|
default_dest:
|
|
br end
|
|
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]] } @aggregate_single_payload_inject_x3(i32, [[WORD]]) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: [[TRUNC:%.*]] = trunc i32 %0 to i21
|
|
// CHECK: [[ZEXT:%.*]] = zext i21 [[TRUNC]] to [[WORD]]
|
|
// CHECK: [[A:%.*]] = insertvalue { [[WORD]], [[WORD]] } undef, [[WORD]] [[ZEXT]], 0
|
|
// CHECK: [[B:%.*]] = insertvalue { [[WORD]], [[WORD]] } [[A]], [[WORD]] %1, 1
|
|
// CHECK: ret { [[WORD]], [[WORD]] } [[B]]
|
|
// CHECK: }
|
|
sil @aggregate_single_payload_inject_x3 : $(Builtin.Int21, Builtin.Word) -> AggregateSinglePayload3 {
|
|
entry(%0 : $Builtin.Int21, %1 : $Builtin.Word):
|
|
%t = tuple (%0 : $Builtin.Int21, %1 : $Builtin.Word)
|
|
%u = enum $AggregateSinglePayload3, #AggregateSinglePayload3.x!enumelt.1, %t : $(Builtin.Int21, Builtin.Word)
|
|
return %u : $AggregateSinglePayload3
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc { [[WORD]], [[WORD]] } @aggregate_single_payload_inject_y3() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret { [[WORD]], [[WORD]] } { [[WORD]] 2097152, [[WORD]] 0 }
|
|
// CHECK: }
|
|
// 2097152 == 0x200000
|
|
sil @aggregate_single_payload_inject_y3 : $() -> AggregateSinglePayload3 {
|
|
entry:
|
|
%u = enum $AggregateSinglePayload3, #AggregateSinglePayload3.y!enumelt
|
|
return %u : $AggregateSinglePayload3
|
|
}
|
|
|
|
enum SinglePayloadSpareBit {
|
|
case x(Builtin.Int63)
|
|
case y
|
|
case z
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_switch(i64) {{.*}} {
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_switch(i32, i32) {{.*}} {
|
|
sil @single_payload_spare_bit_switch : $@convention(thin) (SinglePayloadSpareBit) -> () {
|
|
// CHECK: entry:
|
|
entry(%u : $SinglePayloadSpareBit):
|
|
// CHECK: switch i64 %{{[0-9]+}}, label %[[X_DEST:[0-9]+]] [
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK: i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]]
|
|
// -- 0x8000_0000_0000_0001
|
|
// CHECK: i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]]
|
|
// CHECK: ]
|
|
switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest
|
|
|
|
// CHECK: ; <label>:[[X_DEST]]
|
|
x_dest:
|
|
// CHECK: call swiftcc void @a()
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
// CHECK: br label %[[END:[0-9]+]]
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[Y_DEST]]
|
|
y_dest:
|
|
// CHECK: call swiftcc void @b()
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
// CHECK: br label %[[END]]
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[Z_DEST]]
|
|
z_dest:
|
|
// CHECK: call swiftcc void @c()
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
// CHECK: br label %[[END]]
|
|
br end
|
|
|
|
// CHECK: ; <label>:[[END]]
|
|
end:
|
|
// CHECK: ret void
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_switch_arg(i64) {{.*}} {
|
|
sil @single_payload_spare_bit_switch_arg : $@convention(thin) (SinglePayloadSpareBit) -> () {
|
|
// CHECK: entry:
|
|
entry(%u : $SinglePayloadSpareBit):
|
|
// CHECK-64: switch i64 %0, label %[[X_PREDEST:[0-9]+]] [
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]]
|
|
// -- 0x8000_0000_0000_0001
|
|
// CHECK-64: i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]]
|
|
// CHECK-64: ]
|
|
switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest
|
|
|
|
// CHECK-64: ; <label>:[[X_PREDEST]]
|
|
// CHECK-64: [[TRUNC_PAYLOAD:%.*]] = trunc i64 %0 to i63
|
|
// CHECK-64: br label %[[X_DEST:[0-9]+]]
|
|
// CHECK-64: ; <label>:[[X_DEST]]
|
|
// CHECK-64: {{%.*}} = phi i63 [ [[TRUNC_PAYLOAD]], %[[X_PREDEST]] ]
|
|
x_dest(%u2 : $Builtin.Int63):
|
|
// CHECK-64: call swiftcc void @a()
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
// CHECK-64: br label %[[END:[0-9]+]]
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Y_DEST]]
|
|
y_dest:
|
|
// CHECK-64: call swiftcc void @b()
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
// CHECK-64: br label %[[END]]
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Z_DEST]]
|
|
z_dest:
|
|
// CHECK-64: call swiftcc void @c()
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
// CHECK-64: br label %[[END]]
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[END]]
|
|
end:
|
|
// CHECK-64: ret void
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
sil @single_payload_spare_bit_switch_indirect : $@convention(thin) (@inout SinglePayloadSpareBit) -> () {
|
|
entry(%u : $*SinglePayloadSpareBit):
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %0 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: switch i64 [[PAYLOAD]]
|
|
switch_enum_addr %u : $*SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest
|
|
|
|
// CHECK-64: ; <label>:
|
|
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %0 to i63*
|
|
x_dest:
|
|
%u2 = unchecked_take_enum_data_addr %u : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
y_dest:
|
|
br end
|
|
|
|
z_dest:
|
|
br end
|
|
|
|
end:
|
|
%x = tuple ()
|
|
return %x : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @single_payload_spare_bit_inject_x(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[T:%.*]] = trunc i64 %0 to i63
|
|
// CHECK-64: [[A:%.*]] = zext i63 [[T]] to i64
|
|
// CHECK-64: ret i64 [[A]]
|
|
// CHECK-64: }
|
|
sil @single_payload_spare_bit_inject_x : $(Builtin.Int63) -> SinglePayloadSpareBit {
|
|
entry(%0 : $Builtin.Int63):
|
|
%u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1, %0 : $Builtin.Int63
|
|
return %u : $SinglePayloadSpareBit
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_x_indirect(i64, %T4enum21SinglePayloadSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[T:%.*]] = trunc i64 %0 to i63
|
|
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %1 to i63*
|
|
// CHECK-64: store i63 [[T]], i63* [[DATA_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () {
|
|
entry(%0 : $Builtin.Int63, %1 : $*SinglePayloadSpareBit):
|
|
%a = init_enum_data_addr %1 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1
|
|
store %0 to %a : $*Builtin.Int63
|
|
inject_enum_addr %1 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @single_payload_spare_bit_inject_y() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: ret i64 -9223372036854775808
|
|
// CHECK-64: }
|
|
sil @single_payload_spare_bit_inject_y : $() -> SinglePayloadSpareBit {
|
|
entry:
|
|
%u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.y!enumelt
|
|
return %u : $SinglePayloadSpareBit
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_spare_bit_inject_y_indirect(%T4enum21SinglePayloadSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum21SinglePayloadSpareBitO* %0 to i64*
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @single_payload_spare_bit_inject_y_indirect : $(@inout SinglePayloadSpareBit) -> () {
|
|
entry(%0 : $*SinglePayloadSpareBit):
|
|
inject_enum_addr %0 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.y!enumelt
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @single_payload_spare_bit_inject_z() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// 0x8000_0000_0000_0001
|
|
// CHECK-64: ret i64 -9223372036854775807
|
|
// CHECK-64: }
|
|
sil @single_payload_spare_bit_inject_z : $() -> SinglePayloadSpareBit {
|
|
entry:
|
|
%u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.z!enumelt
|
|
return %u : $SinglePayloadSpareBit
|
|
}
|
|
|
|
enum SinglePayloadNested {
|
|
case a(NoPayloads)
|
|
case b
|
|
case c
|
|
case d
|
|
}
|
|
|
|
enum SinglePayloadNestedNested {
|
|
case e(SinglePayloadNested)
|
|
case f
|
|
case g
|
|
case h
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_nested_switch(i8) {{.*}} {
|
|
sil @single_payload_nested_switch : $(SinglePayloadNestedNested) -> () {
|
|
entry(%u : $SinglePayloadNestedNested):
|
|
// CHECK: switch i8 {{%.*}}, label {{%.*}} [
|
|
// CHECK: i8 6, label {{%.*}}
|
|
// CHECK: i8 7, label {{%.*}}
|
|
// CHECK: i8 8, label {{%.*}}
|
|
// CHECK: ]
|
|
switch_enum %u : $SinglePayloadNestedNested, case #SinglePayloadNestedNested.e!enumelt.1: e_dest, case #SinglePayloadNestedNested.f!enumelt: f_dest, case #SinglePayloadNestedNested.g!enumelt: g_dest, case #SinglePayloadNestedNested.h!enumelt: h_dest
|
|
|
|
e_dest(%v : $SinglePayloadNested):
|
|
// CHECK: switch i8 {{%.*}}, label {{%.*}} [
|
|
// CHECK: i8 3, label {{%.*}}
|
|
// CHECK: i8 4, label {{%.*}}
|
|
// CHECK: i8 5, label {{%.*}}
|
|
// CHECK: ]
|
|
switch_enum %v : $SinglePayloadNested, case #SinglePayloadNested.a!enumelt.1: a_dest, case #SinglePayloadNested.b!enumelt: b_dest, case #SinglePayloadNested.c!enumelt: c_dest, case #SinglePayloadNested.d!enumelt: d_dest
|
|
f_dest:
|
|
br end
|
|
g_dest:
|
|
br end
|
|
h_dest:
|
|
br end
|
|
|
|
a_dest(%w : $NoPayloads):
|
|
// CHECK: switch i8 {{%.*}}, label {{%.*}} [
|
|
// CHECK: i8 0, label {{%.*}}
|
|
// CHECK: i8 1, label {{%.*}}
|
|
// CHECK: i8 2, label {{%.*}}
|
|
// CHECK: ]
|
|
switch_enum %w : $NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest
|
|
b_dest:
|
|
br end
|
|
c_dest:
|
|
br end
|
|
d_dest:
|
|
br end
|
|
|
|
x_dest:
|
|
br end
|
|
y_dest:
|
|
br end
|
|
z_dest:
|
|
br end
|
|
|
|
end:
|
|
%x = tuple()
|
|
return %x : $()
|
|
}
|
|
|
|
class C {}
|
|
sil_vtable C {}
|
|
|
|
sil @$s4enum1CCfD : $@convention(method) (C) -> ()
|
|
|
|
enum SinglePayloadClass {
|
|
case x(C)
|
|
case y
|
|
case z
|
|
case w
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_switch(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: switch i64 %0, label {{%.*}} [
|
|
// CHECK-64: i64 0, label {{%.*}}
|
|
// CHECK-objc-64-simulator-false: i64 2, label {{%.*}}
|
|
// CHECK-objc-64-simulator-false: i64 4, label {{%.*}}
|
|
// CHECK-objc-64-simulator-true: i64 1, label {{%.*}}
|
|
// CHECK-objc-64-simulator-true: i64 2, label {{%.*}}
|
|
// CHECK-native-64: i64 1, label {{%.*}}
|
|
// CHECK-native-64: i64 2, label {{%.*}}
|
|
// CHECK-64: ]
|
|
// CHECK-64: ; <label>
|
|
// CHECK-64: inttoptr [[WORD]] %0 to %T4enum1CC*
|
|
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_switch(i32) {{.*}} {
|
|
// CHECK-32: entry:
|
|
// CHECK-32: switch i32 %0, label {{%.*}} [
|
|
// CHECK-32: i32 0, label {{%.*}}
|
|
// CHECK-32: i32 1, label {{%.*}}
|
|
// CHECK-32: i32 2, label {{%.*}}
|
|
// CHECK-32: ]
|
|
// CHECK-32: ; <label>
|
|
// CHECK-32: inttoptr [[WORD]] %0 to %T4enum1CC*
|
|
|
|
sil @single_payload_class_switch : $(SinglePayloadClass) -> () {
|
|
entry(%c : $SinglePayloadClass):
|
|
switch_enum %c : $SinglePayloadClass, case #SinglePayloadClass.x!enumelt.1: x_dest, case #SinglePayloadClass.y!enumelt: y_dest, case #SinglePayloadClass.z!enumelt: z_dest, case #SinglePayloadClass.w!enumelt: w_dest
|
|
|
|
x_dest(%d : $C):
|
|
br end
|
|
y_dest:
|
|
br end
|
|
z_dest:
|
|
br end
|
|
w_dest:
|
|
br end
|
|
|
|
end:
|
|
return undef : $()
|
|
}
|
|
|
|
protocol PC : class {}
|
|
|
|
enum SinglePayloadClassProtocol {
|
|
case x(PC)
|
|
case y, z, w
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_protocol_switch(i64, i64) {{.*}} {
|
|
// CHECK-64: switch i64 %0, label {{%.*}} [
|
|
// CHECK-64: i64 0, label {{%.*}}
|
|
// CHECK-objc-64-simulator-false: i64 2, label {{%.*}}
|
|
// CHECK-objc-64-simulator-false: i64 4, label {{%.*}}
|
|
// CHECK-objc-64-simulator-true: i64 1, label {{%.*}}
|
|
// CHECK-objc-64-simulator-true: i64 2, label {{%.*}}
|
|
// CHECK-native-64: i64 1, label {{%.*}}
|
|
// CHECK-native-64: i64 2, label {{%.*}}
|
|
// CHECK-64: ]
|
|
|
|
// CHECK-objc-64: inttoptr i64 %0 to %objc_object*
|
|
// CHECK-native-64: inttoptr i64 %0 to %swift.refcounted*
|
|
// CHECK-64: inttoptr i64 %1 to i8**
|
|
|
|
// CHECK-32: define{{( dllexport)?}}{{( protected)?}} swiftcc void @single_payload_class_protocol_switch(i32, i32) {{.*}} {
|
|
// CHECK-32: switch i32 %0, label {{%.*}} [
|
|
// CHECK-32: i32 0, label {{%.*}}
|
|
// CHECK-32: i32 1, label {{%.*}}
|
|
// CHECK-32: i32 2, label {{%.*}}
|
|
// CHECK-32: ]
|
|
|
|
// CHECK-objc-32: inttoptr i32 %0 to %objc_object*
|
|
// CHECK-native-32: inttoptr i32 %0 to %swift.refcounted*
|
|
// CHECK-32: inttoptr i32 %1 to i8**
|
|
|
|
sil @single_payload_class_protocol_switch : $(SinglePayloadClassProtocol) -> () {
|
|
entry(%c : $SinglePayloadClassProtocol):
|
|
switch_enum %c : $SinglePayloadClassProtocol, case #SinglePayloadClassProtocol.x!enumelt.1: x_dest, case #SinglePayloadClassProtocol.y!enumelt: y_dest, case #SinglePayloadClassProtocol.z!enumelt: z_dest, case #SinglePayloadClassProtocol.w!enumelt: w_dest
|
|
|
|
x_dest(%d : $PC):
|
|
br end
|
|
y_dest:
|
|
br end
|
|
z_dest:
|
|
br end
|
|
w_dest:
|
|
br end
|
|
|
|
end:
|
|
return undef : $()
|
|
}
|
|
|
|
enum DynamicSinglePayload<T> {
|
|
case x(T)
|
|
case y
|
|
case z
|
|
case w
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_switch(%T4enum20DynamicSinglePayloadO* noalias nocapture, %swift.type* %T) {{.*}} {
|
|
// CHECK: [[OPAQUE_ENUM:%.*]] = bitcast %T4enum20DynamicSinglePayloadO* %0 to %swift.opaque*
|
|
// CHECK: [[TMP:%.*]] = bitcast %swift.type* %T to i8***
|
|
// CHECK: [[TMP2:%.*]] = getelementptr inbounds i8**, i8*** [[TMP]], i{{.*}} -1
|
|
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[TMP2]]
|
|
// CHECK: [[ENUMADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 6
|
|
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[ENUMADDR]]
|
|
// CHECK: %getEnumTagSinglePayload = bitcast i8* [[WITNESS]] to i32 (%swift.opaque*, i32, %swift.type*)*
|
|
// CHECK: [[CASE_INDEX:%.*]] = call i32 %getEnumTagSinglePayload(%swift.opaque* noalias [[OPAQUE_ENUM]], i32 3, %swift.type* %T)
|
|
// CHECK: switch i32 [[CASE_INDEX]], label {{%.*}} [
|
|
// CHECK: i32 0, label {{%.*}}
|
|
// CHECK: i32 3, 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{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_inject_x(%T4enum20DynamicSinglePayloadO* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T) {{.*}} {
|
|
// CHECK: [[OPAQUE_ENUM:%.*]] = bitcast %T4enum20DynamicSinglePayloadO* %0 to %swift.opaque*
|
|
// CHECK: [[TMP:%.*]] = bitcast %swift.type* %T to i8***
|
|
// CHECK: [[TMP2:%.*]] = getelementptr inbounds i8**, i8*** [[TMP]], i{{.*}} -1
|
|
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[TMP2]]
|
|
// CHECK: [[ENUMADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 7
|
|
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[ENUMADDR]]
|
|
// CHECK: %storeEnumTagSinglePayload = bitcast i8* [[WITNESS]] to void (%swift.opaque*, i32, i32, %swift.type*)*
|
|
// CHECK: call void %storeEnumTagSinglePayload(%swift.opaque* noalias [[OPAQUE_ENUM]], i32 0, i32 3, %swift.type* %T)
|
|
sil @dynamic_single_payload_inject_x : $<T> (@in T) -> @out DynamicSinglePayload<T> {
|
|
entry(%r : $*DynamicSinglePayload<T>, %t : $*T):
|
|
inject_enum_addr %r : $*DynamicSinglePayload<T>, #DynamicSinglePayload.x!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_inject_y(%T4enum20DynamicSinglePayloadO* noalias nocapture sret, %swift.type* %T) {{.*}} {
|
|
// CHECK: [[OPAQUE_ENUM:%.*]] = bitcast %T4enum20DynamicSinglePayloadO* %0 to %swift.opaque*
|
|
// CHECK: [[TMP:%.*]] = bitcast %swift.type* %T to i8***
|
|
// CHECK: [[TMP2:%.*]] = getelementptr inbounds i8**, i8*** [[TMP]], i{{.*}} -1
|
|
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[TMP2]]
|
|
// CHECK: [[ENUMADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 7
|
|
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[ENUMADDR]]
|
|
// CHECK: %storeEnumTagSinglePayload = bitcast i8* [[WITNESS]] to void (%swift.opaque*, i32, i32, %swift.type*)*
|
|
// CHECK: call void %storeEnumTagSinglePayload(%swift.opaque* noalias [[OPAQUE_ENUM]], i32 1, i32 3, %swift.type* %T)
|
|
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{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_empty_payload_switch(i8) {{.*}} {
|
|
// CHECK: switch i8 {{%.*}}, label {{.*}} [
|
|
// CHECK: i8 0, label {{.*}}
|
|
// CHECK: i8 1, label {{.*}}
|
|
// CHECK: i8 2, label {{.*}}
|
|
// CHECK: i8 3, label {{.*}}
|
|
// CHECK: ]
|
|
sil @dynamic_single_payload_empty_payload_switch : $(DynamicSinglePayload<()>) -> () {
|
|
entry(%x : $DynamicSinglePayload<()>):
|
|
switch_enum %x : $DynamicSinglePayload<()>, case #DynamicSinglePayload.x!enumelt.1: x_case, case #DynamicSinglePayload.y!enumelt: y_case, case #DynamicSinglePayload.z!enumelt: z_case, default default_case
|
|
|
|
x_case(%a : $()):
|
|
br end(%a : $())
|
|
|
|
y_case:
|
|
%b = tuple ()
|
|
br end(%b : $())
|
|
|
|
z_case:
|
|
%c = tuple ()
|
|
br end(%c : $())
|
|
|
|
default_case:
|
|
%d = tuple ()
|
|
br end(%d : $())
|
|
|
|
end(%z : $()):
|
|
return %z : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8 @dynamic_single_payload_empty_payload_load([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: %1 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i8*
|
|
// CHECK: %2 = load i8, i8* %1
|
|
// CHECK: ret i8 %2
|
|
// CHECK: }
|
|
sil @dynamic_single_payload_empty_payload_load : $(@inout DynamicSinglePayload<()>) -> DynamicSinglePayload<()> {
|
|
entry(%p : $*DynamicSinglePayload<()>):
|
|
%x = load %p : $*DynamicSinglePayload<()>
|
|
return %x : $DynamicSinglePayload<()>
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_empty_payload_store([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* nocapture dereferenceable({{.*}}), i8) {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: %2 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i8*
|
|
// CHECK: store i8 %1, i8* %2
|
|
// CHECK: ret void
|
|
// CHECK: }
|
|
sil @dynamic_single_payload_empty_payload_store : $(@inout DynamicSinglePayload<()>, DynamicSinglePayload<()>) -> () {
|
|
entry(%p : $*DynamicSinglePayload<()>, %x : $DynamicSinglePayload<()>):
|
|
store %x to %p : $*DynamicSinglePayload<()>
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8 @dynamic_single_payload_empty_payload_inject_payload() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret i8 0
|
|
// CHECK: }
|
|
sil @dynamic_single_payload_empty_payload_inject_payload : $() -> DynamicSinglePayload<()> {
|
|
%v = tuple ()
|
|
%u = enum $DynamicSinglePayload<()>, #DynamicSinglePayload.x!enumelt, %v : $()
|
|
return %u : $DynamicSinglePayload<()>
|
|
}
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc i8 @dynamic_single_payload_empty_payload_inject_no_payload() {{.*}} {
|
|
// CHECK: entry:
|
|
// CHECK: ret i8 1
|
|
// CHECK: }
|
|
sil @dynamic_single_payload_empty_payload_inject_no_payload : $() -> DynamicSinglePayload<()> {
|
|
%u = enum $DynamicSinglePayload<()>, #DynamicSinglePayload.y!enumelt
|
|
return %u : $DynamicSinglePayload<()>
|
|
}
|
|
|
|
// <rdar://problem/15383966>
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_single_payload_generic_destroy
|
|
// CHECK: br i1
|
|
// CHECK: <label>
|
|
// CHECK: call void %destroy
|
|
// CHECK: <label>
|
|
sil @dynamic_single_payload_generic_destroy : $@convention(thin) <T> (@in DynamicSinglePayload<T>) -> () {
|
|
entry(%x : $*DynamicSinglePayload<T>):
|
|
destroy_addr %x : $*DynamicSinglePayload<T>
|
|
%z = tuple ()
|
|
return %z : $()
|
|
}
|
|
|
|
enum MultiPayloadNoSpareBits {
|
|
case x(Builtin.Int64)
|
|
case y(Builtin.Int32)
|
|
case z(Builtin.Int63)
|
|
case a
|
|
case b
|
|
case c
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bits_switch(i64, i8) {{.*}} {
|
|
sil @multi_payload_no_spare_bits_switch : $(MultiPayloadNoSpareBits) -> () {
|
|
entry(%u : $MultiPayloadNoSpareBits):
|
|
// CHECK-64: switch i8 %1, label %[[UNREACHABLE:[0-9]+]] [
|
|
// CHECK-64: i8 0, label %[[X_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 1, label %[[Y_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 2, label %[[Z_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 3, label %[[EMPTY:[0-9]+]]
|
|
// CHECK-64: ]
|
|
// CHECK-64: ; <label>:[[EMPTY]]
|
|
// CHECK-64: switch i64 %0, label %[[UNREACHABLE]] [
|
|
// CHECK-64: i64 0, label %[[A_DEST:[0-9]+]]
|
|
// CHECK-64: i64 1, label %[[B_DEST:[0-9]+]]
|
|
// CHECK-64: i64 2, label %[[C_DEST:[0-9]+]]
|
|
// CHECK-64: ]
|
|
// CHECK-64: ; <label>:[[UNREACHABLE]]
|
|
// CHECK-64: unreachable
|
|
switch_enum %u : $MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadNoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadNoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest
|
|
|
|
// CHECK-64: ; <label>:[[X_PREDEST]]
|
|
// CHECK-64: br label %[[X_DEST:[0-9]+]]
|
|
// CHECK-64: ; <label>:[[Y_PREDEST]]
|
|
// CHECK-64: [[Y_VALUE:%.*]] = trunc i64 %0 to i32
|
|
// CHECK-64: br label %[[Y_DEST:[0-9]+]]
|
|
// CHECK-64: ; <label>:[[Z_PREDEST]]
|
|
// CHECK-64: [[Z_VALUE:%.*]] = trunc i64 %0 to i63
|
|
// CHECK-64: br label %[[Z_DEST:[0-9]+]]
|
|
|
|
// CHECK-64: ; <label>:[[X_DEST]]
|
|
// CHECK-64: phi i64 [ %0, %[[X_PREDEST]] ]
|
|
x_dest(%x : $Builtin.Int64):
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Y_DEST]]
|
|
// CHECK-64: phi i32 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
|
|
y_dest(%y : $Builtin.Int32):
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Z_DEST]]
|
|
// CHECK-64: phi i63 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
|
|
z_dest(%z : $Builtin.Int63):
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[A_DEST]]
|
|
a_dest:
|
|
%d = function_ref @d : $@convention(thin) () -> ()
|
|
apply %d() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[B_DEST]]
|
|
b_dest:
|
|
%e = function_ref @e : $@convention(thin) () -> ()
|
|
apply %e() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[C_DEST]]
|
|
c_dest:
|
|
%f = function_ref @f : $@convention(thin) () -> ()
|
|
apply %f() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
end:
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bits_switch_indirect(%T4enum23MultiPayloadNoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
sil @multi_payload_no_spare_bits_switch_indirect : $(@inout MultiPayloadNoSpareBits) -> () {
|
|
entry(%u : $*MultiPayloadNoSpareBits):
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadNoSpareBitsO, %T4enum23MultiPayloadNoSpareBitsO* %0, i32 0, i32 1
|
|
// CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8*
|
|
// CHECK-64: [[TAG:%.*]] = load i8, i8* [[TAG_ADDR]]
|
|
// CHECK-64: switch i8 [[TAG]]
|
|
// CHECK-64: switch i64 [[PAYLOAD]]
|
|
// CHECK-64: ; <label>:
|
|
// CHECK-64: unreachable
|
|
switch_enum_addr %u : $*MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadNoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadNoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest
|
|
|
|
// CHECK-64: ; <label>:[[X_DEST:[0-9]+]]
|
|
// CHECK-64: bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i64*
|
|
// CHECK-64: ; <label>:[[Y_DEST:[0-9]+]]
|
|
// CHECK-64: bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i32*
|
|
// CHECK-64: ; <label>:[[Z_DEST:[0-9]+]]
|
|
// CHECK-64: bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i63*
|
|
|
|
x_dest:
|
|
%x = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1
|
|
br end
|
|
|
|
y_dest:
|
|
%y = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.y!enumelt.1
|
|
br end
|
|
|
|
z_dest:
|
|
%z = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.z!enumelt.1
|
|
br end
|
|
|
|
a_dest:
|
|
br end
|
|
|
|
b_dest:
|
|
br end
|
|
|
|
c_dest:
|
|
br end
|
|
|
|
end:
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_x(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 %0, 0
|
|
// CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 0, 1
|
|
// CHECK-64: ret { i64, i8 } [[RES]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_x : $(Builtin.Int64) -> MultiPayloadNoSpareBits {
|
|
entry(%0 : $Builtin.Int64):
|
|
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1, %0 : $Builtin.Int64
|
|
return %u : $MultiPayloadNoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_x_indirect(i64, %T4enum23MultiPayloadNoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadNoSpareBitsO* %1 to i64*
|
|
// CHECK-64: store i64 %0, i64* [[DATA_ADDR]]
|
|
// CHECK-64: [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadNoSpareBitsO, %T4enum23MultiPayloadNoSpareBitsO* %1, i32 0, i32 1
|
|
// CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8*
|
|
// CHECK-64: store i8 0, i8* [[TAG_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_x_indirect : $(Builtin.Int64, @inout MultiPayloadNoSpareBits) -> () {
|
|
entry(%0 : $Builtin.Int64, %1 : $*MultiPayloadNoSpareBits):
|
|
%a = init_enum_data_addr %1 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1
|
|
store %0 to %a : $*Builtin.Int64
|
|
inject_enum_addr %1 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_y(i32) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i32 %0 to i64
|
|
// CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[ZEXT]], 0
|
|
// CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 1, 1
|
|
// CHECK-64: ret { i64, i8 } [[RES]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_y : $(Builtin.Int32) -> MultiPayloadNoSpareBits {
|
|
entry(%0 : $Builtin.Int32):
|
|
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.y!enumelt.1, %0 : $Builtin.Int32
|
|
return %u : $MultiPayloadNoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_z(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64
|
|
// CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[ZEXT]], 0
|
|
// CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 2, 1
|
|
// CHECK-64: ret { i64, i8 } [[RES]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_z : $(Builtin.Int63) -> MultiPayloadNoSpareBits {
|
|
entry(%0 : $Builtin.Int63):
|
|
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.z!enumelt.1, %0 : $Builtin.Int63
|
|
return %u : $MultiPayloadNoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_a() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: ret { i64, i8 } { i64 0, i8 3 }
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_a : $() -> MultiPayloadNoSpareBits {
|
|
entry:
|
|
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.a!enumelt
|
|
return %u : $MultiPayloadNoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_no_spare_bit_inject_a_indirect(%T4enum23MultiPayloadNoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadNoSpareBitsO* %0 to i64*
|
|
// CHECK-64: store i64 0, i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadNoSpareBitsO, %T4enum23MultiPayloadNoSpareBitsO* %0, i32 0, i32 1
|
|
// CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i8*
|
|
// CHECK-64: store i8 3, i8* [[TAG_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_a_indirect : $(@inout MultiPayloadNoSpareBits) -> () {
|
|
entry(%0 : $*MultiPayloadNoSpareBits):
|
|
inject_enum_addr %0 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.a!enumelt
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_b() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: ret { i64, i8 } { i64 1, i8 3 }
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_b : $() -> MultiPayloadNoSpareBits {
|
|
entry:
|
|
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.b!enumelt
|
|
return %u : $MultiPayloadNoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_no_spare_bit_inject_c() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: ret { i64, i8 } { i64 2, i8 3 }
|
|
// CHECK-64: }
|
|
sil @multi_payload_no_spare_bit_inject_c : $() -> MultiPayloadNoSpareBits {
|
|
entry:
|
|
%u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.c!enumelt
|
|
return %u : $MultiPayloadNoSpareBits
|
|
}
|
|
|
|
enum MultiPayloadOneSpareBit {
|
|
case x(Builtin.Int62)
|
|
case y(Builtin.Int63)
|
|
case z(Builtin.Int61)
|
|
case a
|
|
case b
|
|
case c
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_switch(i64, i8) {{.*}} {
|
|
sil @multi_payload_one_spare_bit_switch : $(MultiPayloadOneSpareBit) -> () {
|
|
entry(%u : $MultiPayloadOneSpareBit):
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i8 %1 to i1
|
|
// CHECK-64: [[SPARE_TAG_LSHR:%.*]] = lshr i64 %0, 63
|
|
// CHECK-64: [[SPARE_TAG_TRUNC:%.*]] = trunc i64 [[SPARE_TAG_LSHR]] to i8
|
|
// CHECK-64: [[SPARE_TAG:%.*]] = and i8 [[SPARE_TAG_TRUNC]], 1
|
|
// CHECK-64: [[EXTRA_TAG_ZEXT:%.*]] = zext i1 [[NATIVECC_TRUNC]] to i8
|
|
// CHECK-64: [[EXTRA_TAG:%.*]] = shl i8 [[EXTRA_TAG_ZEXT]], 1
|
|
// CHECK-64: [[TAG:%.*]] = or i8 [[SPARE_TAG]], [[EXTRA_TAG]]
|
|
// CHECK-64: switch i8 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [
|
|
// CHECK-64: i8 0, label %[[X_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 1, label %[[Y_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 2, label %[[Z_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 3, label %[[EMPTY_DEST:[0-9]+]]
|
|
// CHECK-64: ]
|
|
|
|
// CHECK-64: ; <label>:[[EMPTY_DEST]]
|
|
// CHECK-64: switch i64 %0, label %[[UNREACHABLE]] [
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: i64 -9223372036854775808, label %[[A_DEST:[0-9]+]]
|
|
// -- 0x8000_0000_0000_0001
|
|
// CHECK-64: i64 -9223372036854775807, label %[[B_DEST:[0-9]+]]
|
|
// -- 0x8000_0000_0000_0002
|
|
// CHECK-64: i64 -9223372036854775806, label %[[C_DEST:[0-9]+]]
|
|
// CHECK-64: ]
|
|
|
|
// CHECK-64: ; <label>:[[UNREACHABLE]]
|
|
// CHECK-64: unreachable
|
|
switch_enum %u : $MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt.1: x_dest, case #MultiPayloadOneSpareBit.y!enumelt.1: y_dest, case #MultiPayloadOneSpareBit.z!enumelt.1: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest
|
|
|
|
// CHECK-64: ; <label>:[[X_PREDEST]]
|
|
// CHECK-64: [[X_VALUE:%.*]] = trunc i64 %0 to i62
|
|
// CHECK-64: br label %[[X_DEST:[0-9]+]]
|
|
// CHECK-64: ; <label>:[[Y_PREDEST]]
|
|
// -- 0x7FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[Y_MASKED:%.*]] = and i64 %0, 9223372036854775807
|
|
// CHECK-64: [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i63
|
|
// CHECK-64: br label %[[Y_DEST:[0-9]+]]
|
|
// CHECK-64: ; <label>:[[Z_PREDEST]]
|
|
// CHECK-64: [[Z_VALUE:%.*]] = trunc i64 %0 to i61
|
|
// CHECK-64: br label %[[Z_DEST:[0-9]+]]
|
|
|
|
// CHECK-64: ; <label>:[[X_DEST]]
|
|
// CHECK-64: phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ]
|
|
x_dest(%x : $Builtin.Int62):
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Y_DEST]]
|
|
// CHECK-64: phi i63 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
|
|
y_dest(%y : $Builtin.Int63):
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Z_DEST]]
|
|
// CHECK-64: phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
|
|
z_dest(%z : $Builtin.Int61):
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[A_DEST]]
|
|
a_dest:
|
|
%d = function_ref @d : $@convention(thin) () -> ()
|
|
apply %d() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[B_DEST]]
|
|
b_dest:
|
|
%e = function_ref @e : $@convention(thin) () -> ()
|
|
apply %e() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[C_DEST]]
|
|
c_dest:
|
|
%f = function_ref @f : $@convention(thin) () -> ()
|
|
apply %f() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
end:
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
sil @multi_payload_one_spare_bit_switch_indirect : $(@inout MultiPayloadOneSpareBit) -> () {
|
|
entry(%u : $*MultiPayloadOneSpareBit):
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %0, i32 0, i32 1
|
|
// CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
|
|
// CHECK-64: [[TAG:%.*]] = load i1, i1* [[TAG_ADDR]]
|
|
// CHECK-64: switch i8 {{%.*}}
|
|
// CHECK-64: switch i64 [[PAYLOAD]]
|
|
// CHECK-64: ; <label>:
|
|
// CHECK-64: unreachable
|
|
switch_enum_addr %u : $*MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt.1: x_dest, case #MultiPayloadOneSpareBit.y!enumelt.1: y_dest, case #MultiPayloadOneSpareBit.z!enumelt.1: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest
|
|
|
|
// CHECK-64: ; <label>:[[X_PREDEST:[0-9]+]]
|
|
// CHECK-64: bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i62*
|
|
|
|
// CHECK-64: ; <label>:[[Y_PREDEST:[0-9]+]]
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// -- 0x7FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
|
|
// CHECK-64: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i63*
|
|
|
|
// CHECK-64: ; <label>:[[Z_PREDEST:[0-9]+]]
|
|
// CHECK-64: bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i61*
|
|
|
|
x_dest:
|
|
%x = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1
|
|
br end
|
|
|
|
y_dest:
|
|
%y = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1
|
|
br end
|
|
|
|
z_dest:
|
|
%z = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt.1
|
|
br end
|
|
|
|
a_dest:
|
|
br end
|
|
|
|
b_dest:
|
|
br end
|
|
|
|
c_dest:
|
|
br end
|
|
|
|
end:
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_x(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64
|
|
// CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[ZEXT]], 0
|
|
// CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 0, 1
|
|
// CHECK-64: ret { i64, i8 } [[RES]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_x : $(Builtin.Int62) -> MultiPayloadOneSpareBit {
|
|
entry(%0 : $Builtin.Int62):
|
|
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1, %0 : $Builtin.Int62
|
|
return %u : $MultiPayloadOneSpareBit
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_x_indirect(i64, %T4enum23MultiPayloadOneSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
|
|
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i62*
|
|
// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// -- 0x7FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
|
|
// CHECK-64: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %1, i32 0, i32 1
|
|
// CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
|
|
// CHECK-64: store i1 false, i1* [[TAG_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_x_indirect : $(Builtin.Int62, @inout MultiPayloadOneSpareBit) -> () {
|
|
entry(%0 : $Builtin.Int62, %1 : $*MultiPayloadOneSpareBit):
|
|
%a = init_enum_data_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1
|
|
store %0 to %a : $*Builtin.Int62
|
|
inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_y(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i63 [[NATIVECC_TRUNC]] to i64
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808
|
|
// CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[TAGGED]], 0
|
|
// CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 0, 1
|
|
// CHECK-64: ret { i64, i8 } [[RES]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_y : $(Builtin.Int63) -> MultiPayloadOneSpareBit {
|
|
entry(%0 : $Builtin.Int63):
|
|
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1, %0 : $Builtin.Int63
|
|
return %u : $MultiPayloadOneSpareBit
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_y_indirect(i64, %T4enum23MultiPayloadOneSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i63
|
|
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i63*
|
|
// CHECK-64: store i63 [[NATIVECC_TRUNC]], i63* [[DATA_ADDR]]
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// -- 0x7FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], -9223372036854775808
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %1 to i64*
|
|
// CHECK-64: store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %1, i32 0, i32 1
|
|
// CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
|
|
// CHECK-64: store i1 false, i1* [[TAG_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
|
|
sil @multi_payload_one_spare_bit_inject_y_indirect : $(Builtin.Int63, @inout MultiPayloadOneSpareBit) -> () {
|
|
entry(%0 : $Builtin.Int63, %1 : $*MultiPayloadOneSpareBit):
|
|
%a = init_enum_data_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1
|
|
store %0 to %a : $*Builtin.Int63
|
|
inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_z(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i61
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i61 [[NATIVECC_TRUNC]] to i64
|
|
// CHECK-64: [[RES_0:%.*]] = insertvalue { i64, i8 } undef, i64 [[ZEXT]], 0
|
|
// CHECK-64: [[RES:%.*]] = insertvalue { i64, i8 } [[RES_0]], i8 1, 1
|
|
// CHECK-64: ret { i64, i8 } [[RES]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_z : $(Builtin.Int61) -> MultiPayloadOneSpareBit {
|
|
entry(%0 : $Builtin.Int61):
|
|
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt.1, %0 : $Builtin.Int61
|
|
return %u : $MultiPayloadOneSpareBit
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_a() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: ret { i64, i8 } { i64 -9223372036854775808, i8 1 }
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_a : $() -> MultiPayloadOneSpareBit {
|
|
entry:
|
|
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt
|
|
return %u : $MultiPayloadOneSpareBit
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_one_spare_bit_inject_a_indirect(%T4enum23MultiPayloadOneSpareBitO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum23MultiPayloadOneSpareBitO* %0 to i64*
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: [[T0:%.*]] = getelementptr inbounds %T4enum23MultiPayloadOneSpareBitO, %T4enum23MultiPayloadOneSpareBitO* %0, i32 0, i32 1
|
|
// CHECK-64: [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
|
|
// CHECK-64: store i1 true, i1* [[TAG_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_a_indirect : $(@inout MultiPayloadOneSpareBit) -> () {
|
|
entry(%0 : $*MultiPayloadOneSpareBit):
|
|
inject_enum_addr %0 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_b() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// -- 0x8000_0000_0000_0001
|
|
// CHECK-64: ret { i64, i8 } { i64 -9223372036854775807, i8 1 }
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_b : $() -> MultiPayloadOneSpareBit {
|
|
entry:
|
|
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.b!enumelt
|
|
return %u : $MultiPayloadOneSpareBit
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @multi_payload_one_spare_bit_inject_c() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// -- 0x8000_0000_0000_0002
|
|
// CHECK-64: ret { i64, i8 } { i64 -9223372036854775806, i8 1 }
|
|
// CHECK-64: }
|
|
sil @multi_payload_one_spare_bit_inject_c : $() -> MultiPayloadOneSpareBit {
|
|
entry:
|
|
%u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.c!enumelt
|
|
return %u : $MultiPayloadOneSpareBit
|
|
}
|
|
|
|
|
|
enum MultiPayloadTwoSpareBits {
|
|
case x(Builtin.Int62)
|
|
case y(Builtin.Int60)
|
|
case z(Builtin.Int61)
|
|
case a
|
|
case b
|
|
case c
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_switch(i64) {{.*}} {
|
|
sil @multi_payload_two_spare_bits_switch : $(MultiPayloadTwoSpareBits) -> () {
|
|
entry(%u : $MultiPayloadTwoSpareBits):
|
|
// CHECK-64: [[TAG_LSHR:%.*]] = lshr i64 %0, 62
|
|
// CHECK-64: [[TAG_BYTE:%.*]] = trunc i64 [[TAG_LSHR]] to i8
|
|
// CHECK-64: [[TAG:%.*]] = and i8 [[TAG_BYTE]], 3
|
|
// CHECK-64: switch i8 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [
|
|
// CHECK-64: i8 0, label %[[X_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 1, label %[[Y_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 2, label %[[Z_PREDEST:[0-9]+]]
|
|
// CHECK-64: i8 3, label %[[EMPTY_DEST:[0-9]+]]
|
|
// CHECK-64: ]
|
|
// CHECK-64: ; <label>:[[EMPTY_DEST]]
|
|
// CHECK-64: switch i64 %0, label %[[UNREACHABLE]] [
|
|
// -- 0xC000_0000_0000_0000
|
|
// CHECK-64: i64 -4611686018427387904, label %[[A_DEST:[0-9]+]]
|
|
// -- 0xC000_0000_0000_0001
|
|
// CHECK-64: i64 -4611686018427387903, label %[[B_DEST:[0-9]+]]
|
|
// -- 0xC000_0000_0000_0002
|
|
// CHECK-64: i64 -4611686018427387902, label %[[C_DEST:[0-9]+]]
|
|
// CHECK-64: ]
|
|
// CHECK-64: ; <label>:[[UNREACHABLE]]
|
|
// CHECK-64: unreachable
|
|
switch_enum %u : $MultiPayloadTwoSpareBits, case #MultiPayloadTwoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadTwoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadTwoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadTwoSpareBits.a!enumelt: a_dest, case #MultiPayloadTwoSpareBits.b!enumelt: b_dest, case #MultiPayloadTwoSpareBits.c!enumelt: c_dest
|
|
|
|
// CHECK-64: ; <label>:[[X_PREDEST]]
|
|
// CHECK-64: [[X_VALUE:%.*]] = trunc i64 %0 to i62
|
|
// CHECK-64: br label %[[X_DEST:[0-9]+]]
|
|
|
|
// CHECK-64: ; <label>:[[Y_PREDEST]]
|
|
// -- 0x3FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903
|
|
// CHECK-64: [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i60
|
|
// CHECK-64: br label %[[Y_DEST:[0-9]+]]
|
|
|
|
// CHECK-64: ; <label>:[[Z_PREDEST]]
|
|
// -- 0x3FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903
|
|
// CHECK-64: [[Z_VALUE:%.*]] = trunc i64 [[Z_MASKED]] to i61
|
|
// CHECK-64: br label %[[Z_DEST:[0-9]+]]
|
|
|
|
// CHECK-64: ; <label>:[[X_DEST]]
|
|
// CHECK-64: phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ]
|
|
x_dest(%x : $Builtin.Int62):
|
|
%a = function_ref @a : $@convention(thin) () -> ()
|
|
apply %a() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Y_DEST]]
|
|
// CHECK-64: phi i60 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
|
|
y_dest(%y : $Builtin.Int60):
|
|
%b = function_ref @b : $@convention(thin) () -> ()
|
|
apply %b() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[Z_DEST]]
|
|
// CHECK-64: phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
|
|
z_dest(%z : $Builtin.Int61):
|
|
%c = function_ref @c : $@convention(thin) () -> ()
|
|
apply %c() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[A_DEST]]
|
|
a_dest:
|
|
%d = function_ref @d : $@convention(thin) () -> ()
|
|
apply %d() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[B_DEST]]
|
|
b_dest:
|
|
%e = function_ref @e : $@convention(thin) () -> ()
|
|
apply %e() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
// CHECK-64: ; <label>:[[C_DEST]]
|
|
c_dest:
|
|
%f = function_ref @f : $@convention(thin) () -> ()
|
|
apply %f() : $@convention(thin) () -> ()
|
|
br end
|
|
|
|
end:
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_x(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i62 [[NATIVECC_TRUNC]] to i64
|
|
// CHECK-64: ret i64 [[ZEXT]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_x : $(Builtin.Int62) -> MultiPayloadTwoSpareBits {
|
|
entry(%0 : $Builtin.Int62):
|
|
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1, %0 : $Builtin.Int62
|
|
return %u : $MultiPayloadTwoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_x_indirect(i64, %T4enum24MultiPayloadTwoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i62
|
|
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i62*
|
|
// CHECK-64: store i62 [[NATIVECC_TRUNC]], i62* [[DATA_ADDR]]
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// -- 0x3FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
|
|
// CHECK-64: store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_x_indirect : $(Builtin.Int62, @inout MultiPayloadTwoSpareBits) -> () {
|
|
entry(%0 : $Builtin.Int62, %1 : $*MultiPayloadTwoSpareBits):
|
|
%a = init_enum_data_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1
|
|
store %0 to %a : $*Builtin.Int62
|
|
inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_y(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i60 [[NATIVECC_TRUNC]] to i64
|
|
// -- 0x4000_0000_0000_0000
|
|
// CHECK-64: [[TAGGED:%.*]] = or i64 [[ZEXT]], 4611686018427387904
|
|
// CHECK-64: ret i64 [[TAGGED]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_y : $(Builtin.Int60) -> MultiPayloadTwoSpareBits {
|
|
entry(%0 : $Builtin.Int60):
|
|
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1, %0 : $Builtin.Int60
|
|
return %u : $MultiPayloadTwoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_y_indirect(i64, %T4enum24MultiPayloadTwoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i60
|
|
// CHECK-64: [[DATA_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i60*
|
|
// CHECK-64: store i60 [[NATIVECC_TRUNC]], i60* [[DATA_ADDR]]
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
|
|
// CHECK-64: [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
|
|
// -- 0x3FFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
|
|
// -- 0x4000_0000_0000_0000
|
|
// CHECK-64: [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], 4611686018427387904
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %1 to i64*
|
|
// CHECK-64: store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_y_indirect : $(Builtin.Int60, @inout MultiPayloadTwoSpareBits) -> () {
|
|
entry(%0 : $Builtin.Int60, %1 : $*MultiPayloadTwoSpareBits):
|
|
%a = init_enum_data_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1
|
|
store %0 to %a : $*Builtin.Int60
|
|
inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_z(i64) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[NATIVECC_TRUNC:%.*]] = trunc i64 %0 to i61
|
|
// CHECK-64: [[ZEXT:%.*]] = zext i61 [[NATIVECC_TRUNC]] to i64
|
|
// -- 0x8000_0000_0000_0000
|
|
// CHECK-64: [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808
|
|
// CHECK-64: ret i64 [[TAGGED]]
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_z : $(Builtin.Int61) -> MultiPayloadTwoSpareBits {
|
|
entry(%0 : $Builtin.Int61):
|
|
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.z!enumelt.1, %0 : $Builtin.Int61
|
|
return %u : $MultiPayloadTwoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_a() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// -- 0xC000_0000_0000_0000
|
|
// CHECK-64: ret i64 -4611686018427387904
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_a : $() -> MultiPayloadTwoSpareBits {
|
|
entry:
|
|
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.a!enumelt
|
|
return %u : $MultiPayloadTwoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_two_spare_bits_inject_a_indirect(%T4enum24MultiPayloadTwoSpareBitsO* nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: [[PAYLOAD_ADDR:%.*]] = bitcast %T4enum24MultiPayloadTwoSpareBitsO* %0 to i64*
|
|
// -- 0xC000_0000_0000_0000
|
|
// CHECK-64: store i64 -4611686018427387904, i64* [[PAYLOAD_ADDR]]
|
|
// CHECK-64: ret void
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_a_indirect : $(@inout MultiPayloadTwoSpareBits) -> () {
|
|
entry(%0 : $*MultiPayloadTwoSpareBits):
|
|
inject_enum_addr %0 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.a!enumelt
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_b() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// -- 0xC000_0000_0000_0001
|
|
// CHECK-64: ret i64 -4611686018427387903
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_b : $() -> MultiPayloadTwoSpareBits {
|
|
entry:
|
|
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.b!enumelt
|
|
return %u : $MultiPayloadTwoSpareBits
|
|
}
|
|
|
|
// CHECK-64: define{{( dllexport)?}}{{( protected)?}} swiftcc i64 @multi_payload_two_spare_bits_inject_c() {{.*}} {
|
|
// CHECK-64: entry:
|
|
// -- 0xC000_0000_0000_0002
|
|
// CHECK-64: ret i64 -4611686018427387902
|
|
// CHECK-64: }
|
|
sil @multi_payload_two_spare_bits_inject_c : $() -> MultiPayloadTwoSpareBits {
|
|
entry:
|
|
%u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.c!enumelt
|
|
return %u : $MultiPayloadTwoSpareBits
|
|
}
|
|
|
|
class D {}
|
|
sil_vtable D {}
|
|
|
|
sil @$s4enum1DCfD : $@convention(method) (D) -> ()
|
|
|
|
enum MultiPayloadClasses {
|
|
case x(C)
|
|
case y(D)
|
|
case z
|
|
case w
|
|
}
|
|
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_classes_switch(i64) {{.*}} {
|
|
// CHECK-64: %1 = lshr i64 %0, 62
|
|
// CHECK-64: %2 = trunc i64 %1 to i8
|
|
// CHECK-64: %3 = and i8 %2, 3
|
|
// CHECK-64: switch i8 %3, label {{%.*}} [
|
|
// CHECK-64: i8 0, label {{%.*}}
|
|
// CHECK-64: i8 1, label {{%.*}}
|
|
// CHECK-64: i8 2, label {{%.*}}
|
|
// CHECK-64: ]
|
|
// CHECK-64: switch i64 %0, label {{%.*}} [
|
|
// -- 0x8000000000000000
|
|
// CHECK-64: i64 -9223372036854775808, label {{%.*}}
|
|
// -- 0x8000000000000008
|
|
// CHECK-64: i64 -9223372036854775800, label {{%.*}}
|
|
// CHECK-64: ]
|
|
// -- Extract x(C)
|
|
// CHECK-64: inttoptr i64 %0 to %T4enum1CC*
|
|
// -- Extract y(D)
|
|
// -- 0x3fffffffffffffff
|
|
// CHECK-64: [[MASKED:%.*]] = and i64 %0, 4611686018427387903
|
|
// CHECK-64: inttoptr i64 [[MASKED]] to %T4enum1DC*
|
|
|
|
// CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_classes_switch(i32) {{.*}} {
|
|
// CHECK-32: %1 = trunc i32 %0 to i8
|
|
// CHECK-32: %2 = and i8 %1, 3
|
|
// CHECK-32: switch i8 %2, label {{%.*}} [
|
|
// CHECK-32: i8 0, label {{%.*}}
|
|
// CHECK-32: i8 1, label {{%.*}}
|
|
// CHECK-32: i8 2, label {{%.*}}
|
|
// CHECK-32: ]
|
|
// CHECK-32: switch i32 %0, label {{%.*}} [
|
|
// CHECK-32: i32 2, label {{%.*}}
|
|
// CHECK-32: i32 6, label {{%.*}}
|
|
// CHECK-32: ]
|
|
// -- Extract x(C)
|
|
// CHECK-32: inttoptr i32 %0 to %T4enum1CC*
|
|
// -- Extract y(D)
|
|
// CHECK-32: [[MASKED:%.*]] = and i32 %0, -4
|
|
// CHECK-32: inttoptr i32 [[MASKED]] to %T4enum1DC*
|
|
|
|
sil @multi_payload_classes_switch : $(MultiPayloadClasses) -> () {
|
|
entry(%c : $MultiPayloadClasses):
|
|
switch_enum %c : $MultiPayloadClasses, case #MultiPayloadClasses.x!enumelt.1: x_dest, case #MultiPayloadClasses.y!enumelt.1: y_dest, case #MultiPayloadClasses.z!enumelt: z_dest, case #MultiPayloadClasses.w!enumelt: w_dest
|
|
|
|
x_dest(%x : $C):
|
|
br end
|
|
|
|
y_dest(%y : $D):
|
|
br end
|
|
|
|
z_dest:
|
|
br end
|
|
|
|
w_dest:
|
|
br end
|
|
|
|
end:
|
|
return undef : $()
|
|
}
|
|
|
|
struct S {
|
|
var a: CharLike
|
|
var b: IntLike
|
|
}
|
|
|
|
enum MultiPayloadSpareBitAggregates {
|
|
// Has spare bits in the padding between Int32 and Int64
|
|
case x(Builtin.Int32, Builtin.Int64)
|
|
// Has spare bits in the object pointers
|
|
case y(C, C)
|
|
// Has spare bits in the padding between struct fields
|
|
case z(S)
|
|
}
|
|
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_spare_bit_aggregate_switch(i64, i64) {{.*}} {
|
|
// CHECK-64: [[T0:%.*]] = lshr i64 %0, 62
|
|
// CHECK-64: [[TAG_BYTE:%.*]] = trunc i64 [[T0]] to i8
|
|
// CHECK-64: [[TAG:%.*]] = and i8 [[TAG_BYTE]], 3
|
|
// CHECK-64: switch i8 [[TAG]], label {{%.*}} [
|
|
// CHECK-64: i8 0, label %[[X_DEST:[0-9]+]]
|
|
// CHECK-64: i8 1, label %[[Y_DEST:[0-9]+]]
|
|
// CHECK-64: i8 2, label %[[Z_DEST:[0-9]+]]
|
|
// CHECK-64: ]
|
|
// CHECK-64: ; <label>:[[X_DEST]]
|
|
// CHECK-64: [[X_0:%.*]] = trunc i64 %0 to i32
|
|
// CHECK-64: ; <label>:[[Y_DEST]]
|
|
// -- 0x3fffffffffffffff
|
|
// CHECK-64: [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903
|
|
// CHECK-64: [[Y_0:%.*]] = inttoptr i64 [[Y_MASKED]] to %T4enum1CC*
|
|
// CHECK-64: [[Y_1:%.*]] = inttoptr i64 %1 to %T4enum1CC*
|
|
// CHECK-64: ; <label>:[[Z_DEST]]
|
|
// -- 0x3fffffffffffffff
|
|
// CHECK-64: [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903
|
|
// CHECK-64: [[Z_A:%.*]] = trunc i64 [[Z_MASKED]] to i21
|
|
|
|
sil @multi_payload_spare_bit_aggregate_switch : $(MultiPayloadSpareBitAggregates) -> () {
|
|
entry(%c : $MultiPayloadSpareBitAggregates):
|
|
switch_enum %c : $MultiPayloadSpareBitAggregates, case #MultiPayloadSpareBitAggregates.x!enumelt.1: x_dest, case #MultiPayloadSpareBitAggregates.y!enumelt.1: y_dest, case #MultiPayloadSpareBitAggregates.z!enumelt.1: z_dest
|
|
|
|
x_dest(%x : $(Builtin.Int32, Builtin.Int64)):
|
|
br end
|
|
|
|
y_dest(%y : $(C, C)):
|
|
br end
|
|
|
|
z_dest(%z : $S):
|
|
br end
|
|
|
|
end:
|
|
return undef : $()
|
|
}
|
|
|
|
// <rdar://problem/15759464>
|
|
enum MultiPayloadInner {
|
|
case A(Builtin.Word)
|
|
case B(Builtin.Word)
|
|
}
|
|
|
|
enum MultiPayloadNested {
|
|
case A(MultiPayloadInner)
|
|
case B(MultiPayloadInner)
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_nested_switch
|
|
// CHECK: %1 = bitcast %T4enum18MultiPayloadNestedO* %0 to { [[WORD]], i8 }*
|
|
// CHECK: %2 = getelementptr
|
|
// CHECK: %3 = load [[WORD]], [[WORD]]* %2
|
|
// CHECK: %4 = getelementptr
|
|
// CHECK: %5 = load i8, i8* %4
|
|
// CHECK: %6 = lshr i8 %5, 7
|
|
// CHECK: %7 = trunc i8 %6 to i1
|
|
// CHECK: br i1 %7
|
|
sil @multi_payload_nested_switch : $(@in MultiPayloadNested) -> () {
|
|
entry(%c : $*MultiPayloadNested):
|
|
switch_enum_addr %c : $*MultiPayloadNested, case #MultiPayloadNested.A!enumelt.1: a_dest, case #MultiPayloadNested.B!enumelt.1: b_dest
|
|
|
|
a_dest:
|
|
br end
|
|
|
|
b_dest:
|
|
br end
|
|
|
|
end:
|
|
return undef : $()
|
|
}
|
|
|
|
enum MultiPayloadInnerSpareBits {
|
|
case A(Builtin.NativeObject)
|
|
case B(Builtin.NativeObject)
|
|
case C(Builtin.NativeObject)
|
|
case D(Builtin.NativeObject)
|
|
}
|
|
|
|
enum MultiPayloadNestedSpareBits {
|
|
case A(MultiPayloadInnerSpareBits)
|
|
case B(MultiPayloadInnerSpareBits)
|
|
}
|
|
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_nested_spare_bits_switch(%T4enum27MultiPayloadNestedSpareBitsO* noalias nocapture dereferenceable({{.*}})) {{.*}} {
|
|
// CHECK-64: entry:
|
|
// CHECK-64: %1 = bitcast %T4enum27MultiPayloadNestedSpareBitsO* %0 to [[WORD]]*
|
|
// CHECK-64: %2 = load [[WORD]], [[WORD]]* %1
|
|
// CHECK-64: %3 = lshr [[WORD]] %2, 61
|
|
// CHECK-64: %4 = trunc [[WORD]] %3 to i1
|
|
// CHECK-64: br i1 %4
|
|
sil @multi_payload_nested_spare_bits_switch : $(@in MultiPayloadNestedSpareBits) -> () {
|
|
entry(%c : $*MultiPayloadNestedSpareBits):
|
|
switch_enum_addr %c : $*MultiPayloadNestedSpareBits, case #MultiPayloadNestedSpareBits.A!enumelt.1: a_dest, case #MultiPayloadNestedSpareBits.B!enumelt.1: b_dest
|
|
|
|
a_dest:
|
|
br end
|
|
|
|
b_dest:
|
|
br end
|
|
|
|
end:
|
|
return undef : $()
|
|
}
|
|
|
|
|
|
// -- test for a switch_enum bug for multi-payload, no-empty-case enums
|
|
// uncovered by Chris
|
|
enum OnlyPayloads {
|
|
case x(Builtin.Int64)
|
|
case y(Builtin.Int32)
|
|
case z(Builtin.Int16)
|
|
}
|
|
|
|
sil @only_payloads_switch : $(OnlyPayloads) -> () {
|
|
entry(%0 : $OnlyPayloads):
|
|
switch_enum %0 : $OnlyPayloads, case #OnlyPayloads.x!enumelt.1: x_dest, case #OnlyPayloads.y!enumelt.1: y_dest, case #OnlyPayloads.z!enumelt.1: z_dest
|
|
|
|
x_dest:
|
|
br end
|
|
y_dest:
|
|
br end
|
|
z_dest:
|
|
br end
|
|
|
|
end:
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// Should not use spare bits, because T may be a tagged ObjC pointer.
|
|
enum MultiPayloadClassGeneric<T: AnyObject> {
|
|
case A(C, Builtin.Word)
|
|
case B(T)
|
|
}
|
|
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i64, i8 } @multi_payload_class_generic_no_spare_bits(i64, i64, i8, %swift.type* %T)
|
|
// CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i32, i32, i8 } @multi_payload_class_generic_no_spare_bits(i32, i32, i8, %swift.type* %T)
|
|
sil @multi_payload_class_generic_no_spare_bits : $@convention(thin) <T: AnyObject> (@owned MultiPayloadClassGeneric<T>) -> MultiPayloadClassGeneric<T> {
|
|
entry(%e : $MultiPayloadClassGeneric<T>):
|
|
return %e : $MultiPayloadClassGeneric<T>
|
|
}
|
|
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i64, i8 } @multi_payload_class_instance_no_spare_bits(i64, i64, i8)
|
|
// CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i32, i32, i8 } @multi_payload_class_instance_no_spare_bits(i32, i32, i8)
|
|
sil @multi_payload_class_instance_no_spare_bits : $@convention(thin) (@owned MultiPayloadClassGeneric<C>) -> MultiPayloadClassGeneric<C> {
|
|
entry(%e : $MultiPayloadClassGeneric<C>):
|
|
return %e : $MultiPayloadClassGeneric<C>
|
|
}
|
|
|
|
enum MultiPayloadAddressOnlyFixed {
|
|
case X(Any)
|
|
case Y(Builtin.Int32)
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_address_only_destroy(%T4enum28MultiPayloadAddressOnlyFixedO* noalias nocapture dereferenceable({{.*}}))
|
|
sil @multi_payload_address_only_destroy : $@convention(thin) (@in MultiPayloadAddressOnlyFixed) -> () {
|
|
entry(%m : $*MultiPayloadAddressOnlyFixed):
|
|
destroy_addr %m : $*MultiPayloadAddressOnlyFixed
|
|
return undef : $()
|
|
}
|
|
|
|
// Even if spare bits are available in an address-only payload,
|
|
// we cannot use them.
|
|
|
|
struct AddressOnlySpareBitsPayload {
|
|
weak var x: C?
|
|
var y: C
|
|
}
|
|
|
|
enum MultiPayloadAddressOnlySpareBits {
|
|
case X(AddressOnlySpareBitsPayload)
|
|
case Y(AddressOnlySpareBitsPayload)
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @multi_payload_address_only_spare_bits(%T4enum32MultiPayloadAddressOnlySpareBitsO* noalias nocapture dereferenceable({{.*}}))
|
|
sil @multi_payload_address_only_spare_bits : $@convention(thin) (@in MultiPayloadAddressOnlySpareBits) -> () {
|
|
entry(%m : $*MultiPayloadAddressOnlySpareBits):
|
|
destroy_addr %m : $*MultiPayloadAddressOnlySpareBits
|
|
return undef : $()
|
|
}
|
|
|
|
// Force the storage types to all be generated.
|
|
typealias AllConcreteTestEnums = (
|
|
Empty,
|
|
EmptySingleton,
|
|
Singleton,
|
|
SingletonRef,
|
|
NoPayloads,
|
|
NoPayloads2,
|
|
SinglePayloadNoXI,
|
|
SinglePayloadNoXI2,
|
|
SinglePayloadSpareBit,
|
|
SinglePayloadNested,
|
|
SinglePayloadNestedNested,
|
|
MultiPayloadNoSpareBits,
|
|
MultiPayloadOneSpareBit,
|
|
MultiPayloadTwoSpareBits,
|
|
MultiPayloadSpareBitAggregates,
|
|
MultiPayloadNested,
|
|
MultiPayloadNestedSpareBits)
|
|
|
|
sil_global @x : $AllConcreteTestEnums
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_singleton_switch_indirect([[DYNAMIC_SINGLETON]]* noalias nocapture, %swift.type* %T) {{.*}} {
|
|
// CHECK: bitcast [[DYNAMIC_SINGLETON]]* %0 to %swift.opaque*
|
|
// CHECK: ret void
|
|
// CHECK: }
|
|
sil @dynamic_singleton_switch_indirect : $<T> (@in DynamicSingleton<T>) -> () {
|
|
entry(%0 : $*DynamicSingleton<T>):
|
|
switch_enum_addr %0 : $*DynamicSingleton<T>, case #DynamicSingleton.value!enumelt.1: dest
|
|
|
|
dest:
|
|
%1 = unchecked_take_enum_data_addr %0 : $*DynamicSingleton<T>, #DynamicSingleton.value!enumelt.1
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// Verify that we can instantiate generic enum instances of dynamic size.
|
|
sil_global @aa : $DynamicSingleton<()>
|
|
sil_global @bb : $DynamicSingleton<NoPayloads>
|
|
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_singleton_instance_arg_1()
|
|
sil @dynamic_singleton_instance_arg_1 : $(DynamicSingleton<()>) -> () {
|
|
entry(%0 : $DynamicSingleton<()>):
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
// CHECK: define{{( dllexport)?}}{{( protected)?}} swiftcc void @dynamic_singleton_instance_arg_2(i8)
|
|
sil @dynamic_singleton_instance_arg_2 : $(DynamicSingleton<NoPayloads>) -> () {
|
|
entry(%0 : $DynamicSingleton<NoPayloads>):
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// Check that payloads get properly masked in nested single-payload enums.
|
|
// rdar://problem/18841262
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @optional_optional_class_protocol(i64, i64)
|
|
// CHECK-objc-64-simulator-false: icmp eq i64 %0, 2
|
|
// CHECK-objc-64-simulator-true: icmp eq i64 %0, 1
|
|
// CHECK-native-64: icmp eq i64 %0, 1
|
|
// CHECK-32-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc i1 @optional_optional_class_protocol(i32, i32)
|
|
// CHECK-32: icmp eq i32 %0, 1
|
|
enum Optionable<T> {
|
|
case some(T), none
|
|
}
|
|
sil @optional_optional_class_protocol : $@convention(thin) (Optionable<Optionable<PC>>) -> Builtin.Int1 {
|
|
entry(%o : $Optionable<Optionable<PC>>):
|
|
%t = integer_literal $Builtin.Int1, 1
|
|
%f = integer_literal $Builtin.Int1, 0
|
|
%r = select_enum %o : $Optionable<Optionable<PC>>, case #Optionable.some!enumelt.1: %t, case #Optionable.none!enumelt: %f : $Builtin.Int1
|
|
return %r : $Builtin.Int1
|
|
}
|
|
|
|
struct ContainsUnowned {
|
|
unowned let x: C
|
|
}
|
|
struct ContainsUnownedObjC {
|
|
unowned let x: C
|
|
}
|
|
// CHECK-LABEL: define {{.*}} @optional_unowned() {{.*}} {
|
|
// CHECK-objc: ret { [[WORD]], [[WORD]], i8 } { [[WORD]] 0, [[WORD]] 0, i8 1 }
|
|
// CHECK-native: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 }
|
|
sil @optional_unowned : $@convention(thin) () -> (Optionable<ContainsUnowned>, Optionable<Optionable<ContainsUnowned>>) {
|
|
entry:
|
|
%a = enum $Optionable<ContainsUnowned>, #Optionable.none!enumelt
|
|
%b = enum $Optionable<Optionable<ContainsUnowned>>, #Optionable.none!enumelt
|
|
%t = tuple (%a : $Optionable<ContainsUnowned>, %b : $Optionable<Optionable<ContainsUnowned>>)
|
|
return %t : $(Optionable<ContainsUnowned>, Optionable<Optionable<ContainsUnowned>>)
|
|
}
|
|
// CHECK-LABEL: define {{.*}} @optional_unowned_objc() {{.*}} {
|
|
// CHECK-objc: ret { [[WORD]], [[WORD]], i8 } { [[WORD]] 0, [[WORD]] 0, i8 1 }
|
|
// CHECK-native: ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 }
|
|
sil @optional_unowned_objc : $@convention(thin) () -> (Optionable<ContainsUnownedObjC>, Optionable<Optionable<ContainsUnownedObjC>>) {
|
|
entry:
|
|
%a = enum $Optionable<ContainsUnownedObjC>, #Optionable.none!enumelt
|
|
%b = enum $Optionable<Optionable<ContainsUnownedObjC>>, #Optionable.none!enumelt
|
|
%t = tuple (%a : $Optionable<ContainsUnownedObjC>, %b : $Optionable<Optionable<ContainsUnownedObjC>>)
|
|
return %t : $(Optionable<ContainsUnownedObjC>, Optionable<Optionable<ContainsUnownedObjC>>)
|
|
}
|
|
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc { i64, i8 } @empty_payload_enum_in_enum(i32)
|
|
sil @empty_payload_enum_in_enum : $@convention(thin) (Int32) -> Optional<(Optional<()>, Int32)> {
|
|
entry(%x : $Int32):
|
|
%a = tuple ()
|
|
%b = enum $Optional<()>, #Optional.some!enumelt.1, %a : $()
|
|
%c = tuple (%b : $Optional<()>, %x : $Int32)
|
|
// CHECK-64: [[INT_ZEXT:%.*]] = zext i32 %0 to i64
|
|
// CHECK-64: [[INT_SHL:%.*]] = shl i64 [[INT_ZEXT]], 32
|
|
// CHECK-64: [[COMBINE:%.*]] = or i64 0, [[INT_SHL]]
|
|
%d = enum $Optional<(Optional<()>, Int32)>, #Optional.some!enumelt.1, %c : $(Optional<()>, Int32)
|
|
// CHECK-64: [[BIT:%.*]] = trunc i64 [[COMBINE]] to i1
|
|
// CHECK-64: [[INT_SHR:%.*]] = lshr i64 [[COMBINE]], 32
|
|
// CHECK-64: [[INT:%.*]] = trunc i64 [[INT_SHR]] to i32
|
|
%e = unchecked_enum_data %d : $Optional<(Optional<()>, Int32)>, #Optional.some!enumelt.1
|
|
return %d : $Optional<(Optional<()>, Int32)>
|
|
}
|
|
|
|
sil @optional_float80 : $@convention(thin) (Float80) -> () {
|
|
entry(%x : $Float80):
|
|
%y = enum $Optional<Float80>, #Optional.some!enumelt.1, %x : $Float80
|
|
return undef : $()
|
|
}
|
|
|
|
// rdar://problem/21126703
|
|
|
|
protocol delegateProtocol : AnyObject { }
|
|
|
|
struct StructWithWeakVar {
|
|
weak var delegate: delegateProtocol?
|
|
}
|
|
|
|
// CHECK-64-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @weak_optional(%T4enum17StructWithWeakVarVSg* noalias nocapture dereferenceable({{.*}}))
|
|
sil @weak_optional : $@convention(thin) (@in StructWithWeakVar?) -> () {
|
|
entry(%x : $*StructWithWeakVar?):
|
|
// CHECK-64: icmp eq [[WORD]] {{%.*}}, 0
|
|
// CHECK-64-NEXT: icmp eq [[WORD]] {{%.*}}, 1
|
|
switch_enum_addr %x : $*StructWithWeakVar?,
|
|
case #Optional.some!enumelt.1: a,
|
|
case #Optional.none!enumelt: b
|
|
a:
|
|
br x
|
|
b:
|
|
// CHECK-64: store [[WORD]] 0
|
|
// CHECK-64: store [[WORD]] 1
|
|
inject_enum_addr %x : $*StructWithWeakVar?, #Optional.none!enumelt
|
|
br x
|
|
|
|
x:
|
|
return undef : $()
|
|
}
|
|
|
|
public struct AnyError : Swift.Error { }
|
|
|
|
public enum Result<T, Error: Swift.Error> {
|
|
case success(T)
|
|
case failure(Error)
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @test_inject_enum_addr_with_bound_generic
|
|
sil @test_inject_enum_addr_with_bound_generic : $@convention(thin) <T> () -> @out Result<T, AnyError> {
|
|
bb0(%0 : $*Result<T, AnyError>):
|
|
// CHECK: call {{.*}} @"$s4enum6ResultOMa"
|
|
// CHECK: call void @swift_storeEnumTagMultiPayload
|
|
inject_enum_addr %0 : $*Result<T, AnyError>, #Result.success!enumelt.1
|
|
%r = tuple ()
|
|
// CHECK: ret void
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @force_global_variables_to_materialize
|
|
sil @force_global_variables_to_materialize : $() -> () {
|
|
entry:
|
|
// Force the global variables to materialize.
|
|
%x = global_addr @x : $*AllConcreteTestEnums
|
|
%y = load %x : $*AllConcreteTestEnums
|
|
%a = global_addr @aa : $*DynamicSingleton<()>
|
|
%q = load %a : $*DynamicSingleton<()>
|
|
%b = global_addr @bb : $*DynamicSingleton<NoPayloads>
|
|
%r = load %b : $*DynamicSingleton<NoPayloads>
|
|
%z = tuple ()
|
|
// CHECK: ret void
|
|
return %z : $()
|
|
}
|
|
|
|
enum Target {
|
|
case Public
|
|
case Friends
|
|
case SomeFriends([UInt])
|
|
}
|
|
|
|
// Ensure that we generate IR that does not run into verification
|
|
// issues for the case where there is a single tag bit and extra
|
|
// inhabitants.
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc void @generate_conditional_branch
|
|
sil @generate_conditional_branch : $@convention(thin) (@owned Target) -> () {
|
|
bb0(%0 : $Target):
|
|
debug_value %0 : $Target
|
|
retain_value %0 : $Target
|
|
switch_enum %0 : $Target, case #Target.Public!enumelt: bb1, default bb2
|
|
|
|
bb1:
|
|
br bb4
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
release_value %0 : $Target
|
|
br bb4
|
|
|
|
bb4:
|
|
release_value %0 : $Target
|
|
%9 = tuple ()
|
|
// CHECK: ret void
|
|
return %9 : $()
|
|
}
|
|
|
|
struct LargeStruct {
|
|
var x: Builtin.Int64
|
|
var x2: Builtin.Int64
|
|
var x3: Builtin.Int64
|
|
var x4: Builtin.Int64
|
|
var x5: Builtin.Int64
|
|
var x6: Builtin.NativeObject
|
|
}
|
|
|
|
enum MyOptional {
|
|
case None
|
|
case Some(LargeStruct)
|
|
}
|
|
|
|
// Make sure we use a memcpy for the none branch of the enum copy.
|
|
|
|
// CHECK-LABEL: define{{.*}} @test_large_optional
|
|
// CHECK: llvm.memcpy
|
|
// CHECK: ret void
|
|
sil @test_large_optional : $@convention(thin) (@in MyOptional) -> () {
|
|
entry(%x : $*MyOptional):
|
|
%stk = alloc_stack $MyOptional
|
|
copy_addr %x to [initialization] %stk : $*MyOptional
|
|
dealloc_stack %stk: $*MyOptional
|
|
%tuple = tuple ()
|
|
return %tuple : $()
|
|
}
|
|
|
|
// -- Fill function for dynamic singleton.
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$s4enum16DynamicSingletonOMi"(%swift.type_descriptor*, i8**, i8*) {{.*}} {
|
|
// CHECK: [[T0:%.*]] = bitcast i8** %1 to %swift.type**
|
|
// CHECK: [[T:%T]] = load %swift.type*, %swift.type** [[T0]],
|
|
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_descriptor* %0, i8** %1, i8* %2, [[WORD]] {{4|8}})
|
|
// CHECK-NEXT: ret %swift.type* [[METADATA]]
|
|
|
|
// CHECK-LABEL: define{{( protected)?}} internal swiftcc %swift.metadata_response @"$s4enum16DynamicSingletonOMr"
|
|
// CHECK-SAME: (%swift.type* [[METADATA:%.*]], i8*, i8**) {{.*}} {
|
|
// CHECK: [[T0:%.*]] = call{{( tail)?}} swiftcc %swift.metadata_response @swift_checkMetadataState([[WORD]] 319, %swift.type* [[T]])
|
|
// CHECK: [[T_CHECKED:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
|
|
// CHECK: [[T_STATUS:%.*]] = extractvalue %swift.metadata_response [[T0]], 1
|
|
// CHECK: [[T_OK:%.*]] = icmp ule [[WORD]] [[T_STATUS]], 63
|
|
// CHECK: br i1 [[T_OK]],
|
|
// CHECK: [[T_VWTS:%.*]] = bitcast %swift.type* [[T_CHECKED]] to i8***
|
|
// CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[T_VWTS]], [[WORD]] -1
|
|
// CHECK: [[T_VWT:%.*]] = load i8**, i8*** [[T_VWT_ADDR]]
|
|
// CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VWT]], i32 8
|
|
// CHECK: call void @swift_initEnumMetadataSingleCase(%swift.type* [[METADATA]], [[WORD]] 0, i8** [[T_LAYOUT]])
|
|
// CHECK: [[PAYLOAD_TYPELAYOUT:%.*]] = bitcast i8** [[T_LAYOUT]] to %swift.type_layout*
|
|
// CHECK: [[PAYLOAD_EXTRAINHABITANTCNT:%.*]] = getelementptr inbounds %swift.type_layout, %swift.type_layout* [[PAYLOAD_TYPELAYOUT]], i32 0, i32 3
|
|
// CHECK: [[CNT:%.*]] = load i32, i32* [[PAYLOAD_EXTRAINHABITANTCNT]]
|
|
// CHECK: [[METADATA2:%.*]] = bitcast %swift.type* [[METADATA]] to i8***
|
|
// CHECK: [[VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[METADATA2]], [[WORD]] -1
|
|
// CHECK: [[VWT:%.*]] = load i8**, i8*** [[VWT_ADDR]]
|
|
// CHECK: [[VWT2:%.*]] = bitcast i8** [[VWT]] to %swift.vwtable*
|
|
// CHECK: [[XIC_ADDR:%.*]] = getelementptr inbounds %swift.vwtable, %swift.vwtable* [[VWT2]], i32 0, i32 11
|
|
// CHECK: store i32 [[CNT]], i32* [[XIC_ADDR]]
|
|
// CHECK: ret %swift.metadata_response
|
|
|
|
// -- Fill function for dynamic single-payload. Call into the runtime to
|
|
// calculate the size.
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal %swift.type* @"$s4enum20DynamicSinglePayloadOMi"
|
|
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata
|
|
|
|
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} internal swiftcc %swift.metadata_response @"$s4enum20DynamicSinglePayloadOMr"
|
|
// CHECK-SAME: (%swift.type* [[METADATA:%.*]], i8*, i8**) {{.*}} {
|
|
// CHECK: [[T0:%.*]] = call{{( tail)?}} swiftcc %swift.metadata_response @swift_checkMetadataState([[WORD]] 319, %swift.type* [[T]])
|
|
// CHECK: [[T_CHECKED:%.*]] = extractvalue %swift.metadata_response [[T0]], 0
|
|
// CHECK: [[T_STATUS:%.*]] = extractvalue %swift.metadata_response [[T0]], 1
|
|
// CHECK: [[T_OK:%.*]] = icmp ule [[WORD]] [[T_STATUS]], 63
|
|
// CHECK: br i1 [[T_OK]],
|
|
// CHECK: [[T_VWTS:%.*]] = bitcast %swift.type* [[T_CHECKED]] to i8***
|
|
// CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[T_VWTS]], [[WORD]] -1
|
|
// CHECK: [[T_VWT:%.*]] = load i8**, i8*** [[T_VWT_ADDR]]
|
|
// CHECK: [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VWT]], i32 8
|
|
// CHECK: call void @swift_initEnumMetadataSinglePayload(%swift.type* [[METADATA]], [[WORD]] 0, i8** [[T_LAYOUT]], i32 3)
|
|
|
|
// CHECK-64-LABEL: define internal void @"$s4enum17StructWithWeakVarVwst"(%swift.opaque* noalias %value, i32 %whichCase, i32 %numEmptyCases, %swift.type* %StructWithWeakVar)
|
|
// -- TODO: some pointless masking here.
|
|
// -- TODO: should use EnumPayload word-chunking.
|
|
// CHECK-64: [[INDEX:%.*]] = sub i32 %whichCase, 1
|
|
// CHECK-64: [[T0:%.*]] = zext i32 [[INDEX]] to i128
|
|
// -- 0xFFFF_FFFF_FFFF_FFFF
|
|
// CHECK-64: [[T1:%.*]] = and i128 [[T0]], 18446744073709551615
|
|
// CHECK-64: [[T2:%.*]] = shl i128 [[T0]], 3
|
|
// -- 0xFFFF_FFFF_FFFF_FFF8__0000_0000_0000_0000
|
|
// CHECK-64: [[T3:%.*]] = and i128 [[T2]], 1329227995784915725329854470603931648
|
|
// CHECK-64: [[T4:%.*]] = or i128 [[T1]], [[T3]]
|
|
// -- 0x1__0000_0000_0000_0000
|
|
// CHECK-64: [[T5:%.*]] = or i128 [[T4]], 18446744073709551616
|
|
|
|
// CHECK-LABEL: define internal i32 @"$s4enum40MultiPayloadLessThan32BitsWithEmptyCasesOwug"(%swift.opaque* noalias %value
|
|
// CHECK: [[VAL00:%.*]] = bitcast %swift.opaque* %value to %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO*
|
|
// CHECK: [[VAL01:%.*]] = bitcast %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO* [[VAL00]] to i8*
|
|
// CHECK: [[VAL02:%.*]] = load {{.*}} [[VAL01]]
|
|
// CHECK: [[VAL03:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1
|
|
// CHECK: [[VAL04:%.*]] = bitcast {{.*}} [[VAL03]] to i8*
|
|
// CHECK: [[VAL05:%.*]] = load {{.*}} [[VAL04]]
|
|
// CHECK: [[VAL06:%.*]] = zext i8 [[VAL05]] to i32
|
|
// CHECK: [[VAL07:%.*]] = zext i8 [[VAL02]] to i32
|
|
// CHECK: [[VAL08:%.*]] = and i32 [[VAL07]], 255
|
|
// CHECK: [[VAL09:%.*]] = add i32 [[VAL08]], 2
|
|
// CHECK: [[VAL10:%.*]] = icmp uge i32 [[VAL06]], 2
|
|
// CHECK: [[VAL11:%.*]] = select i1 [[VAL10]], i32 [[VAL09]], i32 [[VAL06]]
|
|
// CHECK: ret i32 [[VAL11]]
|
|
|
|
// CHECK-LABEL: define internal void @"$s4enum40MultiPayloadLessThan32BitsWithEmptyCasesOwui"(%swift.opaque* noalias %value, i32 %tag
|
|
// CHECK: entry:
|
|
// CHECK: [[VAL00:%.*]] = bitcast %swift.opaque* %value
|
|
// CHECK: [[VAL01:%.*]] = icmp uge i32 %tag, 2
|
|
// CHECK: br i1 [[VAL01]], label %[[TLABEL:.*]], label %[[FLABEL:.*]]
|
|
|
|
// CHECK: <label>:[[TLABEL]]
|
|
// CHECK: [[VAL02:%.*]] = sub i32 %tag, 2
|
|
// CHECK: [[VAL03:%.*]] = trunc i32 [[VAL02]] to i8
|
|
// CHECK: [[VAL04:%.*]] = bitcast %T4enum40MultiPayloadLessThan32BitsWithEmptyCasesO* [[VAL00]] to i8*
|
|
// CHECK: store i8 [[VAL03]], i8* [[VAL04]]
|
|
// CHECK: [[VAL05:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1
|
|
// CHECK: [[VAL06:%.*]] = bitcast [1 x i8]* [[VAL05]] to i8*
|
|
// CHECK: store i8 2, i8* [[VAL06]]
|
|
// CHECK: br label %[[RLABEL:.*]]
|
|
|
|
// CHECK: <label>:[[FLABEL]]
|
|
// CHECK: [[VAL09:%.*]] = trunc i32 %tag to i8
|
|
// CHECK: [[VAL10:%.*]] = getelementptr inbounds {{.*}} [[VAL00]], i32 0, i32 1
|
|
// CHECK: [[VAL11:%.*]] = bitcast [1 x i8]* [[VAL10]] to i8*
|
|
// CHECK: store i8 [[VAL09]], i8* [[VAL11]]
|
|
// CHECK: br label %[[RLABEL]]
|
|
|
|
// CHECK: <label>:[[RLABEL]]
|
|
// CHECK: ret void
|
|
|
|
enum MultiPayloadLessThan32BitsWithEmptyCases {
|
|
case A
|
|
case B
|
|
case C(Builtin.Int8)
|
|
case D(Builtin.Int8)
|
|
}
|