Revision 42e827e6e7247224c068a9dce8f6eabd2ab892ba authored by Devin Coughlin on 21 January 2016, 00:12:56 UTC, committed by Devin Coughlin on 21 January 2016, 01:22:15 UTC
1 parent ac1f5a6
Raw File
enum.sil
// RUN: %target-swift-frontend %s -gnone -emit-ir -disable-objc-attr-requires-foundation-module | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize --check-prefix=CHECK-%target-runtime-%target-ptrsize

// REQUIRES: CPU=i386_or_x86_64

// We have to claim this is raw SIL because there are critical edges from non
// cond_br instructions.
sil_stage raw

import Builtin
import Swift

// -- Singleton enum. The representation is just the singleton payload.
// CHECK: %O4enum9Singleton = type <{ <{ i64, i64 }> }>

// -- Singleton enum with heap object ref payload. <rdar://problem/15679353>
// CHECK: %O4enum12SingletonRef = type <{ %swift.refcounted* }>

// -- No-payload enums. The representation is just an enum tag.
// CHECK: %O4enum10NoPayloads = type <{ i2 }>
// CHECK: %O4enum11NoPayloads2 = type <{ i3 }>

// -- Single-payload enum, no extra inhabitants in the payload type. The
//    representation adds a tag bit to distinguish payload from enum tag:
//      case x(i64): X0 X1 X2 ... X63 | 0, where X0...X63 are the payload bits
//      case y:      0  0  0  ... 0   | 1
//      case z:      1  0  0  ... 0   | 1
// CHECK-64: %O4enum17SinglePayloadNoXI = type <{ [8 x i8], [1 x i8] }>
// CHECK-64: %O4enum18SinglePayloadNoXI2 = type <{ [8 x i8], [1 x i8] }>
// CHECK-32: %O4enum17SinglePayloadNoXI = type <{ [4 x i8], [1 x i8] }>
// CHECK-32: %O4enum18SinglePayloadNoXI2 = type <{ [4 x i8], [1 x i8] }>

// -- Single-payload enum, spare bits. The representation uses a tag bit
//    out of the payload to distinguish payload from enum tag:
//      case x(i3): X0 X1 X2 0 0 0 0 0
//      case y:     0  0  0  1 0 0 0 0
//      case z:     1  0  0  1 0 0 0 0
// CHECK: %O4enum21SinglePayloadSpareBit = type <{ [8 x i8] }>

// -- Single-payload enum containing a no-payload enum as its payload.
//    The representation takes extra inhabitants starting after the greatest
//    discriminator value used by the nested no-payload enum.
// CHECK: %O4enum19SinglePayloadNested = type <{ [1 x i8] }>

// -- Single-payload enum containing another single-payload enum as its
//    payload.
//    The representation takes extra inhabitants from the nested enum's payload
//    that were unused by the nested enum.
// CHECK: %O4enum25SinglePayloadNestedNested = type <{ [1 x i8] }>

// -- Multi-payload enum, no spare bits. The representation adds tag bits
//    to discriminate payloads. No-payload cases all share a tag.
//      case x(i8): X0 X1 X2 ... X7 X8 | 0 0
//      case y(i7): Y0 Y1 Y2 ... Y7 0  | 1 0
//      case z(i2): Z0 Z1 0  ... 0  0  | 0 1
//      case a:     0  0  0  ... 0  0  | 1 1
//      case b:     1  0  0  ... 0  0  | 1 1
//      case c:     0  1  0  ... 0  0  | 1 1
// CHECK: %O4enum23MultiPayloadNoSpareBits = type <{ [8 x i8], [1 x i8] }>

// -- Multi-payload enum, one spare bit. The representation uses spare bits
//    common to all payloads to partially discriminate payloads, with added
//    tag bits to cover the gap. No-payload cases all share a tag.
//      case x(i7): X0 X1 X2 X3 X4 X5 X6 0 | 0
//      case y(i1): Y  0  0  0  0  0  0  1 | 0
//      case z(i5): Z0 Z1 Z2 Z3 Z4 0  0  0 | 1
//      case a:     0  0  0  0  0  0  0  1 | 1
//      case b:     1  0  0  0  0  0  0  1 | 1
//      case c:     0  1  0  0  0  0  0  1 | 1
// CHECK: %O4enum23MultiPayloadOneSpareBit = type <{ [8 x i8], [1 x i8] }>

// -- Multi-payload enum, two spare bits. Same as above, except we have enough
//    spare bits not to require any added tag bits.
//      case x(i6): X0 X1 X2 X3 X4 X5 0  0
//      case y(i1): Y  0  0  0  0  0  1  0
//      case z(i5): Z0 Z1 Z2 Z3 Z4 0  0  1
//      case a:     0  0  0  0  0  0  1  1
//      case b:     1  0  0  0  0  0  1  1
//      case c:     0  1  0  0  0  0  1  1
// CHECK: %O4enum24MultiPayloadTwoSpareBits = type <{ [8 x i8] }>

// CHECK-64: %O4enum30MultiPayloadSpareBitAggregates = type <{ [16 x i8] }>

// CHECK-64: %O4enum18MultiPayloadNested = type <{ [9 x i8] }>
// CHECK-32: %O4enum18MultiPayloadNested = type <{ [5 x i8] }>

// 32-bit object references don't have enough spare bits.
// CHECK-64: %O4enum27MultiPayloadNestedSpareBits = type <{ [8 x i8] }>

// -- Dynamic enums. The type layout is opaque; we dynamically bitcast to
//    the element type.
// CHECK: %O4enum20DynamicSinglePayload = type <{}>
// CHECK: [[DYNAMIC_SINGLE_EMPTY_PAYLOAD:%O4enum20DynamicSinglePayload\.[0-9]+]] = type <{ [1 x i8] }>

// -- Address-only multi-payload enums. We can't use spare bits.
// CHECK-64: %O4enum32MultiPayloadAddressOnlySpareBits = type <{ [16 x i8], [1 x i8] }>
// CHECK-32: %O4enum32MultiPayloadAddressOnlySpareBits = type <{ [8 x i8], [1 x i8] }>

// CHECK: [[DYNAMIC_SINGLETON:%O4enum16DynamicSingleton.*]] = type <{}>

// -- Dynamic metadata template carries a value witness table pattern
//    we fill in on instantiation.
//    The witness table pattern includes extra inhabitant witness
//    implementations which are used if the instance has extra inhabitants.
// CHECK: [[DYNAMICSINGLETON_FIELD_NAMES:@.*]] = private unnamed_addr constant [7 x i8] c"value\00\00"
// CHECK: [[DYNAMICSINGLETON_NAME:@.*]] = private unnamed_addr constant [25 x i8] c"O4enum16DynamicSingleton\00"
// CHECK: @_TMnO4enum16DynamicSingleton = constant { {{.*}} i32 } {
// --       2 = enum
// CHECK:   [[WORD:i64|i32]] 2,
// CHECK:   i8* getelementptr inbounds ([25 x i8], [25 x i8]* [[DYNAMICSINGLETON_NAME]]
// --       One payload
// CHECK:   i32 1,
// --       No empty cases
// CHECK:   i32 0,
// --       Case names
// CHECK:   [[DYNAMICSINGLETON_FIELD_NAMES]]
// --       Case type accessor
// CHECK:   @get_field_types_DynamicSingleton
// --       generic parameter vector offset
// CHECK:   i32 3,
// --       generic parameter vector length; witness table counts
// CHECK:   i32 1, i32 0
// CHECK: }

// CHECK: @_TMPO4enum16DynamicSingleton = global { {{.*}}* } {
// CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSingleton
// CHECK:   @_TMnO4enum16DynamicSingleton
// CHECK:   i8* null
// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum16DynamicSingleton to i8*)
// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum16DynamicSingleton to i8*)

// -- No-payload enums have extra inhabitants in
//    their value witness table.
// CHECK: @_TWVO4enum10NoPayloads = constant [26 x i8*] [
// -- ...
// -- size
// CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
// -- flags                 0x24_0000 - alignment 1, has extra inhabitants and enum witnesses
// CHECK:   i8* inttoptr ([[WORD]] 2359296 to i8*),
// -- stride
// CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
// -- num extra inhabitants (256 - 3 valid states)
// CHECK:   i8* inttoptr ([[WORD]] 253 to i8*)
// -- storeExtraInhabitant
// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum10NoPayloads to i8*)
// -- getExtraInhabitantIndex
// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum10NoPayloads to i8*)
// CHECK: ] 

// -- Single-payload enums take unused extra inhabitants from their payload
//    as their own.
// CHECK: @_TWVO4enum19SinglePayloadNested = constant [26 x i8*] [
// -- ...
// -- size
// CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
// -- flags                 0x4_0000 - alignment 1, has extra inhabitants
// CHECK:   i8* inttoptr ([[WORD]] 2359296 to i8*),
// -- stride
// CHECK:   i8* inttoptr ([[WORD]] 1 to i8*),
// -- num extra inhabitants (253 from payload - 3 empty cases)
// CHECK:   i8* inttoptr ([[WORD]] 250 to i8*)
// -- storeExtraInhabitant
// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum19SinglePayloadNested to i8*)
// -- getExtraInhabitantIndex
// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum19SinglePayloadNested to i8*)
// CHECK: ] 


// CHECK: @_TMPO4enum20DynamicSinglePayload = global { {{.*}}* } {
// CHECK:   %swift.type* (%swift.type_pattern*, i8**)* @create_generic_metadata_DynamicSinglePayload
// CHECK:   i8* null
// CHECK:   i8* bitcast (void (%swift.opaque*, i32, %swift.type*)* @_TwxsO4enum20DynamicSinglePayload to i8*)
// CHECK:   i8* bitcast (i32 (%swift.opaque*, %swift.type*)* @_TwxgO4enum20DynamicSinglePayload to i8*)

// CHECK: @_TWVO4enum18MultiPayloadNested = constant [26 x i8*] [
// CHECK:   i8* inttoptr ([[WORD]] 9 to i8*),
// CHECK:   i8* inttoptr ([[WORD]] 16 to i8*)
// CHECK: ]

enum Empty {}

enum EmptySingleton {
  case foo
}

enum Singleton {
  case value(Builtin.Int64, Builtin.Int64)
}

enum SingletonRef {
  case value(Builtin.NativeObject)
}

enum DynamicSingleton<T> {
  case value(T)
}

// CHECK: define void @singleton_switch(i64, i64) {{.*}} {
sil @singleton_switch : $(Singleton) -> () {
// CHECK: entry:
entry(%u : $Singleton):
// CHECK:   br label %[[DEST:[0-9]+]]
  switch_enum %u : $Singleton, case #Singleton.value!enumelt.1: dest

// CHECK: ; <label>:[[DEST]]
dest:
// CHECK:   ret void
  %x = tuple ()
  return %x : $()
}

// CHECK: define void @singleton_switch_arg(i64, i64) {{.*}} {
sil @singleton_switch_arg : $(Singleton) -> () {
// CHECK: entry:
entry(%u : $Singleton):
// CHECK:   br label %[[PREDEST:[0-9]+]]
  switch_enum %u : $Singleton, case #Singleton.value!enumelt.1: dest

// CHECK: ; <label>:[[PREDEST]]
// CHECK:   br label %[[DEST:[0-9]+]]
// CHECK: ; <label>:[[DEST]]
dest(%u2 : $(Builtin.Int64, Builtin.Int64)):
// CHECK:   {{%.*}} = phi i64 [ %0, %[[PREDEST]] ]
// CHECK:   {{%.*}} = phi i64 [ %1, %[[PREDEST]] ]
// CHECK:   ret void
  %x = tuple ()
  return %x : $()
}

// CHECK: define void @singleton_switch_indirect(%O4enum9Singleton* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: entry:
// CHECK:   br label %[[DEST:[0-9]+]]
// CHECK: ; <label>:[[DEST]]
// CHECK:   [[ADDR:%.*]] = bitcast %O4enum9Singleton* %0 to <{ i64, i64 }>*
// CHECK:   ret void
// CHECK: }
sil @singleton_switch_indirect : $(@inout Singleton) -> () {
entry(%u : $*Singleton):
  switch_enum_addr %u : $*Singleton, case #Singleton.value!enumelt.1: dest
dest:
  %u2 = unchecked_take_enum_data_addr %u : $*Singleton, #Singleton.value!enumelt.1
  %x = tuple ()
  return %x : $()
}

// CHECK: define { i64, i64 } @singleton_inject(i64, i64) {{.*}} {
// CHECK: entry:
// CHECK:   [[A:%.*]] = insertvalue { i64, i64 } undef, i64 %0, 0
// CHECK:   [[B:%.*]] = insertvalue { i64, i64 } [[A]], i64 %1, 1
// CHECK:   ret { i64, i64 } [[B]]
// CHECK: }
sil @singleton_inject : $(Builtin.Int64, Builtin.Int64) -> Singleton {
entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
  %t = tuple (%0 : $Builtin.Int64, %1 : $Builtin.Int64)
  %u = enum $Singleton, #Singleton.value!enumelt.1, %t : $(Builtin.Int64, Builtin.Int64)
  return %u : $Singleton
}

// CHECK: define void @singleton_inject_indirect(i64, i64, %O4enum9Singleton* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: entry:
// CHECK:   [[DATA_ADDR:%.*]] = bitcast %O4enum9Singleton* %2 to <{ i64, i64 }>*
// CHECK:   [[DATA_0_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 0
// CHECK:   store i64 %0, i64* [[DATA_0_ADDR]]
// CHECK:   [[DATA_1_ADDR:%.*]] = getelementptr inbounds <{ i64, i64 }>, <{ i64, i64 }>* [[DATA_ADDR]], i32 0, i32 1
// CHECK:   store i64 %1, i64* [[DATA_1_ADDR]]
// CHECK:   ret void
// CHECK: }
sil @singleton_inject_indirect : $(Builtin.Int64, Builtin.Int64, @inout Singleton) -> () {
entry(%0 : $Builtin.Int64, %1 : $Builtin.Int64, %2 : $*Singleton):
  %t = tuple (%0 : $Builtin.Int64, %1 : $Builtin.Int64)
  %a = init_enum_data_addr %2 : $*Singleton, #Singleton.value!enumelt.1
  store %t to %a : $*(Builtin.Int64, Builtin.Int64)
  inject_enum_addr %2 : $*Singleton, #Singleton.value!enumelt.1
  %v = tuple ()
  return %v : $()
}


enum NoPayloads {
  case x
  case y
  case z
}

sil @a : $@convention(thin) () -> ()
sil @b : $@convention(thin) () -> ()
sil @c : $@convention(thin) () -> ()
sil @d : $@convention(thin) () -> ()
sil @e : $@convention(thin) () -> ()
sil @f : $@convention(thin) () -> ()


// CHECK: define void @no_payload_switch(i2) {{.*}} {
sil @no_payload_switch : $@convention(thin) (NoPayloads) -> () {
// CHECK: entry:
entry(%u : $NoPayloads):
// CHECK:   switch i2 %0, label %[[DFLT:[0-9]+]] [
// CHECK:     i2 0, label %[[X_DEST:[0-9]+]]
// CHECK:     i2 1, label %[[Y_DEST:[0-9]+]]
// CHECK:     i2 -2, label %[[Z_DEST:[0-9]+]]
// CHECK:   ]
// CHECK: ; <label>:[[DFLT]]
// CHECK:   unreachable
  switch_enum %u : $NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest

// CHECK: ; <label>:[[X_DEST]]
// CHECK:   call void @a()
// CHECK:   br label %[[END:[0-9]+]]
x_dest:
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
  br end
// CHECK: ; <label>:[[Y_DEST]]
// CHECK:   call void @b()
// CHECK:   br label %[[END]]
y_dest:
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
  br end
// CHECK: ; <label>:[[Z_DEST]]
// CHECK:   call void @c()
// CHECK:   br label %[[END]]
z_dest:
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[END]]
// CHECK:   ret void
end:
  %x = tuple ()
  return %x : $()
}

// CHECK: define void @no_payload_switch_indirect(%O4enum10NoPayloads* nocapture dereferenceable({{.*}})) {{.*}} {
sil @no_payload_switch_indirect : $@convention(thin) (@inout NoPayloads) -> () {
entry(%u : $*NoPayloads):
// CHECK:   [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads, %O4enum10NoPayloads* %0, i32 0, i32 0
// CHECK:   [[TAG:%.*]] = load i2, i2* [[TAG_ADDR]]
// CHECK:   switch i2 [[TAG]]
  switch_enum_addr %u : $*NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest

x_dest:
  br end
y_dest:
  br end
z_dest:
  br end
end:
  %x = tuple ()
  return %x : $()
}

// CHECK: define i2 @no_payload_inject_x() {{.*}} {
// CHECK: entry:
// CHECK:   ret i2 0
// CHECK: }
sil @no_payload_inject_x : $() -> NoPayloads {
entry:
  %u = enum $NoPayloads, #NoPayloads.x!enumelt
  return %u : $NoPayloads
}

// CHECK: define i2 @no_payload_inject_y() {{.*}} {
// CHECK: entry:
// CHECK:   ret i2 1
// CHECK: }
sil @no_payload_inject_y : $() -> NoPayloads {
entry:
  %u = enum $NoPayloads, #NoPayloads.y!enumelt
  return %u : $NoPayloads
}

// CHECK: define i2 @no_payload_inject_z() {{.*}} {
// CHECK: entry:
// CHECK:   ret i2 -2
// CHECK: }
sil @no_payload_inject_z : $() -> NoPayloads {
entry:
  %u = enum $NoPayloads, #NoPayloads.z!enumelt
  return %u : $NoPayloads
}

// CHECK: define void @no_payload_inject_z_indirect(%O4enum10NoPayloads* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: entry:
// CHECK:   [[TAG_ADDR:%.*]] = getelementptr inbounds %O4enum10NoPayloads, %O4enum10NoPayloads* %0, i32 0, i32 0
// CHECK:   store i2 -2, i2* [[TAG_ADDR]]
// CHECK:   ret void
// CHECK: }
sil @no_payload_inject_z_indirect : $(@inout NoPayloads) -> () {
entry(%0 : $*NoPayloads):
  inject_enum_addr %0 : $*NoPayloads, #NoPayloads.z!enumelt
  %v = tuple ()
  return %v : $()
}


enum NoPayloads2 {
  case a
  case e
  case i
  case o
  case u
  case y
}

// CHECK: define void @no_payload_switch_2(i3) {{.*}} {
sil @no_payload_switch_2 : $@convention(thin) (NoPayloads2) -> () {
// CHECK: entry:
entry(%u : $NoPayloads2):
// CHECK:   switch i3 %0, label %[[DEFAULT_DEST:[0-9]+]] [
// CHECK:     i3 -4, label %[[U_DEST:[0-9]+]]
// CHECK:   ]
  switch_enum %u : $NoPayloads2, case #NoPayloads2.u!enumelt: u_dest, default default_dest

// CHECK: ; <label>:[[U_DEST]]
u_dest:
// CHECK:   call void @a()
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
// CHECK:   br label %[[END:[0-9]+]]
  br end

// CHECK: ; <label>:[[DEFAULT_DEST]]
default_dest:
// CHECK:   call void @b()
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
// CHECK:   br label %[[END]]
  br end

// CHECK: ; <label>:[[END]]
end:
// CHECK:   ret void
  %x = tuple ()
  return %x : $()
}


enum SinglePayloadNoXI {
  case x(Builtin.Word)
  case y
}

enum SinglePayloadNoXI2 {
  case x(Builtin.Word)
  case y
  case z
  case w
  case v
  case u
}

// CHECK-64: define void @single_payload_no_xi_switch([[WORD:i64]], i1) {{.*}} {
// CHECK-32: define void @single_payload_no_xi_switch([[WORD:i32]], i1) {{.*}} {
sil @single_payload_no_xi_switch : $@convention(thin) (SinglePayloadNoXI2) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadNoXI2):
// CHECK:   br i1 %1, label %[[TAGS:[0-9]+]], label %[[X_DEST:[0-9]+]]
// CHECK: ; <label>:[[TAGS]]
// CHECK:   switch [[WORD]] %0, label %[[DFLT:[0-9]+]] [
// CHECK:     [[WORD]] 0, label %[[Y_DEST:[0-9]+]]
// CHECK:     [[WORD]] 1, label %[[Z_DEST:[0-9]+]]
// CHECK:     [[WORD]] 2, label %[[W_DEST:[0-9]+]]
// CHECK:     [[WORD]] 3, label %[[V_DEST:[0-9]+]]
// CHECK:     [[WORD]] 4, label %[[U_DEST:[0-9]+]]
// CHECK:   ]
// CHECK: ; <label>:[[DFLT]]
// CHECK:   unreachable
  switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt.1: x_dest, case #SinglePayloadNoXI2.y!enumelt: y_dest, case #SinglePayloadNoXI2.z!enumelt: z_dest, case #SinglePayloadNoXI2.w!enumelt: w_dest, case #SinglePayloadNoXI2.v!enumelt: v_dest, case #SinglePayloadNoXI2.u!enumelt: u_dest


// CHECK: ; <label>:[[X_DEST]]
// CHECK:   call void @a()
// CHECK:   br label %[[END:[0-9]+]]
x_dest:
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[Y_DEST]]
// CHECK:   call void @b()
// CHECK:   br label %[[END]]
y_dest:
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[Z_DEST]]
// CHECK:   call void @c()
// CHECK:   br label %[[END]]
z_dest:
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[W_DEST]]
// CHECK:   call void @a()
// CHECK:   br label %[[END:[0-9]+]]
w_dest:
  %d = function_ref @a : $@convention(thin) () -> ()
  apply %d() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[V_DEST]]
// CHECK:   call void @b()
// CHECK:   br label %[[END]]
v_dest:
  %e = function_ref @b : $@convention(thin) () -> ()
  apply %e() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[U_DEST]]
// CHECK:   call void @c()
// CHECK:   br label %[[END]]
u_dest:
  %f = function_ref @c : $@convention(thin) () -> ()
  apply %f() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[END]]
// CHECK:   ret void
end:
  %x = tuple ()
  return %x : $()
}

// CHECK: define void @single_payload_no_xi_switch_arg([[WORD]], i1) {{.*}} {
sil @single_payload_no_xi_switch_arg : $@convention(thin) (SinglePayloadNoXI2) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadNoXI2):
// CHECK:   br i1 %1, label %[[TAGS:[0-9]+]], label %[[X_PREDEST:[0-9]+]]
// CHECK: ; <label>:[[TAGS]]
// CHECK:   switch [[WORD]] %0, label %[[DFLT:[0-9]+]] [
// CHECK:     [[WORD]] 0, label %[[Y_DEST:[0-9]+]]
// CHECK:     [[WORD]] 1, label %[[Z_DEST:[0-9]+]]
// CHECK:     [[WORD]] 2, label %[[SPLITEDGE:[0-9]+]]
// CHECK:     [[WORD]] 3, label %[[SPLITEDGE]]
// CHECK:     [[WORD]] 4, label %[[SPLITEDGE]]
// CHECK:   ]
// CHECK: ; <label>:[[DFLT]]
// CHECK:   unreachable
  switch_enum %u : $SinglePayloadNoXI2, case #SinglePayloadNoXI2.x!enumelt.1: x_dest, case #SinglePayloadNoXI2.y!enumelt: y_dest, case #SinglePayloadNoXI2.z!enumelt: z_dest, default end

// CHECK: ; <label>:[[X_PREDEST]]
// CHECK:   br label %[[X_DEST:[0-9]+]]
// CHECK: ; <label>:[[SPLITEDGE]]
// CHECK:   br label %[[END:[0-9]+]]
// CHECK: ; <label>:[[X_DEST]]
// CHECK:   {{%.*}} = phi [[WORD]] [ %0, %[[X_PREDEST]] ]
x_dest(%u2 : $Builtin.Word):
// CHECK:   call void @a()
// CHECK:   br label %[[END]]
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[Y_DEST]]
y_dest:
// CHECK:   call void @b()
// CHECK:   br label %[[END]]
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[Z_DEST]]
z_dest:
// CHECK:   call void @c()
// CHECK:   br label %[[END]]
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
  br end

// CHECK: ; <label>:[[END]]
// CHECK:   ret void
end:
  %x = tuple ()
  return %x : $()
}

// CHECK: define { [[WORD]], i1 } @single_payload_no_xi_inject_x([[WORD]]) {{.*}} {
// CHECK: entry:
// CHECK:   [[A:%.*]] = insertvalue { [[WORD]], i1 } undef, [[WORD]] %0, 0
// CHECK:   [[B:%.*]] = insertvalue { [[WORD]], i1 } [[A]], i1 false, 1
// CHECK:   ret { [[WORD]], i1 } [[B]]
// CHECK: }
sil @single_payload_no_xi_inject_x : $(Builtin.Word) -> SinglePayloadNoXI2 {
entry(%0 : $Builtin.Word):
  %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1, %0 : $Builtin.Word
  return %u : $SinglePayloadNoXI2
}

// CHECK: define void @single_payload_no_xi_inject_x_indirect([[WORD]], %O4enum18SinglePayloadNoXI2* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: entry:
// CHECK:   [[DATA_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %1 to [[WORD]]*
// CHECK:   store [[WORD]] %0, [[WORD]]* [[DATA_ADDR]]
// CHECK:   [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2, %O4enum18SinglePayloadNoXI2* %1, i32 0, i32 1
// CHECK:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK:   store i1 false, i1* [[TAG_ADDR]]
// CHECK:   ret void
// CHECK: }
sil @single_payload_no_xi_inject_x_indirect : $(Builtin.Word, @inout SinglePayloadNoXI2) -> () {
entry(%0 : $Builtin.Word, %1 : $*SinglePayloadNoXI2):
  %a = init_enum_data_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1
  store %0 to %a : $*Builtin.Word
  inject_enum_addr %1 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.x!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK: define { [[WORD]], i1 } @single_payload_no_xi_inject_y() {{.*}} {
// CHECK: entry:
// CHECK:   ret { [[WORD]], i1 } { [[WORD]] 0, i1 true }
// CHECK: }
sil @single_payload_no_xi_inject_y : $() -> SinglePayloadNoXI2 {
entry:
  %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt
  return %u : $SinglePayloadNoXI2
}

// CHECK: define void @single_payload_no_xi_inject_y_indirect(%O4enum18SinglePayloadNoXI2* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: entry:
// CHECK:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum18SinglePayloadNoXI2* %0 to [[WORD]]*
// CHECK:   store [[WORD]] 0, [[WORD]]* [[PAYLOAD_ADDR]]
// CHECK:   [[T0:%.*]] = getelementptr inbounds %O4enum18SinglePayloadNoXI2, %O4enum18SinglePayloadNoXI2* %0, i32 0, i32 1
// CHECK:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK:   store i1 true, i1* [[TAG_ADDR]]
// CHECK:   ret void
// CHECK: }
sil @single_payload_no_xi_inject_y_indirect : $(@inout SinglePayloadNoXI2) -> () {
entry(%0 : $*SinglePayloadNoXI2):
  inject_enum_addr %0 : $*SinglePayloadNoXI2, #SinglePayloadNoXI2.y!enumelt
  %v = tuple ()
  return %v : $()
}

// CHECK: define { [[WORD]], i1 } @single_payload_no_xi_inject_z() {{.*}} {
// CHECK: entry:
// CHECK:   ret { [[WORD]], i1 } { [[WORD]] 1, i1 true }
// CHECK: }
sil @single_payload_no_xi_inject_z : $() -> SinglePayloadNoXI2 {
entry:
  %u = enum $SinglePayloadNoXI2, #SinglePayloadNoXI2.z!enumelt
  return %u : $SinglePayloadNoXI2
}


// -- Test packing and unpacking aggregates.

enum AggregateSinglePayload {
  case x(Builtin.Word, Builtin.Word)
  case y
  case z
}

sil @int21_sink : $@convention(thin) (Builtin.Int21) -> ()
sil @int64_sink : $@convention(thin) (Builtin.Word) -> ()

// CHECK-LABEL: define void @aggregate_single_payload_unpack
// CHECK:         ([[WORD]], [[WORD]], i1) {{.*}} {
sil @aggregate_single_payload_unpack : $@convention(thin) (AggregateSinglePayload) -> () {
entry(%u : $AggregateSinglePayload):
  switch_enum %u : $AggregateSinglePayload, case #AggregateSinglePayload.x!enumelt.1: x_dest, default end

  // CHECK: [[FIRST:%.*]] = phi [[WORD]] [ %0
  // CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1
  // CHECK: call void @int64_sink([[WORD]] [[FIRST]])
  // CHECK: call void @int64_sink([[WORD]] [[SECOND]])
x_dest(%v : $(Builtin.Word, Builtin.Word)):
  %f = function_ref @int64_sink : $@convention(thin) (Builtin.Word) -> ()
  %a = tuple_extract %v : $(Builtin.Word, Builtin.Word), 0
  %b = tuple_extract %v : $(Builtin.Word, Builtin.Word), 1
  %c = apply %f(%a) : $@convention(thin) (Builtin.Word) -> ()
  %d = apply %f(%b) : $@convention(thin) (Builtin.Word) -> ()
  br end

end:
  %x = tuple ()
  return %x : $()
}

// CHECK: define { [[WORD]], [[WORD]] } @aggregate_single_payload_unsafe_unpack([[WORD]], [[WORD]], i1) {{.*}} {
// CHECK:  [[A:%.*]] = insertvalue { [[WORD]], [[WORD]] } undef, [[WORD]] %0, 0
// CHECK:  [[B:%.*]] = insertvalue { [[WORD]], [[WORD]] } [[A]], [[WORD]] %1, 1
// CHECK:  ret { [[WORD]], [[WORD]] } [[B]]
sil @aggregate_single_payload_unsafe_unpack : $@convention(thin) (AggregateSinglePayload) -> (Builtin.Word, Builtin.Word) {
entry(%u : $AggregateSinglePayload):
  %x = unchecked_enum_data %u : $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1
  return %x : $(Builtin.Word, Builtin.Word)
}

// CHECK: define { [[WORD]], [[WORD]], i1 } @aggregate_single_payload_inject([[WORD]], [[WORD]]) {{.*}} {
// CHECK: entry:
// CHECK:   [[RES_0:%.*]] = insertvalue { [[WORD]], [[WORD]], i1 } undef, [[WORD]] %0, 0
// CHECK:   [[RES_1:%.*]] = insertvalue { [[WORD]], [[WORD]], i1 } [[RES_0]], [[WORD]] %1, 1
// CHECK:   [[RES:%.*]] = insertvalue { [[WORD]], [[WORD]], i1 } [[RES_1]], i1 false, 2
// CHECK:   ret { [[WORD]], [[WORD]], i1 } [[RES]]
// CHECK: }
sil @aggregate_single_payload_inject : $(Builtin.Word, Builtin.Word) -> AggregateSinglePayload {
entry(%0 : $Builtin.Word, %1 : $Builtin.Word):
  %t = tuple (%0 : $Builtin.Word, %1 : $Builtin.Word)
  %u = enum $AggregateSinglePayload, #AggregateSinglePayload.x!enumelt.1, %t : $(Builtin.Word, Builtin.Word)
  return %u : $AggregateSinglePayload
}

struct CharLike { var value : Builtin.Int21 }
struct IntLike { var value : Builtin.Word }
struct RangeLike { var from, to : Builtin.Word }

enum AggregateSinglePayload2 {
  case x(CharLike, IntLike, RangeLike)
  case y
  case z
}

// CHECK: define void @aggregate_single_payload_unpack_2(%O4enum23AggregateSinglePayload2* noalias nocapture dereferenceable({{.*}})) {{.*}} {
sil @aggregate_single_payload_unpack_2 : $@convention(thin) (AggregateSinglePayload2) -> () {
entry(%u : $AggregateSinglePayload2):
// CHECK: [[CHUNK0:%.*]] = load [[WORD]]
// CHECK: [[CHUNK1:%.*]] = load [[WORD]]
// CHECK: [[CHUNK2:%.*]] = load [[WORD]]
// CHECK: [[CHUNK3:%.*]] = load [[WORD]]
  switch_enum %u : $AggregateSinglePayload2, case #AggregateSinglePayload2.x!enumelt.1: x_dest, default end

// CHECK:   [[TRUNC:%.*]] = trunc [[WORD]] [[CHUNK0]] to i21
// CHECK:   phi i21 [ [[TRUNC]]
// CHECK:   phi [[WORD]] [ [[CHUNK1]]
// CHECK:   phi [[WORD]] [ [[CHUNK2]]
// CHECK:   phi [[WORD]] [ [[CHUNK3]]
x_dest(%v : $(CharLike, IntLike, RangeLike)):
  br end

end:
  %x = tuple ()
  return %x : $()
}

// CHECK: define void @aggregate_single_payload_2_inject(%O4enum23AggregateSinglePayload2* noalias nocapture sret, i21, [[WORD]], [[WORD]], [[WORD]]) {{.*}} {
// CHECK: entry:
// CHECK:   [[ZEXT_0:%.*]] = zext i21 %1 to [[WORD]]
// CHECK:   store [[WORD]] [[ZEXT_0]]
// CHECK:   store [[WORD]] %2
// CHECK:   store [[WORD]] %3
// CHECK:   store [[WORD]] %4
// CHECK: }
sil @aggregate_single_payload_2_inject : $(CharLike, IntLike, RangeLike) -> AggregateSinglePayload2 {
entry(%0 : $CharLike, %1 : $IntLike, %2 : $RangeLike):
  %t = tuple (%0 : $CharLike, %1 : $IntLike, %2 : $RangeLike)
  %u = enum $AggregateSinglePayload2, #AggregateSinglePayload2.x!enumelt.1, %t : $(CharLike, IntLike, RangeLike)
  return %u : $AggregateSinglePayload2
}

enum AggregateSinglePayload3 {
  case x(Builtin.Int21, Builtin.Word)
  case y
  case z
}

// CHECK: define void @aggregate_single_payload_unpack_3([[WORD]], [[WORD]]) {{.*}} {
sil @aggregate_single_payload_unpack_3 : $@convention(thin) (AggregateSinglePayload3) -> () {
entry(%u : $AggregateSinglePayload3):
  switch_enum %u : $AggregateSinglePayload3, case #AggregateSinglePayload3.x!enumelt.1: x_dest, default end

  // CHECK: [[TRUNC:%.*]] = trunc [[WORD]] %0 to i21
  // CHECK: [[FIRST:%.*]] = phi i21 [ [[TRUNC]]
  // CHECK: [[SECOND:%.*]] = phi [[WORD]] [ %1
  // CHECK: call void @int21_sink(i21 [[FIRST]])
  // CHECK: call void @int64_sink([[WORD]] [[SECOND]])
x_dest(%v : $(Builtin.Int21, Builtin.Word)):
  %f = function_ref @int21_sink : $@convention(thin) (Builtin.Int21) -> ()
  %g = function_ref @int64_sink : $@convention(thin) (Builtin.Word) -> ()
  %a = tuple_extract %v : $(Builtin.Int21, Builtin.Word), 0
  %b = tuple_extract %v : $(Builtin.Int21, Builtin.Word), 1
  %c = apply %f(%a) : $@convention(thin) (Builtin.Int21) -> ()
  %d = apply %g(%b) : $@convention(thin) (Builtin.Word) -> ()
  br end

end:
  %x = tuple ()
  return %x : $()
}

// CHECK: define { [[WORD]], [[WORD]] } @aggregate_single_payload_inject_x3(i21, [[WORD]]) {{.*}} {
// CHECK: entry:
// CHECK:   [[ZEXT_0:%.*]] = zext i21 %0 to [[WORD]]
// CHECK:   [[A:%.*]] = insertvalue { [[WORD]], [[WORD]] } undef, [[WORD]] [[ZEXT_0]], 0
// CHECK:   [[B:%.*]] = insertvalue { [[WORD]], [[WORD]] } [[A]], [[WORD]] %1, 1
// CHECK:   ret { [[WORD]], [[WORD]] } [[B]]
// CHECK: }
sil @aggregate_single_payload_inject_x3 : $(Builtin.Int21, Builtin.Word) -> AggregateSinglePayload3 {
entry(%0 : $Builtin.Int21, %1 : $Builtin.Word):
  %t = tuple (%0 : $Builtin.Int21, %1 : $Builtin.Word)
  %u = enum $AggregateSinglePayload3, #AggregateSinglePayload3.x!enumelt.1, %t : $(Builtin.Int21, Builtin.Word)
  return %u : $AggregateSinglePayload3
}

// CHECK: define { [[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 void @single_payload_spare_bit_switch(i64) {{.*}} {
// CHECK-32: define void @single_payload_spare_bit_switch(i32, i32) {{.*}} {
sil @single_payload_spare_bit_switch : $@convention(thin) (SinglePayloadSpareBit) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadSpareBit):
// CHECK-64:  switch i64 %0, label %[[X_DEST:[0-9]+]] [
// --              0x8000_0000_0000_0000
// CHECK-64:    i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]]
// --              0x8000_0000_0000_0001
// CHECK-64:    i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]]
// CHECK-64:  ]

// CHECK-32:  switch i32 %0, label %[[X_DEST:[0-9]+]] [
// CHECK-32:    i32 0, label %[[Y_HIGH:[0-9]+]]
// CHECK-32:    i32 1, label %[[Z_HIGH:[0-9]+]]
// CHECK-32:  ]
// CHECK-32: ; <label>:[[Y_HIGH]]
// CHECK-32:  [[IS_Y:%.*]] = icmp eq i32 %1, -2147483648
// CHECK-32:  br i1 [[IS_Y]], label %[[Y_DEST:[0-9]+]], label %[[X_DEST]]
// CHECK-32: ; <label>:[[Z_HIGH]]
// CHECK-32:  [[IS_Z:%.*]] = icmp eq i32 %1, -2147483648
// CHECK-32:  br i1 [[IS_Z]], label %[[Z_DEST:[0-9]+]], label %[[X_DEST]]
  switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest

// CHECK: ; <label>:[[X_DEST]]
x_dest:
// CHECK:   call void @a()
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
// CHECK:   br label %[[END:[0-9]+]]
  br end

// CHECK: ; <label>:[[Y_DEST]]
y_dest:
// CHECK:   call void @b()
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
// CHECK:   br label %[[END]]
  br end

// CHECK: ; <label>:[[Z_DEST]]
z_dest:
// CHECK:   call void @c()
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
// CHECK:   br label %[[END]]
  br end

// CHECK: ; <label>:[[END]]
end:
// CHECK:   ret void
  %x = tuple ()
  return %x : $()
}

// CHECK-64: define void @single_payload_spare_bit_switch_arg(i64) {{.*}} {
sil @single_payload_spare_bit_switch_arg : $@convention(thin) (SinglePayloadSpareBit) -> () {
// CHECK: entry:
entry(%u : $SinglePayloadSpareBit):
// CHECK-64:  switch i64 %0, label %[[X_PREDEST:[0-9]+]] [
// --           0x8000_0000_0000_0000
// CHECK-64:    i64 -9223372036854775808, label %[[Y_DEST:[0-9]+]]
// --           0x8000_0000_0000_0001
// CHECK-64:    i64 -9223372036854775807, label %[[Z_DEST:[0-9]+]]
// CHECK-64:  ]
  switch_enum %u : $SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest

// CHECK-64: ; <label>:[[X_PREDEST]]
// CHECK-64:   [[TRUNC_PAYLOAD:%.*]] = trunc i64 %0 to i63
// CHECK-64:   br label %[[X_DEST:[0-9]+]]
// CHECK-64: ; <label>:[[X_DEST]]
// CHECK-64:   {{%.*}} = phi i63 [ [[TRUNC_PAYLOAD]], %[[X_PREDEST]] ]
x_dest(%u2 : $Builtin.Int63):
// CHECK-64:   call void @a()
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
// CHECK-64:   br label %[[END:[0-9]+]]
  br end

// CHECK-64: ; <label>:[[Y_DEST]]
y_dest:
// CHECK-64:   call void @b()
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
// CHECK-64:   br label %[[END]]
  br end

// CHECK-64: ; <label>:[[Z_DEST]]
z_dest:
// CHECK-64:   call void @c()
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
// CHECK-64:   br label %[[END]]
  br end

// CHECK-64: ; <label>:[[END]]
end:
// CHECK-64:   ret void
  %x = tuple ()
  return %x : $()
}

sil @single_payload_spare_bit_switch_indirect : $@convention(thin) (@inout SinglePayloadSpareBit) -> () {
entry(%u : $*SinglePayloadSpareBit):
// CHECK-64:  [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64*
// CHECK-64:  [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// CHECK-64:  switch i64 [[PAYLOAD]]
  switch_enum_addr %u : $*SinglePayloadSpareBit, case #SinglePayloadSpareBit.x!enumelt.1: x_dest, case #SinglePayloadSpareBit.y!enumelt: y_dest, case #SinglePayloadSpareBit.z!enumelt: z_dest

// CHECK-64: ; <label>:
// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i63*
x_dest:
  %u2 = unchecked_take_enum_data_addr %u : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
  br end

y_dest:
  br end

z_dest:
  br end

end:
  %x = tuple ()
  return %x : $()
}

// CHECK-64: define i64 @single_payload_spare_bit_inject_x(i63) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[A:%.*]] = zext i63 %0 to i64
// CHECK-64:   ret i64 [[A]]
// CHECK-64: }
sil @single_payload_spare_bit_inject_x : $(Builtin.Int63) -> SinglePayloadSpareBit {
entry(%0 : $Builtin.Int63):
  %u = enum $SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1, %0 : $Builtin.Int63
  return %u : $SinglePayloadSpareBit
}

// CHECK-64: define void @single_payload_spare_bit_inject_x_indirect(i63, %O4enum21SinglePayloadSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %1 to i63*
// CHECK-64:   store i63 %0, i63* [[DATA_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @single_payload_spare_bit_inject_x_indirect : $(Builtin.Int63, @inout SinglePayloadSpareBit) -> () {
entry(%0 : $Builtin.Int63, %1 : $*SinglePayloadSpareBit):
  %a = init_enum_data_addr %1 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1
  store %0 to %a : $*Builtin.Int63
  inject_enum_addr %1 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.x!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define 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 void @single_payload_spare_bit_inject_y_indirect(%O4enum21SinglePayloadSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum21SinglePayloadSpareBit* %0 to i64*
// --                0x8000_0000_0000_0000
// CHECK-64:   store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @single_payload_spare_bit_inject_y_indirect : $(@inout SinglePayloadSpareBit) -> () {
entry(%0 : $*SinglePayloadSpareBit):
  inject_enum_addr %0 : $*SinglePayloadSpareBit, #SinglePayloadSpareBit.y!enumelt
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define 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 void @single_payload_nested_switch(i8) {{.*}} {
sil @single_payload_nested_switch : $(SinglePayloadNestedNested) -> () {
entry(%u : $SinglePayloadNestedNested):
// CHECK:   switch i8 {{%.*}}, label {{%.*}} [
// CHECK:     i8 6, label {{%.*}}
// CHECK:     i8 7, label {{%.*}}
// CHECK:     i8 8, label {{%.*}}
// CHECK:   ]
  switch_enum %u : $SinglePayloadNestedNested, case #SinglePayloadNestedNested.e!enumelt.1: e_dest, case #SinglePayloadNestedNested.f!enumelt: f_dest, case #SinglePayloadNestedNested.g!enumelt: g_dest, case #SinglePayloadNestedNested.h!enumelt: h_dest

e_dest(%v : $SinglePayloadNested):
// CHECK:   switch i8 {{%.*}}, label {{%.*}} [
// CHECK:     i8 3, label {{%.*}}
// CHECK:     i8 4, label {{%.*}}
// CHECK:     i8 5, label {{%.*}}
// CHECK:   ]
  switch_enum %v : $SinglePayloadNested, case #SinglePayloadNested.a!enumelt.1: a_dest, case #SinglePayloadNested.b!enumelt: b_dest, case #SinglePayloadNested.c!enumelt: c_dest, case #SinglePayloadNested.d!enumelt: d_dest
f_dest:
  br end
g_dest:
  br end
h_dest:
  br end

a_dest(%w : $NoPayloads):
// CHECK:   switch i2 {{%.*}}, label {{%.*}} [
// CHECK:     i2 0, label {{%.*}}
// CHECK:     i2 1, label {{%.*}}
// CHECK:     i2 -2, label {{%.*}}
// CHECK:   ]
  switch_enum %w : $NoPayloads, case #NoPayloads.x!enumelt: x_dest, case #NoPayloads.y!enumelt: y_dest, case #NoPayloads.z!enumelt: z_dest
b_dest:
  br end
c_dest:
  br end
d_dest:
  br end

x_dest:
  br end
y_dest:
  br end
z_dest:
  br end

end:
  %x = tuple()
  return %x : $()
}

class C {}
sil_vtable C {}

sil @_TFC4enum1CD : $@convention(method) (C) -> ()

@objc class OC {}
sil_vtable OC {}
sil hidden @_TToFC4enum2OCcfT_S0_ : $@convention(thin) (OC) -> OC {
entry(%x : $OC):
  return %x : $OC
}

enum SinglePayloadClass {
  case x(C)
  case y
  case z
  case w
}

// CHECK-64: define void @single_payload_class_switch(i64) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   switch i64 %0, label {{%.*}} [
// CHECK-64:     i64 0, label {{%.*}}
// CHECK-64:     i64 2, label {{%.*}}
// CHECK-64:     i64 4, label {{%.*}}
// CHECK-64:   ]
// CHECK-64: ; <label>
// CHECK-64:   inttoptr [[WORD]] %0 to %C4enum1C*

// CHECK-32: define void @single_payload_class_switch(i32) {{.*}} {
// CHECK-32: entry:
// CHECK-32:   switch i32 %0, label {{%.*}} [
// CHECK-32:     i32 0, label {{%.*}}
// CHECK-32:     i32 1, label {{%.*}}
// CHECK-32:     i32 2, label {{%.*}}
// CHECK-32:   ]
// CHECK-32: ; <label>
// CHECK-32:   inttoptr [[WORD]] %0 to %C4enum1C*

sil @single_payload_class_switch : $(SinglePayloadClass) -> () {
entry(%c : $SinglePayloadClass):
  switch_enum %c : $SinglePayloadClass, case #SinglePayloadClass.x!enumelt.1: x_dest, case #SinglePayloadClass.y!enumelt: y_dest, case #SinglePayloadClass.z!enumelt: z_dest, case #SinglePayloadClass.w!enumelt: w_dest

x_dest(%d : $C):
  br end
y_dest:
  br end
z_dest:
  br end
w_dest:
  br end

end:
  return undef : $()
}

protocol PC : class {}
@objc protocol PO {}

enum SinglePayloadClassProtocol {
  case x(PC)
  case y, z, w
}

enum SinglePayloadObjCProtocol {
  case x(PO)
  case y, z, w
}

// CHECK-64: define void @single_payload_class_protocol_switch(i64, i64) {{.*}} {
// CHECK-64:   switch i64 %0, label {{%.*}} [
// CHECK-64:     i64 0, label {{%.*}}
// CHECK-64:     i64 2, label {{%.*}}
// CHECK-64:     i64 4, label {{%.*}}
// CHECK-64:   ]

// CHECK-objc-64:     inttoptr i64 %0 to %objc_object*
// CHECK-native-64:   inttoptr i64 %0 to %swift.refcounted*
// CHECK-64:   inttoptr i64 %1 to i8**

// CHECK-32: define void @single_payload_class_protocol_switch(i32, i32) {{.*}} {
// CHECK-32:   switch i32 %0, label {{%.*}} [
// CHECK-32:     i32 0, label {{%.*}}
// CHECK-32:     i32 1, label {{%.*}}
// CHECK-32:     i32 2, label {{%.*}}
// CHECK-32:   ]

// CHECK-objc-32:     inttoptr i32 %0 to %objc_object*
// CHECK-native-32:   inttoptr i32 %0 to %swift.refcounted*
// CHECK-32:   inttoptr i32 %1 to i8**

sil @single_payload_class_protocol_switch : $(SinglePayloadClassProtocol) -> () {
entry(%c : $SinglePayloadClassProtocol):
  switch_enum %c : $SinglePayloadClassProtocol, case #SinglePayloadClassProtocol.x!enumelt.1: x_dest, case #SinglePayloadClassProtocol.y!enumelt: y_dest, case #SinglePayloadClassProtocol.z!enumelt: z_dest, case #SinglePayloadClassProtocol.w!enumelt: w_dest

x_dest(%d : $PC):
  br end
y_dest:
  br end
z_dest:
  br end
w_dest:
  br end

end:
  return undef : $()
}

// CHECK-64: define void @single_payload_objc_protocol_switch(i64) {{.*}} {
// CHECK-64:   switch i64 %0, label {{%.*}}
// CHECK-64:     i64 0, label {{%.*}}
// CHECK-64:     i64 2, label {{%.*}}
// CHECK-64:     i64 4, label {{%.*}}
// CHECK-64:   ]
// CHECK-objc-64:     inttoptr i64 %0 to %objc_object*
// CHECK-native-64:   inttoptr i64 %0 to %swift.refcounted*

// CHECK-32: define void @single_payload_objc_protocol_switch(i32) {{.*}} {
// CHECK-32:   switch i32 %0, label {{%.*}}
// CHECK-32:     i32 0, label {{%.*}}
// CHECK-32:     i32 1, label {{%.*}}
// CHECK-32:     i32 2, label {{%.*}}
// CHECK-32:   ]
// CHECK-objc-32:     inttoptr i32 %0 to %objc_object*
// CHECK-native-32:   inttoptr i32 %0 to %swift.refcounted*

sil @single_payload_objc_protocol_switch : $(SinglePayloadObjCProtocol) -> () {
entry(%c : $SinglePayloadObjCProtocol):
  switch_enum %c : $SinglePayloadObjCProtocol, case #SinglePayloadObjCProtocol.x!enumelt.1: x_dest, case #SinglePayloadObjCProtocol.y!enumelt: y_dest, case #SinglePayloadObjCProtocol.z!enumelt: z_dest, case #SinglePayloadObjCProtocol.w!enumelt: w_dest

x_dest(%d : $PO):
  br end
y_dest:
  br end
z_dest:
  br end
w_dest:
  br end

end:
  return undef : $()
}


enum DynamicSinglePayload<T> {
  case x(T)
  case y
  case z
  case w
}

// CHECK: define void @dynamic_single_payload_switch(%O4enum20DynamicSinglePayload* noalias nocapture, %swift.type* %T) {{.*}} {
// CHECK:   [[OPAQUE_ENUM:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
// CHECK:   [[CASE_INDEX:%.*]] = call i32 @swift_getEnumCaseSinglePayload(%swift.opaque* [[OPAQUE_ENUM]], %swift.type* %T, i32 3)
// CHECK:   switch i32 [[CASE_INDEX]], label {{%.*}} [
// CHECK:     i32 -1, label {{%.*}}
// CHECK:     i32 2, label {{%.*}}
// CHECK:   ]
sil @dynamic_single_payload_switch : $<T> (@in DynamicSinglePayload<T>) -> () {
entry(%u : $*DynamicSinglePayload<T>):
  switch_enum_addr %u : $*DynamicSinglePayload<T>, case #DynamicSinglePayload.x!enumelt.1: x_dest, case #DynamicSinglePayload.w!enumelt: w_dest, default default_dest

x_dest:
  br end

w_dest:
  br end

default_dest:
  br end

end:
  %v = tuple ()
  return %v : $()
}

// CHECK: define void @dynamic_single_payload_inject_x(%O4enum20DynamicSinglePayload* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T) {{.*}} {
// CHECK:   [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
// CHECK:   call void @swift_storeEnumTagSinglePayload(%swift.opaque* [[ADDR]], %swift.type* %T, i32 -1, i32 3)
sil @dynamic_single_payload_inject_x : $<T> (@out DynamicSinglePayload<T>, @in T) -> () {
entry(%r : $*DynamicSinglePayload<T>, %t : $*T):
  inject_enum_addr %r : $*DynamicSinglePayload<T>, #DynamicSinglePayload.x!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK: define void @dynamic_single_payload_inject_y(%O4enum20DynamicSinglePayload* noalias nocapture sret, %swift.type* %T) {{.*}} {
// CHECK:   [[ADDR:%.*]] = bitcast %O4enum20DynamicSinglePayload* %0 to %swift.opaque*
// CHECK:   call void @swift_storeEnumTagSinglePayload(%swift.opaque* [[ADDR]], %swift.type* %T, i32 0, i32 3)
sil @dynamic_single_payload_inject_y : $<T> (@out DynamicSinglePayload<T>) -> () {
entry(%r : $*DynamicSinglePayload<T>):
  inject_enum_addr %r : $*DynamicSinglePayload<T>, #DynamicSinglePayload.y!enumelt
  %v = tuple ()
  return %v : $()
}

// -- Ensure instantiations of single-payload types with empty payloads work.
//    Bug discovered by Greg Parker.

// CHECK: define void @dynamic_single_payload_empty_payload_switch(i2) {{.*}} {
// CHECK:   switch i2 {{%.*}}, label {{.*}} [
// CHECK:     i2 0, label {{.*}}
// CHECK:     i2 1, label {{.*}}
// CHECK:     i2 -2, label {{.*}}
// CHECK:     i2 -1, label {{.*}}
// CHECK:   ]
sil @dynamic_single_payload_empty_payload_switch : $DynamicSinglePayload<()> -> () {
entry(%x : $DynamicSinglePayload<()>):
  switch_enum %x : $DynamicSinglePayload<()>, case #DynamicSinglePayload.x!enumelt.1: x_case, case #DynamicSinglePayload.y!enumelt: y_case, case #DynamicSinglePayload.z!enumelt: z_case, default default_case

x_case(%a : $()):
  br end(%a : $())

y_case:
  %b = tuple ()
  br end(%b : $())

z_case:
  %c = tuple ()
  br end(%c : $())

default_case:
  %d = tuple ()
  br end(%d : $())

end(%z : $()):
  return %z : $()
}

// CHECK: define i2 @dynamic_single_payload_empty_payload_load([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK: entry:
// CHECK:   %1 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i2*
// CHECK:   %2 = load i2, i2* %1
// CHECK:   ret i2 %2
// CHECK: }
sil @dynamic_single_payload_empty_payload_load : $(@inout DynamicSinglePayload<()>) -> DynamicSinglePayload<()> {
entry(%p : $*DynamicSinglePayload<()>):
  %x = load %p : $*DynamicSinglePayload<()>
  return %x : $DynamicSinglePayload<()>
}

// CHECK: define void @dynamic_single_payload_empty_payload_store([[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* nocapture dereferenceable({{.*}}), i2) {{.*}} {
// CHECK: entry:
// CHECK:   %2 = bitcast [[DYNAMIC_SINGLE_EMPTY_PAYLOAD]]* %0 to i2*
// CHECK:   store i2 %1, i2* %2
// CHECK:   ret void
// CHECK: }
sil @dynamic_single_payload_empty_payload_store : $(@inout DynamicSinglePayload<()>, DynamicSinglePayload<()>) -> () {
entry(%p : $*DynamicSinglePayload<()>, %x : $DynamicSinglePayload<()>):
  store %x to %p : $*DynamicSinglePayload<()>
  %v = tuple ()
  return %v : $()
}

// CHECK: define i2 @dynamic_single_payload_empty_payload_inject_payload() {{.*}} {
// CHECK: entry:
// CHECK:   ret i2 0
// CHECK: }
sil @dynamic_single_payload_empty_payload_inject_payload : $() -> DynamicSinglePayload<()> {
  %v = tuple ()
  %u = enum $DynamicSinglePayload<()>, #DynamicSinglePayload.x!enumelt, %v : $()
  return %u : $DynamicSinglePayload<()>
}

// CHECK: define i2 @dynamic_single_payload_empty_payload_inject_no_payload() {{.*}} {
// CHECK: entry:
// CHECK:   ret i2 1
// CHECK: }
sil @dynamic_single_payload_empty_payload_inject_no_payload : $() -> DynamicSinglePayload<()> {
  %u = enum $DynamicSinglePayload<()>, #DynamicSinglePayload.y!enumelt
  return %u : $DynamicSinglePayload<()>
}

// <rdar://problem/15383966>
// CHECK: define void @dynamic_single_payload_generic_destroy
// CHECK:   br i1
// CHECK: <label>
// CHECK:   call void %destroy
// CHECK: <label>
sil @dynamic_single_payload_generic_destroy : $@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 void @multi_payload_no_spare_bits_switch(i64, i2) {{.*}} {
sil @multi_payload_no_spare_bits_switch : $(MultiPayloadNoSpareBits) -> () {
entry(%u : $MultiPayloadNoSpareBits):
// CHECK-64:   switch i2 %1, label %[[UNREACHABLE:[0-9]+]] [
// CHECK-64:     i2 0, label %[[X_PREDEST:[0-9]+]]
// CHECK-64:     i2 1, label %[[Y_PREDEST:[0-9]+]]
// CHECK-64:     i2 -2, label %[[Z_PREDEST:[0-9]+]]
// CHECK-64:     i2 -1, label %[[EMPTY:[0-9]+]]
// CHECK-64:   ]
// CHECK-64: ; <label>:[[EMPTY]]
// CHECK-64:   switch i64 %0, label %[[UNREACHABLE]] [
// CHECK-64:     i64 0, label %[[A_DEST:[0-9]+]]
// CHECK-64:     i64 1, label %[[B_DEST:[0-9]+]]
// CHECK-64:     i64 2, label %[[C_DEST:[0-9]+]]
// CHECK-64:   ]
// CHECK-64: ; <label>:[[UNREACHABLE]]
// CHECK-64:   unreachable
  switch_enum %u : $MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadNoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadNoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest

// CHECK-64: ; <label>:[[X_PREDEST]]
// CHECK-64:   br label %[[X_DEST:[0-9]+]]
// CHECK-64: ; <label>:[[Y_PREDEST]]
// CHECK-64:   [[Y_VALUE:%.*]] = trunc i64 %0 to i32
// CHECK-64:   br label %[[Y_DEST:[0-9]+]]
// CHECK-64: ; <label>:[[Z_PREDEST]]
// CHECK-64:   [[Z_VALUE:%.*]] = trunc i64 %0 to i63
// CHECK-64:   br label %[[Z_DEST:[0-9]+]]

// CHECK-64: ; <label>:[[X_DEST]]
// CHECK-64:   phi i64 [ %0, %[[X_PREDEST]] ]
x_dest(%x : $Builtin.Int64):
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[Y_DEST]]
// CHECK-64:   phi i32 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
y_dest(%y : $Builtin.Int32):
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[Z_DEST]]
// CHECK-64:   phi i63 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
z_dest(%z : $Builtin.Int63):
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[A_DEST]]
a_dest:
  %d = function_ref @d : $@convention(thin) () -> ()
  apply %d() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[B_DEST]]
b_dest:
  %e = function_ref @e : $@convention(thin) () -> ()
  apply %e() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[C_DEST]]
c_dest:
  %f = function_ref @f : $@convention(thin) () -> ()
  apply %f() : $@convention(thin) () -> ()
  br end

end:
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define void @multi_payload_no_spare_bits_switch_indirect(%O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
sil @multi_payload_no_spare_bits_switch_indirect : $(@inout MultiPayloadNoSpareBits) -> () {
entry(%u : $*MultiPayloadNoSpareBits):
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
// CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1
// CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i2*
// CHECK-64:   [[TAG:%.*]] = load i2, i2* [[TAG_ADDR]]
// CHECK-64:   switch i2 [[TAG]]
// CHECK-64:   switch i64 [[PAYLOAD]]
// CHECK-64: ; <label>:
// CHECK-64:   unreachable
  switch_enum_addr %u : $*MultiPayloadNoSpareBits, case #MultiPayloadNoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadNoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadNoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadNoSpareBits.a!enumelt: a_dest, case #MultiPayloadNoSpareBits.b!enumelt: b_dest, case #MultiPayloadNoSpareBits.c!enumelt: c_dest

// CHECK-64: ; <label>:[[X_DEST:[0-9]+]]
// CHECK-64:   bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
// CHECK-64: ; <label>:[[Y_DEST:[0-9]+]]
// CHECK-64:   bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i32*
// CHECK-64: ; <label>:[[Z_DEST:[0-9]+]]
// CHECK-64:   bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i63*

x_dest:
  %x = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1
  br end

y_dest:
  %y = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.y!enumelt.1
  br end

z_dest:
  %z = unchecked_take_enum_data_addr %u : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.z!enumelt.1
  br end

a_dest:
  br end

b_dest:
  br end

c_dest:
  br end

end:
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define { i64, i2 } @multi_payload_no_spare_bit_inject_x(i64) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[RES_0:%.*]] = insertvalue { i64, i2 } undef, i64 %0, 0
// CHECK-64:   [[RES:%.*]] = insertvalue { i64, i2 } [[RES_0]], i2 0, 1
// CHECK-64:   ret { i64, i2 } [[RES]]
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_x : $(Builtin.Int64) -> MultiPayloadNoSpareBits {
entry(%0 : $Builtin.Int64):
  %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1, %0 : $Builtin.Int64
  return %u : $MultiPayloadNoSpareBits
}

// CHECK-64: define void @multi_payload_no_spare_bit_inject_x_indirect(i64, %O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %1 to i64*
// CHECK-64:   store i64 %0, i64* [[DATA_ADDR]]
// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %1, i32 0, i32 1
// CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i2*
// CHECK-64:   store i2 0, i2* [[TAG_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_x_indirect : $(Builtin.Int64, @inout MultiPayloadNoSpareBits) -> () {
entry(%0 : $Builtin.Int64, %1 : $*MultiPayloadNoSpareBits):
  %a = init_enum_data_addr %1 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1
  store %0 to %a : $*Builtin.Int64
  inject_enum_addr %1 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.x!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define { i64, i2 } @multi_payload_no_spare_bit_inject_y(i32) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i32 %0 to i64
// CHECK-64:   [[RES_0:%.*]] = insertvalue { i64, i2 } undef, i64 [[ZEXT]], 0
// CHECK-64:   [[RES:%.*]] = insertvalue { i64, i2 } [[RES_0]], i2 1, 1
// CHECK-64:   ret { i64, i2 } [[RES]]
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_y : $(Builtin.Int32) -> MultiPayloadNoSpareBits {
entry(%0 : $Builtin.Int32):
  %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.y!enumelt.1, %0 : $Builtin.Int32
  return %u : $MultiPayloadNoSpareBits
}

// CHECK-64: define { i64, i2 } @multi_payload_no_spare_bit_inject_z(i63) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i63 %0 to i64
// CHECK-64:   [[RES_0:%.*]] = insertvalue { i64, i2 } undef, i64 [[ZEXT]], 0
// CHECK-64:   [[RES:%.*]] = insertvalue { i64, i2 } [[RES_0]], i2 -2, 1
// CHECK-64:   ret { i64, i2 } [[RES]]
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_z : $(Builtin.Int63) -> MultiPayloadNoSpareBits {
entry(%0 : $Builtin.Int63):
  %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.z!enumelt.1, %0 : $Builtin.Int63
  return %u : $MultiPayloadNoSpareBits
}

// CHECK-64: define { i64, i2 } @multi_payload_no_spare_bit_inject_a() {{.*}} {
// CHECK-64: entry:
// CHECK-64:   ret { i64, i2 } { i64 0, i2 -1 }
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_a : $() -> MultiPayloadNoSpareBits {
entry:
  %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.a!enumelt
  return %u : $MultiPayloadNoSpareBits
}

// CHECK-64: define void @multi_payload_no_spare_bit_inject_a_indirect(%O4enum23MultiPayloadNoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadNoSpareBits* %0 to i64*
// CHECK-64:   store i64 0, i64* [[PAYLOAD_ADDR]]
// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadNoSpareBits, %O4enum23MultiPayloadNoSpareBits* %0, i32 0, i32 1
// CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i2*
// CHECK-64:   store i2 -1, i2* [[TAG_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_a_indirect : $(@inout MultiPayloadNoSpareBits) -> () {
entry(%0 : $*MultiPayloadNoSpareBits):
  inject_enum_addr %0 : $*MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.a!enumelt
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define { i64, i2 } @multi_payload_no_spare_bit_inject_b() {{.*}} {
// CHECK-64: entry:
// CHECK-64:   ret { i64, i2 } { i64 1, i2 -1 }
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_b : $() -> MultiPayloadNoSpareBits {
entry:
  %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.b!enumelt
  return %u : $MultiPayloadNoSpareBits
}

// CHECK-64: define { i64, i2 } @multi_payload_no_spare_bit_inject_c() {{.*}} {
// CHECK-64: entry:
// CHECK-64:   ret { i64, i2 } { i64 2, i2 -1 }
// CHECK-64: }
sil @multi_payload_no_spare_bit_inject_c : $() -> MultiPayloadNoSpareBits {
entry:
  %u = enum $MultiPayloadNoSpareBits, #MultiPayloadNoSpareBits.c!enumelt
  return %u : $MultiPayloadNoSpareBits
}

enum MultiPayloadOneSpareBit {
  case x(Builtin.Int62)
  case y(Builtin.Int63)
  case z(Builtin.Int61)
  case a
  case b
  case c
}

// CHECK-64: define void @multi_payload_one_spare_bit_switch(i64, i1) {{.*}} {
sil @multi_payload_one_spare_bit_switch : $(MultiPayloadOneSpareBit) -> () {
entry(%u : $MultiPayloadOneSpareBit):
// CHECK-64:   [[SPARE_TAG_LSHR:%.*]] = lshr i64 %0, 63
// CHECK-64:   [[SPARE_TAG_TRUNC:%.*]] = trunc i64 [[SPARE_TAG_LSHR]] to i2
// CHECK-64:   [[SPARE_TAG:%.*]] = and i2 [[SPARE_TAG_TRUNC]], 1
// CHECK-64:   [[EXTRA_TAG_ZEXT:%.*]] = zext i1 %1 to i2
// CHECK-64:   [[EXTRA_TAG:%.*]] = shl i2 [[EXTRA_TAG_ZEXT]], 1
// CHECK-64:   [[TAG:%.*]] = or i2 [[SPARE_TAG]], [[EXTRA_TAG]]
// CHECK-64:   switch i2 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [
// CHECK-64:     i2 0, label %[[X_PREDEST:[0-9]+]]
// CHECK-64:     i2 1, label %[[Y_PREDEST:[0-9]+]]
// CHECK-64:     i2 -2, label %[[Z_PREDEST:[0-9]+]]
// CHECK-64:     i2 -1, label %[[EMPTY_DEST:[0-9]+]]
// CHECK-64:   ]

// CHECK-64: ; <label>:[[EMPTY_DEST]]
// CHECK-64:   switch i64 %0, label %[[UNREACHABLE]] [
// --            0x8000_0000_0000_0000
// CHECK-64:     i64 -9223372036854775808, label %[[A_DEST:[0-9]+]]
// --            0x8000_0000_0000_0001
// CHECK-64:     i64 -9223372036854775807, label %[[B_DEST:[0-9]+]]
// --            0x8000_0000_0000_0002
// CHECK-64:     i64 -9223372036854775806, label %[[C_DEST:[0-9]+]]
// CHECK-64:   ]

// CHECK-64: ; <label>:[[UNREACHABLE]]
// CHECK-64:   unreachable
  switch_enum %u : $MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt.1: x_dest, case #MultiPayloadOneSpareBit.y!enumelt.1: y_dest, case #MultiPayloadOneSpareBit.z!enumelt.1: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest

// CHECK-64: ; <label>:[[X_PREDEST]]
// CHECK-64:   [[X_VALUE:%.*]] = trunc i64 %0 to i62
// CHECK-64:   br label %[[X_DEST:[0-9]+]]
// CHECK-64: ; <label>:[[Y_PREDEST]]
// --                                    0x7FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[Y_MASKED:%.*]] = and i64 %0, 9223372036854775807
// CHECK-64:   [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i63
// CHECK-64:   br label %[[Y_DEST:[0-9]+]]
// CHECK-64: ; <label>:[[Z_PREDEST]]
// CHECK-64:   [[Z_VALUE:%.*]] = trunc i64 %0 to i61
// CHECK-64:   br label %[[Z_DEST:[0-9]+]]

// CHECK-64: ; <label>:[[X_DEST]]
// CHECK-64:   phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ]
x_dest(%x : $Builtin.Int62):
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[Y_DEST]]
// CHECK-64:   phi i63 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
y_dest(%y : $Builtin.Int63):
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[Z_DEST]]
// CHECK-64:   phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
z_dest(%z : $Builtin.Int61):
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[A_DEST]]
a_dest:
  %d = function_ref @d : $@convention(thin) () -> ()
  apply %d() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[B_DEST]]
b_dest:
  %e = function_ref @e : $@convention(thin) () -> ()
  apply %e() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[C_DEST]]
c_dest:
  %f = function_ref @f : $@convention(thin) () -> ()
  apply %f() : $@convention(thin) () -> ()
  br end

end:
  %v = tuple ()
  return %v : $()
}

sil @multi_payload_one_spare_bit_switch_indirect : $(@inout MultiPayloadOneSpareBit) -> () {
entry(%u : $*MultiPayloadOneSpareBit):
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
// CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1
// CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK-64:   [[TAG:%.*]] = load i1, i1* [[TAG_ADDR]]
// CHECK-64:   switch i2 {{%.*}}
// CHECK-64:   switch i64 [[PAYLOAD]]
// CHECK-64: ; <label>:
// CHECK-64:   unreachable
  switch_enum_addr %u : $*MultiPayloadOneSpareBit, case #MultiPayloadOneSpareBit.x!enumelt.1: x_dest, case #MultiPayloadOneSpareBit.y!enumelt.1: y_dest, case #MultiPayloadOneSpareBit.z!enumelt.1: z_dest, case #MultiPayloadOneSpareBit.a!enumelt: a_dest, case #MultiPayloadOneSpareBit.b!enumelt: b_dest, case #MultiPayloadOneSpareBit.c!enumelt: c_dest

// CHECK-64: ; <label>:[[X_PREDEST:[0-9]+]]
// CHECK-64:   bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i62*

// CHECK-64: ; <label>:[[Y_PREDEST:[0-9]+]]
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
// CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// --                                                   0x7FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
// CHECK-64:   store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
// CHECK-64:   bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i63*

// CHECK-64: ; <label>:[[Z_PREDEST:[0-9]+]]
// CHECK-64:   bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i61*

x_dest:
  %x = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1
  br end

y_dest:
  %y = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1
  br end

z_dest:
  %z = unchecked_take_enum_data_addr %u : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt.1
  br end

a_dest:
  br end

b_dest:
  br end

c_dest:
  br end

end:
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define { i64, i1 } @multi_payload_one_spare_bit_inject_x(i62) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i62 %0 to i64
// CHECK-64:   [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[ZEXT]], 0
// CHECK-64:   [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 false, 1
// CHECK-64:   ret { i64, i1 } [[RES]]
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_x : $(Builtin.Int62) -> MultiPayloadOneSpareBit {
entry(%0 : $Builtin.Int62):
  %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1, %0 : $Builtin.Int62
  return %u : $MultiPayloadOneSpareBit
}

// CHECK-64: define void @multi_payload_one_spare_bit_inject_x_indirect(i62, %O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i62*
// CHECK-64:   store i62 %0, i62* [[DATA_ADDR]]
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
// CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// --                                                   0x7FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
// CHECK-64:   store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1
// CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK-64:   store i1 false, i1* [[TAG_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_x_indirect : $(Builtin.Int62, @inout MultiPayloadOneSpareBit) -> () {
entry(%0 : $Builtin.Int62, %1 : $*MultiPayloadOneSpareBit):
  %a = init_enum_data_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1
  store %0 to %a : $*Builtin.Int62
  inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.x!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define { i64, i1 } @multi_payload_one_spare_bit_inject_y(i63) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i63 %0 to i64
// --                                        0x8000_0000_0000_0000
// CHECK-64:   [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808
// CHECK-64:   [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[TAGGED]], 0
// CHECK-64:   [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 false, 1
// CHECK-64:   ret { i64, i1 } [[RES]]
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_y : $(Builtin.Int63) -> MultiPayloadOneSpareBit {
entry(%0 : $Builtin.Int63):
  %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1, %0 : $Builtin.Int63
  return %u : $MultiPayloadOneSpareBit
}

// CHECK-64: define void @multi_payload_one_spare_bit_inject_y_indirect(i63, %O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i63*
// CHECK-64:   store i63 %0, i63* [[DATA_ADDR]]
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
// CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// --                                                   0x7FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 9223372036854775807
// --                                                          0x8000_0000_0000_0000
// CHECK-64:   [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], -9223372036854775808
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %1 to i64*
// CHECK-64:   store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]]
// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %1, i32 0, i32 1
// CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK-64:   store i1 false, i1* [[TAG_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }

sil @multi_payload_one_spare_bit_inject_y_indirect : $(Builtin.Int63, @inout MultiPayloadOneSpareBit) -> () {
entry(%0 : $Builtin.Int63, %1 : $*MultiPayloadOneSpareBit):
  %a = init_enum_data_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1
  store %0 to %a : $*Builtin.Int63
  inject_enum_addr %1 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.y!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define { i64, i1 } @multi_payload_one_spare_bit_inject_z(i61) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i61 %0 to i64
// CHECK-64:   [[RES_0:%.*]] = insertvalue { i64, i1 } undef, i64 [[ZEXT]], 0
// CHECK-64:   [[RES:%.*]] = insertvalue { i64, i1 } [[RES_0]], i1 true, 1
// CHECK-64:   ret { i64, i1 } [[RES]]
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_z : $(Builtin.Int61) -> MultiPayloadOneSpareBit {
entry(%0 : $Builtin.Int61):
  %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.z!enumelt.1, %0 : $Builtin.Int61
  return %u : $MultiPayloadOneSpareBit
}

// CHECK-64: define { i64, i1 } @multi_payload_one_spare_bit_inject_a() {{.*}} {
// CHECK-64: entry:
// --                            0x8000_0000_0000_0000
// CHECK-64:   ret { i64, i1 } { i64 -9223372036854775808, i1 true }
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_a : $() -> MultiPayloadOneSpareBit {
entry:
  %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt
  return %u : $MultiPayloadOneSpareBit
}

// CHECK-64: define void @multi_payload_one_spare_bit_inject_a_indirect(%O4enum23MultiPayloadOneSpareBit* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum23MultiPayloadOneSpareBit* %0 to i64*
// --                0x8000_0000_0000_0000
// CHECK-64:   store i64 -9223372036854775808, i64* [[PAYLOAD_ADDR]]
// CHECK-64:   [[T0:%.*]] = getelementptr inbounds %O4enum23MultiPayloadOneSpareBit, %O4enum23MultiPayloadOneSpareBit* %0, i32 0, i32 1
// CHECK-64:   [[TAG_ADDR:%.*]] = bitcast [1 x i8]* [[T0]] to i1*
// CHECK-64:   store i1 true, i1* [[TAG_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_a_indirect : $(@inout MultiPayloadOneSpareBit) -> () {
entry(%0 : $*MultiPayloadOneSpareBit):
  inject_enum_addr %0 : $*MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.a!enumelt
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define { i64, i1 } @multi_payload_one_spare_bit_inject_b() {{.*}} {
// CHECK-64: entry:
// --                            0x8000_0000_0000_0001
// CHECK-64:   ret { i64, i1 } { i64 -9223372036854775807, i1 true }
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_b : $() -> MultiPayloadOneSpareBit {
entry:
  %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.b!enumelt
  return %u : $MultiPayloadOneSpareBit
}

// CHECK-64: define { i64, i1 } @multi_payload_one_spare_bit_inject_c() {{.*}} {
// CHECK-64: entry:
// --                            0x8000_0000_0000_0002
// CHECK-64:   ret { i64, i1 } { i64 -9223372036854775806, i1 true }
// CHECK-64: }
sil @multi_payload_one_spare_bit_inject_c : $() -> MultiPayloadOneSpareBit {
entry:
  %u = enum $MultiPayloadOneSpareBit, #MultiPayloadOneSpareBit.c!enumelt
  return %u : $MultiPayloadOneSpareBit
}


enum MultiPayloadTwoSpareBits {
  case x(Builtin.Int62)
  case y(Builtin.Int60)
  case z(Builtin.Int61)
  case a
  case b
  case c
}

// CHECK-64: define void @multi_payload_two_spare_bits_switch(i64) {{.*}} {
sil @multi_payload_two_spare_bits_switch : $(MultiPayloadTwoSpareBits) -> () {
entry(%u : $MultiPayloadTwoSpareBits):
// CHECK-64:   [[TAG_LSHR:%.*]] = lshr i64 %0, 62
// CHECK-64:   [[TAG:%.*]] = trunc i64 [[TAG_LSHR]] to i2
// CHECK-64:   switch i2 [[TAG]], label %[[UNREACHABLE:[0-9]+]] [
// CHECK-64:     i2 0, label %[[X_PREDEST:[0-9]+]]
// CHECK-64:     i2 1, label %[[Y_PREDEST:[0-9]+]]
// CHECK-64:     i2 -2, label %[[Z_PREDEST:[0-9]+]]
// CHECK-64:     i2 -1, label %[[EMPTY_DEST:[0-9]+]]
// CHECK-64:   ]
// CHECK-64: ; <label>:[[EMPTY_DEST]]
// CHECK-64:   switch i64 %0, label %[[UNREACHABLE]] [
// --            0xC000_0000_0000_0000
// CHECK-64:     i64 -4611686018427387904, label %[[A_DEST:[0-9]+]]
// --            0xC000_0000_0000_0001
// CHECK-64:     i64 -4611686018427387903, label %[[B_DEST:[0-9]+]]
// --            0xC000_0000_0000_0002
// CHECK-64:     i64 -4611686018427387902, label %[[C_DEST:[0-9]+]]
// CHECK-64:   ]
// CHECK-64: ; <label>:[[UNREACHABLE]]
// CHECK-64:   unreachable
  switch_enum %u : $MultiPayloadTwoSpareBits, case #MultiPayloadTwoSpareBits.x!enumelt.1: x_dest, case #MultiPayloadTwoSpareBits.y!enumelt.1: y_dest, case #MultiPayloadTwoSpareBits.z!enumelt.1: z_dest, case #MultiPayloadTwoSpareBits.a!enumelt: a_dest, case #MultiPayloadTwoSpareBits.b!enumelt: b_dest, case #MultiPayloadTwoSpareBits.c!enumelt: c_dest

// CHECK-64: ; <label>:[[X_PREDEST]]
// CHECK-64:   [[X_VALUE:%.*]] = trunc i64 %0 to i62
// CHECK-64:   br label %[[X_DEST:[0-9]+]]

// CHECK-64: ; <label>:[[Y_PREDEST]]
// --                                    0x3FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903
// CHECK-64:   [[Y_VALUE:%.*]] = trunc i64 [[Y_MASKED]] to i60
// CHECK-64:   br label %[[Y_DEST:[0-9]+]]

// CHECK-64: ; <label>:[[Z_PREDEST]]
// --                                    0x3FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903
// CHECK-64:   [[Z_VALUE:%.*]] = trunc i64 [[Z_MASKED]] to i61
// CHECK-64:   br label %[[Z_DEST:[0-9]+]]

// CHECK-64: ; <label>:[[X_DEST]]
// CHECK-64:   phi i62 [ [[X_VALUE]], %[[X_PREDEST]] ]
x_dest(%x : $Builtin.Int62):
  %a = function_ref @a : $@convention(thin) () -> ()
  apply %a() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[Y_DEST]]
// CHECK-64:   phi i60 [ [[Y_VALUE]], %[[Y_PREDEST]] ]
y_dest(%y : $Builtin.Int60):
  %b = function_ref @b : $@convention(thin) () -> ()
  apply %b() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[Z_DEST]]
// CHECK-64:   phi i61 [ [[Z_VALUE]], %[[Z_PREDEST]] ]
z_dest(%z : $Builtin.Int61):
  %c = function_ref @c : $@convention(thin) () -> ()
  apply %c() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[A_DEST]]
a_dest:
  %d = function_ref @d : $@convention(thin) () -> ()
  apply %d() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[B_DEST]]
b_dest:
  %e = function_ref @e : $@convention(thin) () -> ()
  apply %e() : $@convention(thin) () -> ()
  br end

// CHECK-64: ; <label>:[[C_DEST]]
c_dest:
  %f = function_ref @f : $@convention(thin) () -> ()
  apply %f() : $@convention(thin) () -> ()
  br end

end:
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define i64 @multi_payload_two_spare_bits_inject_x(i62) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i62 %0 to i64
// CHECK-64:   ret i64 [[ZEXT]]
// CHECK-64: }
sil @multi_payload_two_spare_bits_inject_x : $(Builtin.Int62) -> MultiPayloadTwoSpareBits {
entry(%0 : $Builtin.Int62):
  %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1, %0 : $Builtin.Int62
  return %u : $MultiPayloadTwoSpareBits
}

// CHECK-64: define void @multi_payload_two_spare_bits_inject_x_indirect(i62, %O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i62*
// CHECK-64:   store i62 %0, i62* [[DATA_ADDR]]
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
// CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// --                                                   0x3FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
// CHECK-64:   store i64 [[PAYLOAD_MASKED]], i64* [[PAYLOAD_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @multi_payload_two_spare_bits_inject_x_indirect : $(Builtin.Int62, @inout MultiPayloadTwoSpareBits) -> () {
entry(%0 : $Builtin.Int62, %1 : $*MultiPayloadTwoSpareBits):
  %a = init_enum_data_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1
  store %0 to %a : $*Builtin.Int62
  inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.x!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define i64 @multi_payload_two_spare_bits_inject_y(i60) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i60 %0 to i64
// --                     0x4000_0000_0000_0000
// CHECK-64:   [[TAGGED:%.*]] = or i64 [[ZEXT]], 4611686018427387904
// CHECK-64:   ret i64 [[TAGGED]]
// CHECK-64: }
sil @multi_payload_two_spare_bits_inject_y : $(Builtin.Int60) -> MultiPayloadTwoSpareBits {
entry(%0 : $Builtin.Int60):
  %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1, %0 : $Builtin.Int60
  return %u : $MultiPayloadTwoSpareBits
}

// CHECK-64: define void @multi_payload_two_spare_bits_inject_y_indirect(i60, %O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[DATA_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i60*
// CHECK-64:   store i60 %0, i60* [[DATA_ADDR]]
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
// CHECK-64:   [[PAYLOAD:%.*]] = load i64, i64* [[PAYLOAD_ADDR]]
// --                                                   0x3FFF_FFFF_FFFF_FFFF
// CHECK-64:   [[PAYLOAD_MASKED:%.*]] = and i64 [[PAYLOAD]], 4611686018427387903
// --                                                         0x4000_0000_0000_0000
// CHECK-64:   [[PAYLOAD_TAGGED:%.*]] = or i64 [[PAYLOAD_MASKED]], 4611686018427387904
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %1 to i64*
// CHECK-64:   store i64 [[PAYLOAD_TAGGED]], i64* [[PAYLOAD_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @multi_payload_two_spare_bits_inject_y_indirect : $(Builtin.Int60, @inout MultiPayloadTwoSpareBits) -> () {
entry(%0 : $Builtin.Int60, %1 : $*MultiPayloadTwoSpareBits):
  %a = init_enum_data_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1
  store %0 to %a : $*Builtin.Int60
  inject_enum_addr %1 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.y!enumelt.1
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define i64 @multi_payload_two_spare_bits_inject_z(i61) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[ZEXT:%.*]] = zext i61 %0 to i64
// --                      0x8000_0000_0000_0000
// CHECK-64:   [[TAGGED:%.*]] = or i64 [[ZEXT]], -9223372036854775808
// CHECK-64:   ret i64 [[TAGGED]]
// CHECK-64: }
sil @multi_payload_two_spare_bits_inject_z : $(Builtin.Int61) -> MultiPayloadTwoSpareBits {
entry(%0 : $Builtin.Int61):
  %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.z!enumelt.1, %0 : $Builtin.Int61
  return %u : $MultiPayloadTwoSpareBits
}

// CHECK-64: define 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 void @multi_payload_two_spare_bits_inject_a_indirect(%O4enum24MultiPayloadTwoSpareBits* nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   [[PAYLOAD_ADDR:%.*]] = bitcast %O4enum24MultiPayloadTwoSpareBits* %0 to i64*
// --                0xC000_0000_0000_0000
// CHECK-64:   store i64 -4611686018427387904, i64* [[PAYLOAD_ADDR]]
// CHECK-64:   ret void
// CHECK-64: }
sil @multi_payload_two_spare_bits_inject_a_indirect : $(@inout MultiPayloadTwoSpareBits) -> () {
entry(%0 : $*MultiPayloadTwoSpareBits):
  inject_enum_addr %0 : $*MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.a!enumelt
  %v = tuple ()
  return %v : $()
}

// CHECK-64: define 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 i64 @multi_payload_two_spare_bits_inject_c() {{.*}} {
// CHECK-64: entry:
// --              0xC000_0000_0000_0002
// CHECK-64:   ret i64 -4611686018427387902
// CHECK-64: }
sil @multi_payload_two_spare_bits_inject_c : $() -> MultiPayloadTwoSpareBits {
entry:
  %u = enum $MultiPayloadTwoSpareBits, #MultiPayloadTwoSpareBits.c!enumelt
  return %u : $MultiPayloadTwoSpareBits
}

class D {}
sil_vtable D {}

sil @_TFC4enum1DD : $@convention(method) (D) -> ()

enum MultiPayloadClasses {
  case x(C)
  case y(D)
  case z
  case w
}

// CHECK-64-LABEL: define void @multi_payload_classes_switch(i64) {{.*}} {
// CHECK-64:   %1 = lshr i64 %0, 62
// CHECK-64:   %2 = trunc i64 %1 to i2
// CHECK-64:   switch i2 %2, label {{%.*}} [
// CHECK-64:     i2 0, label {{%.*}}
// CHECK-64:     i2 1, label {{%.*}}
// CHECK-64:     i2 -2, label {{%.*}}
// CHECK-64:   ]
// CHECK-64:   switch i64 %0, label {{%.*}} [
// --             0x8000000000000000
// CHECK-64:     i64 -9223372036854775808, label {{%.*}}
// --             0x8000000000000008
// CHECK-64:     i64 -9223372036854775800, label {{%.*}}
// CHECK-64:   ]
// -- Extract x(C)
// CHECK-64:   inttoptr i64 %0 to %C4enum1C*
// -- Extract y(D)
// --                                     0x3fffffffffffffff
// CHECK-64:   [[MASKED:%.*]] = and i64 %0, 4611686018427387903
// CHECK-64:   inttoptr i64 [[MASKED]] to %C4enum1D*

// CHECK-32-LABEL: define void @multi_payload_classes_switch(i32) {{.*}} {
// CHECK-32:   %1 = trunc i32 %0 to i2
// CHECK-32:   switch i2 %1, label {{%.*}} [
// CHECK-32:     i2 0, label {{%.*}}
// CHECK-32:     i2 1, label {{%.*}}
// CHECK-32:     i2 -2, label {{%.*}}
// CHECK-32:   ]
// CHECK-32:   switch i32 %0, label {{%.*}} [
// CHECK-32:     i32 2, label {{%.*}}
// CHECK-32:     i32 6, label {{%.*}}
// CHECK-32:   ]
// -- Extract x(C)
// CHECK-32:   inttoptr i32 %0 to %C4enum1C*
// -- Extract y(D)
// CHECK-32:   [[MASKED:%.*]] = and i32 %0, -4
// CHECK-32:   inttoptr i32 [[MASKED]] to %C4enum1D*

sil @multi_payload_classes_switch : $(MultiPayloadClasses) -> () {
entry(%c : $MultiPayloadClasses):
  switch_enum %c : $MultiPayloadClasses, case #MultiPayloadClasses.x!enumelt.1: x_dest, case #MultiPayloadClasses.y!enumelt.1: y_dest, case #MultiPayloadClasses.z!enumelt: z_dest, case #MultiPayloadClasses.w!enumelt: w_dest

x_dest(%x : $C):
  br end

y_dest(%y : $D):
  br end

z_dest:
  br end

w_dest:
  br end

end:
  return undef : $()
}

struct S {
  var a: CharLike
  var b: IntLike
}

enum MultiPayloadSpareBitAggregates {
  // Has spare bits in the padding between Int32 and Int64
  case x(Builtin.Int32, Builtin.Int64)
  // Has spare bits in the object pointers
  case y(C, C)
  // Has spare bits in the padding between struct fields
  case z(S)
}

// CHECK-64-LABEL: define void @multi_payload_spare_bit_aggregate_switch(i64, i64) {{.*}} {
// CHECK-64:   [[T0:%.*]] = lshr i64 %0, 62
// CHECK-64:   [[TAG:%.*]] = trunc i64 [[T0]] to i2
// CHECK-64:   switch i2 [[TAG]], label {{%.*}} [
// CHECK-64:     i2 0, label %[[X_DEST:[0-9]+]]
// CHECK-64:     i2 1, label %[[Y_DEST:[0-9]+]]
// CHECK-64:     i2 -2, label %[[Z_DEST:[0-9]+]]
// CHECK-64:   ]
// CHECK-64: ; <label>:[[X_DEST]]
// CHECK-64:   [[X_0:%.*]] = trunc i64 %0 to i32
// CHECK-64: ; <label>:[[Y_DEST]]
// --                                        0x3fffffffffffffff
// CHECK-64:   [[Y_MASKED:%.*]] = and i64 %0, 4611686018427387903
// CHECK-64:   [[Y_0:%.*]] = inttoptr i64 [[Y_MASKED]] to %C4enum1C*
// CHECK-64:   [[Y_1:%.*]] = inttoptr i64 %1 to %C4enum1C*
// CHECK-64: ; <label>:[[Z_DEST]]
// --                                        0x3fffffffffffffff
// CHECK-64:   [[Z_MASKED:%.*]] = and i64 %0, 4611686018427387903
// CHECK-64:   [[Z_A:%.*]] = trunc i64 [[Z_MASKED]] to i21

sil @multi_payload_spare_bit_aggregate_switch : $(MultiPayloadSpareBitAggregates) -> () {
entry(%c : $MultiPayloadSpareBitAggregates):
  switch_enum %c : $MultiPayloadSpareBitAggregates, case #MultiPayloadSpareBitAggregates.x!enumelt.1: x_dest, case #MultiPayloadSpareBitAggregates.y!enumelt.1: y_dest, case #MultiPayloadSpareBitAggregates.z!enumelt.1: z_dest

x_dest(%x : $(Builtin.Int32, Builtin.Int64)):
  br end

y_dest(%y : $(C, C)):
  br end

z_dest(%z : $S):
  br end

end:
  return undef : $()
}

// <rdar://problem/15759464>
enum MultiPayloadInner {
  case A(Builtin.Word)
  case B(Builtin.Word)
}

enum MultiPayloadNested {
  case A(MultiPayloadInner)
  case B(MultiPayloadInner)
}

// CHECK-LABEL: define void @multi_payload_nested_switch
// CHECK:   %1 = bitcast %O4enum18MultiPayloadNested* %0 to { [[WORD]], i8 }*
// CHECK:   %2 = getelementptr
// CHECK:   %3 = load [[WORD]], [[WORD]]* %2
// CHECK:   %4 = getelementptr
// CHECK:   %5 = load i8, i8* %4
// CHECK:   %6 = lshr i8 %5, 7
// CHECK:   %7 = trunc i8 %6 to i1
// CHECK:   switch i1 %7, label {{%.*}} [
// CHECK:     i1 false, label {{%.*}}
// CHECK:     i1 true, label {{%.*}}
// CHECK:   ]
sil @multi_payload_nested_switch : $(@in MultiPayloadNested) -> () {
entry(%c : $*MultiPayloadNested):
  switch_enum_addr %c : $*MultiPayloadNested, case #MultiPayloadNested.A!enumelt.1: a_dest, case #MultiPayloadNested.B!enumelt.1: b_dest

a_dest:
  br end

b_dest:
  br end

end:
  return undef : $()
}

enum MultiPayloadInnerSpareBits {
  case A(Builtin.NativeObject)
  case B(Builtin.NativeObject)
  case C(Builtin.NativeObject)
  case D(Builtin.NativeObject)
}

enum MultiPayloadNestedSpareBits {
  case A(MultiPayloadInnerSpareBits)
  case B(MultiPayloadInnerSpareBits)
}

// CHECK-64-LABEL: define void @multi_payload_nested_spare_bits_switch(%O4enum27MultiPayloadNestedSpareBits* noalias nocapture dereferenceable({{.*}})) {{.*}} {
// CHECK-64: entry:
// CHECK-64:   %1 = bitcast %O4enum27MultiPayloadNestedSpareBits* %0 to [[WORD]]*
// CHECK-64:   %2 = load [[WORD]], [[WORD]]* %1
// CHECK-64:   %3 = lshr [[WORD]] %2, 61
// CHECK-64:   %4 = trunc [[WORD]] %3 to i1
// CHECK-64:   switch i1 %4, label {{%.*}} [
// CHECK-64:     i1 false, label {{%.*}}
// CHECK-64:     i1 true, label {{%.*}}
// CHECK-64:   ]
sil @multi_payload_nested_spare_bits_switch : $(@in MultiPayloadNestedSpareBits) -> () {
entry(%c : $*MultiPayloadNestedSpareBits):
  switch_enum_addr %c : $*MultiPayloadNestedSpareBits, case #MultiPayloadNestedSpareBits.A!enumelt.1: a_dest, case #MultiPayloadNestedSpareBits.B!enumelt.1: b_dest

a_dest:
  br end

b_dest:
  br end

end:
  return undef : $()
}


// -- test for a switch_enum bug for multi-payload, no-empty-case enums
//    uncovered by Chris
enum OnlyPayloads {
  case x(Builtin.Int64)
  case y(Builtin.Int32)
  case z(Builtin.Int16)
}

sil @only_payloads_switch : $(OnlyPayloads) -> () {
entry(%0 : $OnlyPayloads):
  switch_enum %0 : $OnlyPayloads, case #OnlyPayloads.x!enumelt.1: x_dest, case #OnlyPayloads.y!enumelt.1: y_dest, case #OnlyPayloads.z!enumelt.1: z_dest

x_dest:
  br end
y_dest:
  br end
z_dest:
  br end

end:
  %v = tuple ()
  return %v : $()
}

// Should not use spare bits, because T may be a tagged ObjC pointer.
enum MultiPayloadClassGeneric<T: AnyObject> {
  case A(C, Builtin.Word)
  case B(T)
}

// CHECK-64-LABEL: define { i64, i64, i1 } @multi_payload_class_generic_no_spare_bits(i64, i64, i1, %swift.type* %T)
// CHECK-32-LABEL: define { i32, i32, i1 } @multi_payload_class_generic_no_spare_bits(i32, i32, i1, %swift.type* %T)
sil @multi_payload_class_generic_no_spare_bits : $@convention(thin) <T: AnyObject> (@owned MultiPayloadClassGeneric<T>) -> MultiPayloadClassGeneric<T> {
entry(%e : $MultiPayloadClassGeneric<T>):
  return %e : $MultiPayloadClassGeneric<T>
}

// CHECK-64-LABEL: define { i64, i64, i1 } @multi_payload_class_instance_no_spare_bits(i64, i64, i1)
// CHECK-32-LABEL: define { i32, i32, i1 } @multi_payload_class_instance_no_spare_bits(i32, i32, i1)
sil @multi_payload_class_instance_no_spare_bits : $@convention(thin) (@owned MultiPayloadClassGeneric<C>) -> MultiPayloadClassGeneric<C> {
entry(%e : $MultiPayloadClassGeneric<C>):
  return %e : $MultiPayloadClassGeneric<C>
}

enum MultiPayloadAddressOnlyFixed {
  case X(protocol<>)
  case Y(Builtin.Int32)
}

// CHECK-LABEL: define void @multi_payload_address_only_destroy(%O4enum28MultiPayloadAddressOnlyFixed* noalias nocapture dereferenceable({{.*}}))
sil @multi_payload_address_only_destroy : $@convention(thin) (@in MultiPayloadAddressOnlyFixed) -> () {
entry(%m : $*MultiPayloadAddressOnlyFixed):
  destroy_addr %m : $*MultiPayloadAddressOnlyFixed
  return undef : $()
}

// Even if spare bits are available in an address-only payload,
// we cannot use them.

struct AddressOnlySpareBitsPayload {
  weak var x: C?
  var y: C
}

enum MultiPayloadAddressOnlySpareBits {
  case X(AddressOnlySpareBitsPayload)
  case Y(AddressOnlySpareBitsPayload)
}

// CHECK-LABEL: define void @multi_payload_address_only_spare_bits(%O4enum32MultiPayloadAddressOnlySpareBits* noalias nocapture dereferenceable({{.*}}))
sil @multi_payload_address_only_spare_bits : $@convention(thin) (@in MultiPayloadAddressOnlySpareBits) -> () {
entry(%m : $*MultiPayloadAddressOnlySpareBits):
  destroy_addr %m : $*MultiPayloadAddressOnlySpareBits
  return undef : $()
}

// Force the storage types to all be generated.
typealias AllConcreteTestEnums = (
  Empty,
  EmptySingleton,
  Singleton,
  SingletonRef,
  NoPayloads,
  NoPayloads2,
  SinglePayloadNoXI,
  SinglePayloadNoXI2,
  SinglePayloadSpareBit,
  SinglePayloadNested,
  SinglePayloadNestedNested,
  MultiPayloadNoSpareBits,
  MultiPayloadOneSpareBit,
  MultiPayloadTwoSpareBits,
  MultiPayloadSpareBitAggregates,
  MultiPayloadNested,
  MultiPayloadNestedSpareBits)

sil_global @x : $AllConcreteTestEnums

// CHECK: define 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 void @dynamic_singleton_instance_arg_1()
sil @dynamic_singleton_instance_arg_1 : $(DynamicSingleton<()>) -> () {
entry(%0 : $DynamicSingleton<()>):
  %v = tuple ()
  return %v : $()
}
// CHECK: define void @dynamic_singleton_instance_arg_2(i2)
sil @dynamic_singleton_instance_arg_2 : $(DynamicSingleton<NoPayloads>) -> () {
entry(%0 : $DynamicSingleton<NoPayloads>):
  %v = tuple ()
  return %v : $()
}

// Check that payloads get properly masked in nested single-payload enums.
// rdar://problem/18841262
// CHECK-64-LABEL: define i1 @optional_optional_class_protocol(i64, i64)
// CHECK-64:         icmp eq i64 %0, 2
// CHECK-32-LABEL: define i1 @optional_optional_class_protocol(i32, i32)
// CHECK-32:         icmp eq i32 %0, 1
enum Optionable<T> {
  case Some(T), None
}
sil @optional_optional_class_protocol : $@convention(thin) Optionable<Optionable<PC>> -> Builtin.Int1 {
entry(%o : $Optionable<Optionable<PC>>):
  %t = integer_literal $Builtin.Int1, 1
  %f = integer_literal $Builtin.Int1, 0
  %r = select_enum %o : $Optionable<Optionable<PC>>, case #Optionable.Some!enumelt.1: %t, case #Optionable.None!enumelt: %f : $Builtin.Int1
  return %r : $Builtin.Int1
}

struct ContainsUnowned {
  unowned let x: C
}
struct ContainsUnownedObjC {
  unowned let x: C
}
// CHECK-LABEL: define {{.*}} @optional_unowned() {{.*}} {
// CHECK-objc-64:     ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true }
// CHECK-native-64:   ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 2 }
// CHECK-objc-32:     ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true }
// CHECK-native-32:   ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 }
sil @optional_unowned : $@convention(thin) () -> (Optionable<ContainsUnowned>, Optionable<Optionable<ContainsUnowned>>) {
entry:
  %a = enum $Optionable<ContainsUnowned>, #Optionable.None!enumelt
  %b = enum $Optionable<Optionable<ContainsUnowned>>, #Optionable.None!enumelt
  %t = tuple (%a : $Optionable<ContainsUnowned>, %b : $Optionable<Optionable<ContainsUnowned>>)
  return %t : $(Optionable<ContainsUnowned>, Optionable<Optionable<ContainsUnowned>>)
}
// CHECK-LABEL: define {{.*}} @optional_unowned_objc() {{.*}} {
// CHECK-objc-64:      ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true }
// CHECK-native-64:    ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 2 }
// CHECK-objc-32:      ret { [[WORD]], [[WORD]], i1 } { [[WORD]] 0, [[WORD]] 0, i1 true }
// CHECK-native-32:    ret { [[WORD]], [[WORD]] } { [[WORD]] 0, [[WORD]] 1 }
sil @optional_unowned_objc : $@convention(thin) () -> (Optionable<ContainsUnownedObjC>, Optionable<Optionable<ContainsUnownedObjC>>) {
entry:
  %a = enum $Optionable<ContainsUnownedObjC>, #Optionable.None!enumelt
  %b = enum $Optionable<Optionable<ContainsUnownedObjC>>, #Optionable.None!enumelt
  %t = tuple (%a : $Optionable<ContainsUnownedObjC>, %b : $Optionable<Optionable<ContainsUnownedObjC>>)
  return %t : $(Optionable<ContainsUnownedObjC>, Optionable<Optionable<ContainsUnownedObjC>>)
}

// CHECK-64-LABEL: define { i64, i1 } @empty_payload_enum_in_enum(i32)
sil @empty_payload_enum_in_enum : $@convention(thin) (Int32) -> Optional<(Optional<()>, Int32)> {
entry(%x : $Int32):
  %a = tuple ()
  %b = enum $Optional<()>, #Optional.Some!enumelt.1, %a : $()
  %c = tuple (%b : $Optional<()>, %x : $Int32)
  // CHECK-64: [[INT_ZEXT:%.*]] = zext i32 %0 to i64
  // CHECK-64: [[INT_SHL:%.*]] = shl i64 [[INT_ZEXT]], 32
  // CHECK-64: [[COMBINE:%.*]] = or i64 0, [[INT_SHL]]
  %d = enum $Optional<(Optional<()>, Int32)>, #Optional.Some!enumelt.1, %c : $(Optional<()>, Int32)
  // CHECK-64: [[BIT:%.*]] = trunc i64 [[COMBINE]] to i1
  // CHECK-64: [[INT_SHR:%.*]] = lshr i64 [[COMBINE]], 32
  // CHECK-64: [[INT:%.*]] = trunc i64 [[INT_SHR]] to i32
  %e = unchecked_enum_data %d : $Optional<(Optional<()>, Int32)>, #Optional.Some!enumelt.1
  return %d : $Optional<(Optional<()>, Int32)>
}

sil @optional_float80 : $@convention(thin) Float80 -> () {
entry(%x : $Float80):
  %y = enum $Optional<Float80>, #Optional.Some!enumelt.1, %x : $Float80
  return undef : $()
}

// rdar://problem/21126703

protocol delegateProtocol : AnyObject { }

struct StructWithWeakVar {
weak var delegate: delegateProtocol?
}

// CHECK-64-LABEL: define void @weak_optional(%Sq{{.*}}* noalias nocapture dereferenceable({{.*}}))
sil @weak_optional : $@convention(thin) (@in StructWithWeakVar?) -> () {
entry(%x : $*StructWithWeakVar?):
  // CHECK-64:      icmp eq [[WORD]] {{%.*}}, 0
  // CHECK-64-NEXT: icmp eq [[WORD]] {{%.*}}, 1
  switch_enum_addr %x : $*StructWithWeakVar?,
    case #Optional.Some!enumelt.1: a,
    case #Optional.None!enumelt:   b
a:
  br x
b:
  // CHECK-64:      store [[WORD]] 0
  // CHECK-64:      store [[WORD]] 1
  inject_enum_addr %x : $*StructWithWeakVar?, #Optional.None!enumelt
  br x

x:
  return undef : $()
}

// CHECK-LABEL: define 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 void @generate_conditional_branch
sil @generate_conditional_branch : $@convention(thin) (@owned Target) -> () {
bb0(%0 : $Target):
  debug_value %0 : $Target
  retain_value %0 : $Target
  switch_enum %0 : $Target, case #Target.Public!enumelt: bb1, default bb2

bb1:
  br bb4

bb2:
  br bb3

bb3:
  release_value %0 : $Target
  br bb4

bb4:
  release_value %0 : $Target
  %9 = tuple ()
// CHECK: ret void
  return %9 : $()
}

// -- Fill function for dynamic singleton. The value witness table flags just
//    get copied over from the element.
// CHECK: define private %swift.type* @create_generic_metadata_DynamicSingleton(%swift.type_pattern*, i8**) {{.*}} {
// CHECK:   [[T0:%.*]] = load i8*, i8** %1
// CHECK:   [[T:%.*]] = bitcast i8* [[T0]] to %swift.type*
// CHECK:   [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1)
// CHECK:   [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8**
// CHECK:   [[T0:%.*]] = bitcast %swift.type* [[T]] to i8*
// CHECK:   [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 3
// CHECK:   store i8* [[T0]], i8** [[T1]]
// CHECK:   [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 5
// CHECK:   [[T0:%.*]] = bitcast i8** [[VWT]] to i8*
// CHECK:   [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 -1
// CHECK:   store i8* [[T0]], i8** [[T1]]
// CHECK:   [[T_VWTS:%.*]] = bitcast %swift.type* [[T]] to i8***
// CHECK:   [[T_VWT_ADDR:%.*]] = getelementptr inbounds i8**, i8*** [[T_VWTS]], [[WORD]] -1
// CHECK:   [[T_VWT:%.*]] = load i8**, i8*** [[T_VWT_ADDR]]
// CHECK:   [[T_LAYOUT:%.*]] = getelementptr inbounds i8*, i8** [[T_VWT]], i32 17
// CHECK:   [[SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 17
// CHECK:   [[T_SIZE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 0
// CHECK:   [[T_SIZE:%.*]] = load i8*, i8** [[T_SIZE_ADDR]]
// CHECK:   store i8* [[T_SIZE]], i8** [[SIZE_ADDR]]
// CHECK:   [[STRIDE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 19
// CHECK:   [[T_STRIDE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 2
// CHECK:   [[T_STRIDE:%.*]] = load i8*, i8** [[T_STRIDE_ADDR]]
// CHECK:   store i8* [[T_STRIDE]], i8** [[STRIDE_ADDR]]
// CHECK:   [[FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 18
// CHECK:   [[T_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 1
// CHECK:   [[T_FLAGS:%.*]] = load i8*, i8** [[T_FLAGS_ADDR]]
// CHECK:   [[T_FLAGS_INT:%.*]] = ptrtoint i8* [[T_FLAGS]] to [[WORD]]
// CHECK:   [[T_FLAGS_INT_2:%.*]] = or [[WORD]] [[T_FLAGS_INT]], 2097152
// CHECK:   [[T_FLAGS_2:%.*]] = inttoptr [[WORD]] [[T_FLAGS_INT_2]] to i8*
// CHECK:   store i8* [[T_FLAGS_2]], i8** [[FLAGS_ADDR]]
// -- Test the 'has extra inhabitants' bit and carry over the extra inhabitants
//    flag if set.
// CHECK:   [[T_FLAGS_VAL:%.*]] = ptrtoint i8* [[T_FLAGS]] to [[WORD]]
// CHECK:   [[XI_FLAG:%.*]] = and [[WORD]] [[T_FLAGS_VAL]], 262144
// CHECK:   [[XI_BIT:%.*]] = icmp ne [[WORD]] [[XI_FLAG]], 0
// CHECK:   br i1 [[XI_BIT]], label %[[HAS_XI:[0-9]+]], label %[[HAS_NO_XI:[0-9]+]]
// CHECK: ; <label>:[[HAS_XI]]
// CHECK:   [[XI_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[VWT]], i32 20
// CHECK:   [[T_XI_FLAGS_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[T_LAYOUT]], i32 3
// CHECK:   [[T_XI_FLAGS:%.*]] = load i8*, i8** [[T_XI_FLAGS_ADDR]]
// CHECK:   store i8* [[T_XI_FLAGS]], i8** [[XI_FLAGS_ADDR]]
// CHECK:   br label %[[HAS_NO_XI]]
// CHECK: ; <label>:[[HAS_NO_XI]]
// CHECK:   ret %swift.type* [[METADATA]]

// -- Fill function for dynamic single-payload. Call into the runtime to
//    calculate the size.
// CHECK: define private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} {
// CHECK:   call void @swift_initEnumValueWitnessTableSinglePayload

// CHECK-64-LABEL: define linkonce_odr hidden void @_TwxsV4enum17StructWithWeakVar(%swift.opaque* %dest, i32 %index, %swift.type* %Self)
// -- TODO: some pointless masking here.
// -- TODO: should use EnumPayload word-chunking.
// CHECK-64:         %1 = zext i32 %index to i128
// --                             0xFFFF_FFFF_FFFF_FFFF
// CHECK-64:         %2 = and i128 %1, 18446744073709551615
// CHECK-64:         %3 = shl i128 %1, 3
// --                             0xFFFF_FFFF_FFFF_FFF8__0000_0000_0000_0000
// CHECK-64:         %4 = and i128 %3, 1329227995784915725329854470603931648
// CHECK-64:         %5 = or i128 %2, %4
// --                             0x1__0000_0000_0000_0000
// CHECK-64:         %6 = or i128 %5, 18446744073709551616
back to top