Files
swift-mirror/test/SILOptimizer/sil_combine.sil
Nate Chandler e5d87f75a8 [SIL] Add source formal type to checked_cast_br.
It is necessary for opaque values where for casts that will newly start
out as checked_cast_brs and be lowered to checked_cast_addr_brs, since
the latter has the source formal type, IRGen relies on being able to
access it, and there's no way in general to obtain the source formal
type from the source lowered type.
2023-07-27 15:04:15 -07:00

4344 lines
174 KiB
Plaintext

// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all %s -sil-combine | %FileCheck %s
// REQUIRES: swift_in_compiler
// Declare this SIL to be canonical because some tests break raw SIL
// conventions. e.g. address-type block args. -enforce-exclusivity=none is also
// required to allow address-type block args in canonical SIL.
sil_stage canonical
import Builtin
import Swift
class Klass {}
class RawBuffer {}
class HeapBufferStorage<T, U> : RawBuffer {}
enum FakeOptional<T> {
case none
case some(T)
}
struct StringData {
var size: Builtin.Word
}
struct PointerStorage {
var ptr: FakeOptional<Builtin.NativeObject>
}
class B { }
class E : B { }
enum AddressOnlyEnum {
case Loadable(Builtin.Int32)
case AddressOnly(Any)
}
protocol FakeProtocol {
func requirement()
}
struct MyInt {
var value: Builtin.Int32
}
sil [global_init] @global_init_fun : $@convention(thin) () -> Builtin.RawPointer
sil @user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
sil @unknown : $@convention(thin) () -> ()
//////////////////////
// Simple DCE Tests //
//////////////////////
// CHECK-LABEL: sil @dead_inst_elimination_one_bb
// CHECK-NOT: integer_literal $Builtin.Int64, 24
sil @dead_inst_elimination_one_bb : $@convention(thin) () -> () {
%0 = integer_literal $Builtin.Int64, 24
%1 = tuple()
return %1 : $()
}
// CHECK-LABEL: sil @dead_inst_elimination_diamond
// CHECK: bb0
// CHECK-NOT: integer_literal $Builtin.Int64, 24
// CHECK: bb1
// CHECK-NOT: integer_literal $Builtin.Int64, 48
sil @dead_inst_elimination_diamond : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int64, 24
cond_br %0, bb1, bb2
bb1:
%2 = integer_literal $Builtin.Int64, 48
br bb3
bb2:
%3 = integer_literal $Builtin.Int64, 96
br bb3
bb3:
%4 = tuple()
return %4 : $()
}
sil @random_counter : $@convention(thin) () -> Builtin.Int1
// CHECK-LABEL: sil @dead_inst_elimination_loop
// CHECK: bb0
// CHECK-NOT: integer_literal
// CHECK: bb1
// CHECK: function_ref
// CHECK: apply
// CHECK-NOT: integer_literal
// CHECK: bb2
// CHECK-NOT: integer_literal
// CHECK: tuple
// CHECK: return
sil @dead_inst_elimination_loop : $@convention(thin) () -> () {
bb0:
%1 = integer_literal $Builtin.Int64, 24
br bb1
bb1:
%2 = function_ref @random_counter : $@convention(thin) () -> Builtin.Int1
%3 = apply %2() : $@convention(thin) () -> Builtin.Int1
%4 = integer_literal $Builtin.Int64, 48
cond_br %3, bb1, bb2
bb2:
%5 = integer_literal $Builtin.Int64, 59
%6 = tuple()
return %6 : $()
}
// For now until the proper unreachable pruning code is committed for
// SILCombine, we should not dce dead instructions in unreachable code.
// CHECK-LABEL: sil @dead_inst_elimination_ignore_unreachable
// CHECK: bb0
// CHECK-NOT: integer_literal $Builtin.Int64, 24
// CHECK: bb1
// CHECK: integer_literal $Builtin.Int64, 48
sil @dead_inst_elimination_ignore_unreachable : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Int64, 24
br bb2
bb1:
%1 = integer_literal $Builtin.Int64, 48
br bb2
bb2:
%2 = tuple()
return %2 : $()
}
//////////////////////////////////////////////////////////
// Other DCE Tests taken from diagnose_unreachable.sil //
//////////////////////////////////////////////////////////
sil @exit : $@convention(thin) () -> Never {
bb0:
br bb1
bb1:
br bb1
}
// CHECK-LABEL: sil @removeTriviallyDeadInstructions
// CHECK: store
// CHECK: strong_retain
// CHECK-NOT: unchecked_ref_cast
// CHECK: strong_release
// CHECK-NEXT: strong_release
// CHECK-NOT: unchecked_ref_cast
sil @removeTriviallyDeadInstructions : $@convention(thin) (@owned B) -> () {
bb0(%0 : $B):
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <B>
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
store %0 to %1a : $*B
%3 = load %1a : $*B
strong_retain %3 : $B
%5 = unchecked_ref_cast %3 : $B to $Builtin.NativeObject
strong_release %3 : $B
strong_release %1 : $<τ_0_0> { var τ_0_0 } <B>
%9 = function_ref @exit : $@convention(thin) () -> Never // ret.exit : () -> ()
%10 = apply %9() : $@convention(thin) () -> Never
unreachable
}
// CHECK-LABEL: sil @removeTriviallyDeadCrossBasicBlocks
// CHECK-NOT: unchecked_ref_cast
// CHECK: cond_br
// CHECK-NOT: unchecked_ref_cast
// CHECK: }
sil @removeTriviallyDeadCrossBasicBlocks : $@convention(thin) (@owned B, Builtin.Int1) -> () {
bb0(%0: $B, %1: $Builtin.Int1):
%5 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject
cond_br %1, bb1, bb2
bb1:
br bb2
bb2:
%9 = function_ref @exit : $@convention(thin) () -> Never // ret.exit : () -> ()
%10 = apply %9() : $@convention(thin) () -> Never
unreachable
}
// CHECK-LABEL: sil @dead_use_of_alloc_stack
// CHECK: bb
// CHECK: alloc_stack
// CHECK: dealloc_stack
// CHECK: }
sil @dead_use_of_alloc_stack : $@convention(thin) () -> () {
bb0:
%1 = alloc_stack $((), (), ())
%2 = tuple_element_addr %1 : $*((), (), ()), 0
dealloc_stack %1 : $*((), (), ())
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: sil @tuple_extract
// CHECK: bb
// CHECK-NEXT: return %0
sil @tuple_extract : $@convention(thin) (Int64) -> Int64 {
bb0(%0 : $Int64):
%1 = tuple (%0 : $Int64, %0 : $Int64)
%2 = tuple_extract %1 : $(Int64, Int64), 0
return %2 : $Int64
}
// CHECK-LABEL: sil @do_not_fold_integer_literal
// CHECK: bb
// CHECK: cond_br
// CHECK: {{^bb}}
// CHECK-NEXT: integer_literal
// CHECK-NEXT: br bb
// CHECK: {{^bb}}
// CHECK-NEXT: integer_literal
// CHECK-NEXT: br bb
sil @do_not_fold_integer_literal : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb3
bb1:
%1 = integer_literal $Builtin.Int1, 0
br bb2(%1 : $Builtin.Int1)
bb3:
%2 = integer_literal $Builtin.Int1, -1
br bb2(%2 : $Builtin.Int1)
bb2(%3 : $Builtin.Int1):
return %3 : $Builtin.Int1
}
enum BoolLike { case true_, false_ }
// CHECK-LABEL: sil @fold_enum
// CHECK: bb
// CHECK: switch_enum
// CHECK: {{^bb}}
// CHECK-NOT: enum
// CHECK-NEXT: br bb
// CHECK: {{^bb}}
// CHECK-NOT: enum
// CHECK-NEXT: br bb
sil @fold_enum : $@convention(thin) (BoolLike) -> BoolLike {
bb0(%0 : $BoolLike):
switch_enum %0 : $BoolLike, case #BoolLike.true_!enumelt: bb1, case #BoolLike.false_!enumelt: bb2
bb1:
%1 = enum $BoolLike, #BoolLike.true_!enumelt
br bb3(%1 : $BoolLike)
bb2:
%2 = enum $BoolLike, #BoolLike.false_!enumelt
br bb3(%2 : $BoolLike)
bb3(%3 : $BoolLike):
return %3 : $BoolLike
}
// CHECK-LABEL: sil @do_not_fold_enum
// CHECK: bb
// CHECK: switch_enum
// CHECK: {{^bb}}
// CHECK-NEXT: enum
// CHECK-NEXT: br bb
// CHECK: {{^bb}}
// CHECK-NEXT: enum
// CHECK-NEXT: br bb
sil @do_not_fold_enum : $@convention(thin) (BoolLike) -> BoolLike {
bb0(%0 : $BoolLike):
switch_enum %0 : $BoolLike, case #BoolLike.true_!enumelt: bb1, case #BoolLike.false_!enumelt: bb2
bb1:
%1 = enum $BoolLike, #BoolLike.false_!enumelt
br bb3(%1 : $BoolLike)
bb2:
%2 = enum $BoolLike, #BoolLike.true_!enumelt
br bb3(%2 : $BoolLike)
bb3(%3 : $BoolLike):
return %3 : $BoolLike
}
// CHECK-LABEL: sil @struct_extract_load_to_load_struct_element_addr
// CHECK: bb0([[IN:%[0-9]+]] : $*UInt8):
// CHECK-NEXT: [[IN_GEP:%[0-9]+]] = struct_element_addr [[IN]] : $*UInt8, #UInt8._value
// CHECK-NEXT: [[IN_LOADED:%[0-9]+]] = load [[IN_GEP]] : $*Builtin.Int8
// CHECK-NEXT: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int8, 1
// CHECK-NEXT: [[UINT8:%.*]] = struct $UInt8 ([[LITERAL]] : $Builtin.Int8)
// CHECK-NEXT: store [[UINT8]] to [[IN]] : $*UInt8
// CHECK-NEXT: return [[IN_LOADED]] : $Builtin.Int8
sil @struct_extract_load_to_load_struct_element_addr : $@convention(thin) (@inout UInt8) -> (Builtin.Int8) {
bb0(%0 : $*UInt8):
%1 = load %0 : $*UInt8
%2 = integer_literal $Builtin.Int8, 1
%3 = struct_element_addr %0 : $*UInt8, #UInt8._value
store %2 to %3 : $*Builtin.Int8
%5 = struct_extract %1 : $UInt8, #UInt8._value
return %5 : $Builtin.Int8
}
// CHECK-LABEL: sil @tuple_extract_load_to_load_tuple_element_addr
// CHECK: bb0([[IN:%[0-9]+]] : $*(Builtin.Int8, Builtin.Int8)):
// CHECK-NEXT: [[IN_GEP:%[0-9]+]] = tuple_element_addr [[IN]] : $*(Builtin.Int8, Builtin.Int8), 0
// CHECK-NEXT: [[IN_LOADED:%[0-9]+]] = load [[IN_GEP]] : $*Builtin.Int8
// CHECK-NEXT: [[LITERAL:%[0-9]+]] = integer_literal $Builtin.Int8, 1
// CHECK-NEXT: [[IN_STORE_GEP:%[0-9]+]] = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
// CHECK-NEXT: store [[LITERAL]] to [[IN_STORE_GEP]] : $*Builtin.Int8
// CHECK-NEXT: return [[IN_LOADED]] : $Builtin.Int8
sil @tuple_extract_load_to_load_tuple_element_addr : $@convention(thin) (@inout (Builtin.Int8, Builtin.Int8)) -> (Builtin.Int8) {
bb0(%0 : $*(Builtin.Int8, Builtin.Int8)):
%1 = load %0 : $*(Builtin.Int8, Builtin.Int8)
%2 = integer_literal $Builtin.Int8, 1
%3 = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
store %2 to %3 : $*Builtin.Int8
%5 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int8), 0
return %5 : $Builtin.Int8
}
// Do not perform the optimization of the input load has multiple uses.
//
// CHECK-LABEL: sil @multiple_use_struct_extract_load_to_load_struct_element_addr
// CHECK: bb0([[IN:%[0-9]+]] : $*UInt8):
// CHECK-NEXT: load
// CHECK-NEXT: integer_literal
// CHECK-NEXT: struct
// CHECK-NEXT: store
// CHECK-NEXT: struct_extract
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @multiple_use_struct_extract_load_to_load_struct_element_addr : $@convention(thin) (@inout UInt8) -> (UInt8, Builtin.Int8) {
bb0(%0 : $*UInt8):
%1 = load %0 : $*UInt8
%2 = integer_literal $Builtin.Int8, 1
%3 = struct_element_addr %0 : $*UInt8, #UInt8._value
store %2 to %3 : $*Builtin.Int8
%5 = struct_extract %1 : $UInt8, #UInt8._value
%6 = tuple (%1 : $UInt8, %5 : $Builtin.Int8)
return %6 : $(UInt8, Builtin.Int8)
}
// Do not perform the optimization of the input load has multiple uses.
//
// CHECK-LABEL: sil @multiple_use_tuple_extract_load_to_load_tuple_element_addr
// CHECK: bb0
// CHECK-NEXT: load
// CHECK-NEXT: integer_literal
// CHECK-NEXT: tuple_element_addr
// CHECK-NEXT: store
// CHECK-NEXT: tuple_extract
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @multiple_use_tuple_extract_load_to_load_tuple_element_addr : $@convention(thin) (@inout (Builtin.Int8, Builtin.Int8)) -> ((Builtin.Int8, Builtin.Int8), Builtin.Int8) {
bb0(%0 : $*(Builtin.Int8, Builtin.Int8)):
%1 = load %0 : $*(Builtin.Int8, Builtin.Int8)
%2 = integer_literal $Builtin.Int8, 1
%3 = tuple_element_addr %0 : $*(Builtin.Int8, Builtin.Int8), 0
store %2 to %3 : $*Builtin.Int8
%5 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int8), 0
%6 = tuple (%1 : $(Builtin.Int8, Builtin.Int8), %5 : $Builtin.Int8)
return %6 : $((Builtin.Int8, Builtin.Int8), Builtin.Int8)
}
// CHECK-LABEL: sil @optimize_load_first_char_from_string_literal
// CHECK: bb0:
// CHECK-NEXT: %0 = integer_literal $Builtin.Int8, 97
// CHECK-NEXT: return %0
sil @optimize_load_first_char_from_string_literal : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = string_literal utf8 "abc123a"
%1 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*UInt8
%2 = struct_element_addr %1 : $*UInt8, #UInt8._value
%3 = load %2 : $*Builtin.Int8
return %3 : $Builtin.Int8
}
// CHECK-LABEL: sil @optimize_load_from_string_literal
// CHECK: bb0:
// CHECK-NEXT: %0 = integer_literal $Builtin.Int8, 49
// CHECK-NEXT: return %0
sil @optimize_load_from_string_literal : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = string_literal utf8 "abc123a"
%1 = integer_literal $Builtin.Word, 3
%2 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*UInt8
%3 = index_addr %2 : $*UInt8, %1 : $Builtin.Word
%4 = struct_element_addr %3 : $*UInt8, #UInt8._value
%5 = load %4 : $*Builtin.Int8
return %5 : $Builtin.Int8
}
// CHECK-LABEL: sil @optimize_nested_index_addr
// CHECK: bb0(%0 : $Builtin.RawPointer):
// CHECK-NEXT: %1 = pointer_to_address %0
// CHECK-NEXT: %2 = integer_literal $Builtin.Word, 10
// CHECK-NEXT: %3 = index_addr %1 : $*UInt8, %2
// CHECK-NEXT: %4 = address_to_pointer %3
// CHECK-NEXT: return %4
sil @optimize_nested_index_addr : $@convention(thin) (Builtin.RawPointer) -> Builtin.RawPointer {
bb0(%0 : $Builtin.RawPointer):
%1 = integer_literal $Builtin.Word, 3
%2 = integer_literal $Builtin.Word, 7
%3 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*UInt8
%4 = index_addr %3 : $*UInt8, %1 : $Builtin.Word
%5 = index_addr %4 : $*UInt8, %2 : $Builtin.Word
%6 = address_to_pointer %5 : $*UInt8 to $Builtin.RawPointer
return %6 : $Builtin.RawPointer
}
// CHECK-LABEL: sil @release_value_test
// CHECK: bb0({{%[0-9]+}} : $Builtin.Int8, [[RELEASE_TARGET:%[0-9]+]] : $Builtin.NativeObject):
// CHECK-NEXT: strong_release [[RELEASE_TARGET]] : $Builtin.NativeObject
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
sil @release_value_test : $@convention(thin) (Builtin.Int8, Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.Int8, %1 : $Builtin.NativeObject):
release_value %0 : $Builtin.Int8
release_value %1 : $Builtin.NativeObject
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @retain_value_test
// CHECK: bb0([[TRIVIAL_TARGET:%[0-9]+]] : $Builtin.Int8, [[REFCOUNT_TARGET:%[0-9]+]] : $Builtin.NativeObject):
// CHECK-NEXT: strong_retain [[REFCOUNT_TARGET]] : $Builtin.NativeObject
// CHECK-NEXT: tuple ([[TRIVIAL_TARGET]] : $Builtin.Int8, [[REFCOUNT_TARGET]] : $Builtin.NativeObject)
// CHECK-NEXT: return
sil @retain_value_test : $@convention(thin) (Builtin.Int8, Builtin.NativeObject) -> (Builtin.Int8, Builtin.NativeObject) {
bb0(%0 : $Builtin.Int8, %1 : $Builtin.NativeObject):
retain_value %0 : $Builtin.Int8
retain_value %1 : $Builtin.NativeObject
%4 = tuple(%0 : $Builtin.Int8, %1 : $Builtin.NativeObject)
return %4 : $(Builtin.Int8, Builtin.NativeObject)
}
// CHECK-LABEL: sil @a2p_p2a_test
// CHECK: bb0([[ADR:%[0-9]+]] : $*Builtin.Word, [[RAWPTR:%[0-9]+]] : $Builtin.RawPointer):
// CHECK-NEXT: load
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @a2p_p2a_test : $@convention(thin) (@inout Builtin.Word, Builtin.RawPointer) -> (Builtin.Word, Builtin.RawPointer) {
bb0(%0 : $*Builtin.Word, %1 : $Builtin.RawPointer):
%2 = address_to_pointer %0 : $*Builtin.Word to $Builtin.RawPointer
%3 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Builtin.Word
%4 = pointer_to_address %2 : $Builtin.RawPointer to [strict] $*Builtin.Word
%5 = address_to_pointer %3 : $*Builtin.Word to $Builtin.RawPointer
%6 = load %4 : $*Builtin.Word
%7 = tuple(%6 : $Builtin.Word, %5 : $Builtin.RawPointer)
return %7 : $(Builtin.Word, Builtin.RawPointer)
}
// CHECK-LABEL: sil @a2p_p2a_reinterpret_cast_word_raw_pointer
// CHECK: bb0
// CHECK-NEXT: unchecked_addr_cast
// CHECK-NEXT: load
// CHECK-NEXT: return
sil @a2p_p2a_reinterpret_cast_word_raw_pointer : $@convention(thin) (@inout Builtin.Word, Builtin.RawPointer) -> Int32 {
bb0(%0 : $*Builtin.Word, %1 : $Builtin.RawPointer):
%2 = address_to_pointer %0 : $*Builtin.Word to $Builtin.RawPointer
%3 = pointer_to_address %2 : $Builtin.RawPointer to [strict] $*Int32
%4 = load %3 : $*Int32
return %4 : $Int32
}
// CHECK-LABEL: sil @sil_extract_of_string
//
// Make sure we only forward the first field of the string_literal
// instead of the whole string literal. Otherwise we run into arity
// issues.
sil @sil_extract_of_string : $@convention(thin) () -> Builtin.Word {
%0 = string_literal utf8 ""
%l1 = integer_literal $Builtin.Word, 0
%1 = struct $StringData (%l1 : $Builtin.Word)
%2 = struct_extract %1 : $StringData, #StringData.size
return %2 : $Builtin.Word
}
class C {}
enum U {
init()
case X
case Y(Builtin.Int64)
case Z(C)
}
// CHECK-LABEL: sil @sil_destroyvalue_of_enum
// CHECK: bb0([[TYPE_ARG:%[0-9]+]] : $@thin U.Type, [[CLASS_ARG:%[0-9]+]] : $C):
// CHECK-NEXT: enum $U, #U.X!enumelt
// CHECK-NEXT: integer_literal $Builtin.Int64, 32
// CHECK-NEXT: enum $U, #U.Y!enumelt, {{%[0-9]+}} : $Builtin.Int64
// CHECK-NEXT: [[INVALID_CASE:%[0-9]+]] = enum $U, #U.Z!enumelt, {{%[0-9]+}} : $C
// CHECK-NEXT: strong_release [[CLASS_ARG]] : $C
// CHECK-NEXT: tuple ({{%[0-9]+}} : $U, {{%[0-9]+}} : $U, [[INVALID_CASE]] : $U)
// CHECK-NEXT: return
//
// release_value of an enum without any payload or with a trivial
// typed payload is a no-op. Leave enums with non-trivial payloads
// alone.
//
// rdar://15568314
sil @sil_destroyvalue_of_enum : $@convention(thin) (@thin U.Type, C) -> (U, U, U) {
bb0(%0 : $@thin U.Type, %1 : $C):
%2 = enum $U, #U.X!enumelt
release_value %2 : $U
%3 = integer_literal $Builtin.Int64, 32
%4 = enum $U, #U.Y!enumelt, %3 : $Builtin.Int64
release_value %4 : $U
%5 = enum $U, #U.Z!enumelt, %1 : $C
release_value %5 : $U
%6 = tuple(%2 : $U, %4 : $U, %5 : $U)
return %6 : $(U, U, U)
}
// CHECK-LABEL: sil @sil_copyvalue_of_enum
// CHECK: bb0([[TYPE_ARG:%[0-9]+]] : $@thin U.Type, [[CLASS_ARG:%[0-9]+]] : $C):
// CHECK-NEXT: enum $U, #U.X!enumelt
// CHECK-NEXT: integer_literal $Builtin.Int64, 32
// CHECK-NEXT: enum $U, #U.Y!enumelt, {{%[0-9]+}} : $Builtin.Int64
// CHECK-NEXT: [[INVALID_CASE:%[0-9]+]] = enum $U, #U.Z!enumelt, {{%[0-9]+}} : $C
// CHECK-NEXT: strong_retain [[CLASS_ARG]] : $C
// CHECK-NEXT: tuple ({{%[0-9]+}} : $U, {{%[0-9]+}} : $U, [[INVALID_CASE]] : $U)
// CHECK-NEXT: return
//
// copy of an enum without any payload or with a trivial typed payload
// is a no-op. Leave enums with non-trivial payloads alone.
//
// rdar://15568314
sil @sil_copyvalue_of_enum : $@convention(thin) (@thin U.Type, C) -> (U, U, U) {
bb0(%0 : $@thin U.Type, %1 : $C):
%2 = enum $U, #U.X!enumelt
retain_value %2 : $U
%3 = integer_literal $Builtin.Int64, 32
%4 = enum $U, #U.Y!enumelt, %3 : $Builtin.Int64
retain_value %4 : $U
%5 = enum $U, #U.Z!enumelt, %1 : $C
retain_value %5 : $U
%6 = tuple(%2 : $U, %4 : $U, %5 : $U)
return %6 : $(U, U, U)
}
// CHECK-LABEL: sil @downcast_upcast_roundtrip
// CHECK: bb0
// CHECK-NEXT: return
sil @downcast_upcast_roundtrip : $@convention(thin) <T_0_0, T_0_1> (HeapBufferStorage<T_0_0, T_0_1>) -> HeapBufferStorage<T_0_0, T_0_1> {
bb0(%0 : $HeapBufferStorage<T_0_0, T_0_1>):
%2 = upcast %0 : $HeapBufferStorage<T_0_0, T_0_1> to $RawBuffer // user: %3
%3 = unconditional_checked_cast %2 : $RawBuffer to HeapBufferStorage<T_0_0, T_0_1>
return %3 : $HeapBufferStorage<T_0_0, T_0_1>
}
class Derived : C {}
// CHECK-LABEL: sil @dead_unconditional_checked_cast :
// CHECK-NOT: unconditional_checked_cast
// CHECK: bb1:
// CHECK: strong_release %0
// CHECK: } // end sil function 'dead_unconditional_checked_cast'
sil @dead_unconditional_checked_cast : $@convention(thin) (@owned C) -> () {
bb0(%0 : $C):
%1 = unconditional_checked_cast %0 : $C to Derived
br bb1
bb1:
strong_release %1 : $Derived
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @cond_fail_applied_to_zero_removal
// CHECK: bb0
// CHECK-NEXT: cond_fail
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
sil @cond_fail_applied_to_zero_removal : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
cond_fail %0 : $Builtin.Int1
%1 = integer_literal $Builtin.Int1, 0
cond_fail %1 : $Builtin.Int1
%2 = tuple ()
return %2 : $()
}
// CHECK-LABEL: sil @release_then_retain_peephole
// CHECK: bb0
// CHECK-NOT: strong_release
// CHECK-NOT: strong_retain
// CHECK-NOT: retain_value
// CHECK-NOT: release_value
// CHECK-NEXT: return
sil @release_then_retain_peephole : $@convention(thin) (Builtin.NativeObject, FakeOptional<Builtin.NativeObject>) -> (Builtin.NativeObject) {
bb0(%0 : $Builtin.NativeObject, %1 : $FakeOptional<Builtin.NativeObject>):
strong_release %0 : $Builtin.NativeObject
strong_retain %0 : $Builtin.NativeObject
release_value %1 : $FakeOptional<Builtin.NativeObject>
retain_value %1 : $FakeOptional<Builtin.NativeObject>
return %0 : $Builtin.NativeObject
}
// CHECK-LABEL: sil @unchecked_ref_cast_unchecked_ref_cast_round_trip
// CHECK: bb0
// CHECK-NEXT: return
sil @unchecked_ref_cast_unchecked_ref_cast_round_trip : $@convention(thin) <T_0_0, T_0_1> (HeapBufferStorage<T_0_0, T_0_1>) -> HeapBufferStorage<T_0_0, T_0_1> {
bb0(%0 : $HeapBufferStorage<T_0_0, T_0_1>):
%1 = unchecked_ref_cast %0 : $HeapBufferStorage<T_0_0, T_0_1> to $Builtin.NativeObject
%2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $HeapBufferStorage<T_0_0, T_0_1>
return %2 : $HeapBufferStorage<T_0_0, T_0_1>
}
// CHECK-LABEL: sil @raw_pointer_to_ref_ref_to_raw_pointer_round_trip
// CHECK: bb0
// CHECK-NEXT: return
sil @raw_pointer_to_ref_ref_to_raw_pointer_round_trip : $@convention(thin) (Builtin.RawPointer) -> Builtin.RawPointer {
bb0(%0 : $Builtin.RawPointer):
%1 = raw_pointer_to_ref %0 : $Builtin.RawPointer to $C
%2 = ref_to_raw_pointer %1 : $C to $Builtin.RawPointer
return %2 : $Builtin.RawPointer
}
sil @test_closure : $@convention(thin) (@guaranteed C) -> ()
// CHECK-LABEL: sil @dead_closure_elimination
// CHECK: bb0(%0 : $C):
// CHECK-NEXT: cond_br
// CHECK-NOT: strong_release
// CHECK: bb2:
// CHECK-NEXT: strong_release %0
// CHECK: return
sil @dead_closure_elimination : $@convention(thin) (@owned C) -> () {
bb0(%0 : $C):
%1 = function_ref @test_closure : $@convention(thin) (@guaranteed C) -> ()
%2 = partial_apply [callee_guaranteed] %1(%0) : $@convention(thin) (@guaranteed C) -> ()
cond_br undef, bb1, bb2
bb1:
strong_retain %2 : $@callee_guaranteed () -> ()
strong_release %2 : $@callee_guaranteed () -> ()
br bb2
bb2:
release_value %2 : $@callee_guaranteed () -> ()
%5 = tuple()
return %5 : $()
}
////////////////////////////////////////////
// Load Proj To GEP Load Canonicalization //
////////////////////////////////////////////
struct Y {
var int : Builtin.Int64
var ptr : Builtin.NativeObject
var tup : (Builtin.Int32, Builtin.Int1)
}
struct X {
var y : Y
var t : (Builtin.NativeObject, Y)
}
sil @mix1 : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
sil @mix2 : $@convention(thin) (Builtin.NativeObject, Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
// CHECK-LABEL: sil @load_proj_to_gep_load_canonicalization_no_rep_no_other_use_test : $@convention(thin) (@inout X) -> ()
// CHECK-NOT: struct_extract
// CHECK-NOT: tuple_extract
sil @load_proj_to_gep_load_canonicalization_no_rep_no_other_use_test : $@convention(thin) (@inout X) -> () {
bb0(%0 : $*X):
%1 = load %0 : $*X
%2 = struct_extract %1 : $X, #X.y
%3 = struct_extract %2 : $Y, #Y.int
%4 = struct_extract %2 : $Y, #Y.ptr
%5 = struct_extract %2 : $Y, #Y.tup
%6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0
%7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1
%8 = struct_extract %1 : $X, #X.t
%9 = tuple_extract %8 : $(Builtin.NativeObject, Y), 0
%10 = tuple_extract %8 : $(Builtin.NativeObject, Y), 1
%11 = struct_extract %10 : $Y, #Y.int
%12 = struct_extract %10 : $Y, #Y.ptr
%13 = struct_extract %10 : $Y, #Y.tup
%14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0
%15 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 1
%16 = function_ref @mix1 : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
apply %16(%3, %4, %6, %7) : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
%17 = function_ref @mix2 : $@convention(thin) (Builtin.NativeObject, Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
apply %17(%9, %11, %12, %14, %15) : $@convention(thin) (Builtin.NativeObject, Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
%18 = tuple()
return %18 : $()
}
// CHECK-LABEL: sil @load_proj_to_gep_load_canonicalization_with_rep_no_other_use_test : $@convention(thin) (@inout X) -> ()
// CHECK-NOT: struct_extract
// CHECK-NOT: tuple_extract
// CHECK: apply {{%[0-9]+}}([[ARG1:%[0-9]+]], [[ARG2:%[0-9]+]], [[ARG3:%[0-9]+]], [[ARG4:%[0-9]+]]
// CHECK-NEXT: apply {{%[0-9]+}}([[ARG1]], [[ARG2]], [[ARG3]], [[ARG4]]
// CHECK-NOT: struct_extract
// CHECK-NOT: tuple_extract
sil @load_proj_to_gep_load_canonicalization_with_rep_no_other_use_test : $@convention(thin) (@inout X) -> () {
bb0(%0 : $*X):
%1 = load %0 : $*X
%2 = struct_extract %1 : $X, #X.y
%3 = struct_extract %2 : $Y, #Y.int
%4 = struct_extract %2 : $Y, #Y.ptr
%5 = struct_extract %2 : $Y, #Y.tup
%6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0
%7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1
%16 = function_ref @mix1 : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
apply %16(%3, %4, %6, %7) : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
%19 = struct_extract %2 : $Y, #Y.int
%20 = struct_extract %2 : $Y, #Y.ptr
%21 = struct_extract %2 : $Y, #Y.tup
%22 = tuple_extract %21 : $(Builtin.Int32, Builtin.Int1), 0
%23 = tuple_extract %21 : $(Builtin.Int32, Builtin.Int1), 1
apply %16(%19, %20, %22, %23) : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
%18 = tuple()
return %18 : $()
}
sil @disrupting_use : $@convention(thin) (Y) -> ()
// CHECK-LABEL: sil @load_proj_to_gep_load_canonicalization_no_rep_with_disrupting_use_test : $@convention(thin) (@inout X) -> ()
// CHECK: bb0
// CHECK-NEXT: struct_element_addr
// CHECK-NEXT: struct_element_addr
// CHECK-NEXT: load
// CHECK-NEXT: struct_element_addr
// CHECK-NEXT: load
// CHECK-NEXT: struct_element_addr
// CHECK-NEXT: tuple_element_addr
// CHECK-NEXT: load
// CHECK-NEXT: tuple_element_addr
// CHECK-NEXT: load
// CHECK-NEXT: struct_element_addr
// CHECK-NEXT: tuple_element_addr
// CHECK-NEXT: load
// CHECK-NEXT: tuple_element_addr
// CHECK-NEXT: load
// CHECK-NEXT: struct_extract
// CHECK-NEXT: struct_extract
// CHECK-NEXT: struct_extract
// CHECK-NEXT: tuple_extract
// CHECK-NEXT: tuple_extract
// CHECK-NEXT: function_ref
// CHECK-NEXT: function_ref
// CHECK-NEXT: apply
// CHECK-NEXT: function_ref
// CHECK-NEXT: function_ref
// CHECK-NEXT: apply
// CHECK-NEXT: function_ref
// CHECK-NEXT: function_ref
// CHECK-NEXT: apply
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @load_proj_to_gep_load_canonicalization_no_rep_with_disrupting_use_test : $@convention(thin) (@inout X) -> () {
bb0(%0 : $*X):
%1 = load %0 : $*X
%2 = struct_extract %1 : $X, #X.y
%3 = struct_extract %2 : $Y, #Y.int
%4 = struct_extract %2 : $Y, #Y.ptr
%5 = struct_extract %2 : $Y, #Y.tup
%6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0
%7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1
%8 = struct_extract %1 : $X, #X.t
%9 = tuple_extract %8 : $(Builtin.NativeObject, Y), 0
%10 = tuple_extract %8 : $(Builtin.NativeObject, Y), 1
%11 = struct_extract %10 : $Y, #Y.int
%12 = struct_extract %10 : $Y, #Y.ptr
%13 = struct_extract %10 : $Y, #Y.tup
%14 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 0
%15 = tuple_extract %13 : $(Builtin.Int32, Builtin.Int1), 1
%16 = function_ref @mix1 : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
apply %16(%3, %4, %6, %7) : $@convention(thin) (Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
%17 = function_ref @mix2 : $@convention(thin) (Builtin.NativeObject, Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
apply %17(%9, %11, %12, %14, %15) : $@convention(thin) (Builtin.NativeObject, Builtin.Int64, Builtin.NativeObject, Builtin.Int32, Builtin.Int1) -> ()
%18 = function_ref @disrupting_use : $@convention(thin) (Y) -> ()
apply %18(%10) : $@convention(thin) (Y) -> ()
%19 = tuple()
return %19 : $()
}
sil @unbalanced_closure : $@convention(thin) (@guaranteed B) -> ()
// CHECK-LABEL: sil @partial_apply_unbalanced_retain_release
sil @partial_apply_unbalanced_retain_release : $@convention(thin) (@owned B) -> () {
// CHECK: bb0
bb0(%0 : $B):
%1 = function_ref @unbalanced_closure : $@convention(thin) (@guaranteed B) -> ()
// CHECK-NOT: partial_apply
%2 = partial_apply %1(%0) : $@convention(thin) (@guaranteed B) -> ()
// Check that the arguments of the closure are released after its last use
// CHECK-NEXT: strong_release %0 : $B
strong_retain %2 : $@callee_owned () -> ()
// CHECK-NEXT: unreachable
unreachable
}
class C1 {}
class C2 : C1 {}
class C3 : C2 {}
// CHECK-LABEL: sil @upcast_upcast_merge
// CHECK: bb0
// CHECK-NEXT: upcast
// CHECK-NEXT: return
sil @upcast_upcast_merge : $@convention(thin)(C3) -> C1 {
bb0(%0 : $C3):
%1 = upcast %0 : $C3 to $C2
%2 = upcast %1 : $C2 to $C1
return %2 : $C1
}
// CHECK-LABEL: sil @dead_upcast
// CHECK: bb0
// CHECK-NEXT: strong_retain %0
// CHECK-NEXT: strong_release %0
// CHECK-NEXT: return
sil @dead_upcast : $@convention(thin) (C2) -> C2 {
bb0(%0 : $C2):
%1 = upcast %0 : $C2 to $C1
strong_retain %1 : $C1
strong_release %0 : $C2
return %0 : $C2
}
// CHECK-LABEL: sil @dead_unchecked_ref_cast
// CHECK: bb0
// CHECK-NEXT: strong_retain %0
// CHECK-NEXT: strong_release %0
// CHECK-NEXT: return
sil @dead_unchecked_ref_cast : $@convention(thin) (C1) -> C1 {
bb0(%0 : $C1):
%1 = unchecked_ref_cast %0 : $C1 to $C2
strong_retain %1 : $C2
strong_release %0 : $C1
return %0 : $C1
}
// strong_retain/strong_release don't accept an Optional<reference>.
//
// CHECK-LABEL: sil @dontOptimizeRefCastOfOptional
// CHECK: %1 = unchecked_ref_cast %0
// CHECK: strong_retain %1
// CHECK: } // end sil function 'dontOptimizeRefCastOfOptional'
sil @dontOptimizeRefCastOfOptional : $@convention(thin) (@guaranteed Optional<C1>) -> () {
bb0(%0 : $Optional<C1>):
%1 = unchecked_ref_cast %0 : $Optional<C1> to $C1
strong_retain %1 : $C1
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: sil @dead_end_cow_mutation
// CHECK: bb0
// CHECK-NEXT: strong_retain %0
// CHECK-NEXT: strong_release %0
// CHECK-NEXT: return
sil @dead_end_cow_mutation : $@convention(thin) (C1) -> C1 {
bb0(%0 : $C1):
%1 = end_cow_mutation %0 : $C1
strong_retain %1 : $C1
strong_release %0 : $C1
return %0 : $C1
}
struct XS {
var m: Int
var k: Float
init(x: XS)
}
//CHECK-LABEL: strc_from_extr
//CHECK-NOT: struct_extract
//CHECK-NOT: struct
//CHECK: return
sil @strc_from_extr : $@convention(thin) (XS, @thin XS.Type) -> XS {
bb0(%0 : $XS, %1 : $@thin XS.Type):
%2 = struct_extract %0 : $XS, #XS.m
%3 = struct_extract %0 : $XS, #XS.k
%4 = struct $XS (%2 : $Int, %3 : $Float)
return %4 : $XS
}
//CHECK-LABEL: tup_from_extr_tup
//CHECK-NOT: tuple_extract
//CHECK-NOT: tuple
//CHECK: return
sil @tup_from_extr_tup : $@convention(thin) () -> (Int, Int) {
bb0:
// function_ref x
%0 = function_ref @tup_from_extr_tup : $@convention(thin) () -> (Int, Int) // user: %1
%1 = apply %0() : $@convention(thin) () -> (Int, Int) // users: %2, %3
%2 = tuple_extract %1 : $(Int, Int), 0 // user: %4
%3 = tuple_extract %1 : $(Int, Int), 1 // user: %4
%4 = tuple (%2 : $Int, %3 : $Int) // user: %5
return %4 : $(Int, Int) // id: %5
}
// CHECK-LABEL: sil @apply_and_pa_merge
// CHECK-NOT: partial_apply
// CHECK: [[C:%.*]] = function_ref @some_closure
// CHECK: [[P:%.*]] = function_ref @print_a_number
// CHECK: [[R1:%.*]] = apply [[C]](
// CHECK: = apply [[P]]([[R1]]
// CHECK: return
sil @apply_and_pa_merge : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = function_ref @some_closure : $@convention(thin) (Int) -> Int // user: %2
%2 = partial_apply %1(%0) : $@convention(thin) (Int) -> Int // users: %4, %5, %7
%3 = function_ref @print_a_number : $@convention(thin) (Int) -> () // user: %6
strong_retain %2 : $@callee_owned () -> Int // id: %4
%5 = apply %2() : $@callee_owned () -> Int // user: %6
%6 = apply %3(%5) : $@convention(thin) (Int) -> ()
strong_release %2 : $@callee_owned () -> Int // id: %7
%8 = tuple () // user: %9
return %8 : $() // id: %9
}
sil @some_closure : $@convention(thin) (Int) -> Int
sil @print_a_number : $@convention(thin) (Int) -> ()
// CHECK-LABEL: sil @applied
sil @applied : $@convention(thin) (Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int32):
// CHECK: return
return %0 : $Builtin.Int32
}
// CHECK-LABEL: sil @combine_partial_apply_with_apply
sil @combine_partial_apply_with_apply : $@convention(thin) (Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int32):
// CHECK: [[APPLIED:%.*]] = function_ref @applied
%2 = function_ref @applied : $@convention(thin) (Builtin.Int32) -> Builtin.Int32
// CHECK: [[THICK:%.*]] = thin_to_thick_function [[APPLIED]]
%3 = thin_to_thick_function %2 : $@convention(thin) (Builtin.Int32) -> Builtin.Int32 to $@callee_owned (Builtin.Int32) -> Builtin.Int32
// CHECK: [[REABSTRACT:%.*]] = function_ref @reabstract
%4 = function_ref @reabstract : $@convention(thin) (Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> Builtin.Int32) -> @out Builtin.Int32
// CHECK-NOT: partial_apply
%5 = partial_apply %4(%3) : $@convention(thin) (Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> Builtin.Int32) -> @out Builtin.Int32
// CHECK: [[TMP:%.*]] = alloc_stack $Builtin.Int32
%6 = alloc_stack $Builtin.Int32
// CHECK-NOT: strong_retain
strong_retain %5 : $@callee_owned (Builtin.Int32) -> @out Builtin.Int32
// CHECK: apply [[REABSTRACT]]([[TMP]], %0, [[THICK]])
%8 = apply %5(%6, %0) : $@callee_owned (Builtin.Int32) -> @out Builtin.Int32
// CHECK-NOT: strong_release
strong_release %5 : $@callee_owned (Builtin.Int32) -> @out Builtin.Int32
// CHECK-NOT: tuple
%10 = tuple ()
// CHECK: [[RESULT:%.*]] = load [[TMP]]
%11 = load %6 : $*Builtin.Int32
// CHECK: dealloc_stack [[TMP]]
dealloc_stack %6 : $*Builtin.Int32
// CHECK: return [[RESULT]]
return %11 : $Builtin.Int32
}
// CHECK-LABEL: sil shared [transparent] @reabstract
sil shared [transparent] @reabstract : $@convention(thin) (Builtin.Int32, @owned @callee_owned (Builtin.Int32) -> Builtin.Int32) -> @out Builtin.Int32 {
bb0(%0 : $*Builtin.Int32, %1 : $Builtin.Int32, %2 : $@callee_owned (Builtin.Int32) -> Builtin.Int32):
%3 = apply %2(%1) : $@callee_owned (Builtin.Int32) -> Builtin.Int32
store %3 to %0 : $*Builtin.Int32
%5 = tuple ()
// CHECK: return
return %5 : $()
}
// CHECK-LABEL: sil @generic_is_objc
sil @generic_is_objc : $@convention(thin) <T> (@in T) -> Int8 {
bb0(%0 : $*T):
// CHECK: [[TYPE:%[a-zA-Z0-9]+]] = metatype $@thick [[ARCH:[a-zA-Z]+]].Type
%1 = metatype $@thick T.Type // user: %3
// CHECK: builtin "canBeClass"<[[ARCH]]>([[TYPE]] : $@thick [[ARCH]].Type)
%3 = builtin "canBeClass"<T>(%1 : $@thick T.Type) : $Builtin.Int8 // user: %4
%4 = struct $Int8 (%3 : $Builtin.Int8) // user: %6
destroy_addr %0 : $*T // id: %5
return %4 : $Int8 // id: %6
}
// CHECK-LABEL: sil @is_int_objc
sil @is_int_objc : $@convention(thin) (Int) -> Int8 {
bb0(%0 : $Int):
%1 = metatype $@thick Int.Type // user: %3
// CHECK-NOT: builtin "canBeClass"
// CHECK-NOT: apply
%3 = builtin "canBeClass"<Int>(%1 : $@thick Int.Type) : $Builtin.Int8 // user: %4
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 0
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
%4 = struct $Int8 (%3 : $Builtin.Int8) // user: %5
// CHECK: return [[RESULT]] : $Int8
return %4 : $Int8 // id: %5
}
// An archetype with a trivial layout constraint can never be a class.
// CHECK-LABEL: sil @is_trivial_layout_constraint_class
sil @is_trivial_layout_constraint_class : $@convention(thin) <T where T: _Trivial> (@in T) -> Int8 {
bb0(%0 : $*T):
%1 = metatype $@thick T.Type
// CHECK-NOT: builtin "canBeClass"
// CHECK-NOT: apply
%3 = builtin "canBeClass"<T>(%1 : $@thick T.Type) : $Builtin.Int8
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 0
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
%4 = struct $Int8 (%3 : $Builtin.Int8)
// CHECK: return [[RESULT]] : $Int8
return %4 : $Int8
}
// An archetype with a _Class layout constraint is always a class.
// CHECK-LABEL: sil @is_class_layout_constraint_class
sil @is_class_layout_constraint_class : $@convention(thin) <T where T: _Class> (@in T) -> Int8 {
bb0(%0 : $*T):
%1 = metatype $@thick T.Type
// CHECK-NOT: builtin "canBeClass"
// CHECK-NOT: apply
%3 = builtin "canBeClass"<T>(%1 : $@thick T.Type) : $Builtin.Int8
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 1
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
%4 = struct $Int8 (%3 : $Builtin.Int8)
// CHECK: return [[RESULT]] : $Int8
return %4 : $Int8
}
// An archetype with a _NativeClass layout constraint is always a class.
// CHECK-LABEL: sil @is_native_class_layout_constraint_class
sil @is_native_class_layout_constraint_class : $@convention(thin) <T where T: _NativeClass> (@in T) -> Int8 {
bb0(%0 : $*T):
%1 = metatype $@thick T.Type
// CHECK-NOT: builtin "canBeClass"
// CHECK-NOT: apply
%3 = builtin "canBeClass"<T>(%1 : $@thick T.Type) : $Builtin.Int8
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 1
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
%4 = struct $Int8 (%3 : $Builtin.Int8)
// CHECK: return [[RESULT]] : $Int8
return %4 : $Int8
}
@objc class MyClass {
}
// CHECK-LABEL: sil @is_objc_class_objc
sil @is_objc_class_objc : $@convention(thin) (@owned MyClass) -> Int8 {
bb0(%0 : $MyClass):
%1 = metatype $@thick MyClass.Type // user: %3
// CHECK-NOT: builtin "canBeClass"
%3 = builtin "canBeClass"<MyClass>(%1 : $@thick MyClass.Type) : $Builtin.Int8 // user: %4
// CHECK: [[LITERAL:%[a-zA-Z0-9]+]] = integer_literal $Builtin.Int8, 1
// CHECK: [[RESULT:%[a-zA-Z0-9]+]] = struct $Int8 ([[LITERAL]] : $Builtin.Int8)
%4 = struct $Int8 (%3 : $Builtin.Int8) // user: %6
strong_release %0 : $MyClass // id: %5
// CHECK: return [[RESULT]] : $Int8
return %4 : $Int8 // id: %6
}
// CHECK-LABEL: sil @constant_expect_hint
// CHECK: bb0:
// CHECK-NEXT: [[INT1:%[0-9]+]] = integer_literal $Builtin.Int1, 0
// CHECK-NEXT: [[INT2:%[0-9]+]] = integer_literal $Builtin.Int32, 5
// CHECK-NEXT: [[INT3:%[0-9]+]] = integer_literal $Builtin.Int64, 32
// CHECK-NEXT: [[TUPLE:%[0-9]+]] = tuple ([[INT1]] : $Builtin.Int1, [[INT2]] : $Builtin.Int32, [[INT3]] : $Builtin.Int64)
// CHECK-NEXT: return [[TUPLE]]
// CHECK-NEXT: }
sil @constant_expect_hint : $@convention(thin) () -> (Builtin.Int1, Builtin.Int32, Builtin.Int64) {
bb0:
%0 = integer_literal $Builtin.Int1, 0
%1 = integer_literal $Builtin.Int32, 5
%2 = integer_literal $Builtin.Int64, 32
%3 = integer_literal $Builtin.Int1, 1
%4 = integer_literal $Builtin.Int32, 400
%5 = integer_literal $Builtin.Int64, 5000
%9 = builtin "int_expect_Int1"(%0 : $Builtin.Int1, %3 : $Builtin.Int1) : $Builtin.Int1
%10 = builtin "int_expect_Int32"(%1 : $Builtin.Int32, %4 : $Builtin.Int32) : $Builtin.Int32
%11 = builtin "int_expect_Int64"(%2 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int64
%12 = tuple (%9 : $Builtin.Int1, %10 : $Builtin.Int32, %11 : $Builtin.Int64)
return %12 : $(Builtin.Int1, Builtin.Int32, Builtin.Int64)
}
// CHECK-LABEL: @_TF6expect3fooFSiSi
// CHECK: bb0
// CHECK-NEXT: cond_br %0, bb2, bb1
sil @_TF6expect3fooFSiSi : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%5 = integer_literal $Builtin.Int1, -1
%9 = builtin "xor_Int1"(%0 : $Builtin.Int1, %5 : $Builtin.Int1) : $Builtin.Int1
cond_br %9, bb1, bb2 // id: %10
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
// CHECK-LABEL: sil @enum_promotion_of_concrete_types
// CHECK: bb0([[INT_PTR:%[0-9]+]]
// CHECK-NEXT: [[ALLOCA1:%[0-9]+]] = alloc_stack $FakeOptional<Builtin.Int1>
// CHECK-NEXT: [[ENUM1:%[0-9]+]] = enum $FakeOptional<Builtin.Int1>, #FakeOptional.none!enumelt
// CHECK-NEXT: store [[ENUM1]] to [[ALLOCA1]]
// CHECK-NEXT: [[ALLOCA2:%[0-9]+]] = alloc_stack $FakeOptional<Builtin.Int1>
// CHECK-NEXT: [[INT:%[0-9]+]] = load [[INT_PTR]] : $*Builtin.Int1
// CHECK-NEXT: [[ENUM2:%[0-9]+]] = enum $FakeOptional<Builtin.Int1>, #FakeOptional.some!enumelt, [[INT]] : $Builtin.Int1
// CHECK-NEXT: store [[ENUM2]] to [[ALLOCA2]] : $*FakeOptional<Builtin.Int1>
// CHECK-NEXT: [[RESULT1:%[0-9]+]] = load [[ALLOCA1]]
// CHECK-NEXT: [[RESULT2:%[0-9]+]] = load [[ALLOCA2]]
// CHECK-NEXT: [[RESULT:%[0-9]+]] = tuple ([[RESULT1]] : $FakeOptional<Builtin.Int1>, [[RESULT2]] : $FakeOptional<Builtin.Int1>)
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: return [[RESULT]]
sil @enum_promotion_of_concrete_types : $@convention(thin) (@in Builtin.Int1) -> (FakeOptional<Builtin.Int1>, FakeOptional<Builtin.Int1>) {
bb0(%0 : $*Builtin.Int1):
%1 = alloc_stack $FakeOptional<Builtin.Int1>
inject_enum_addr %1 : $*FakeOptional<Builtin.Int1>, #FakeOptional.none!enumelt
%2 = integer_literal $Builtin.Int1, 1
%3 = alloc_stack $FakeOptional<Builtin.Int1>
%4 = init_enum_data_addr %3 : $*FakeOptional<Builtin.Int1>, #FakeOptional.some!enumelt
%5 = load %0 : $*Builtin.Int1
store %5 to %4 : $*Builtin.Int1
inject_enum_addr %3 : $*FakeOptional<Builtin.Int1>, #FakeOptional.some!enumelt
%6 = load %1 : $*FakeOptional<Builtin.Int1>
%7 = load %3 : $*FakeOptional<Builtin.Int1>
%8 = tuple(%6 : $FakeOptional<Builtin.Int1>, %7 : $FakeOptional<Builtin.Int1>)
dealloc_stack %3 : $*FakeOptional<Builtin.Int1>
dealloc_stack %1 : $*FakeOptional<Builtin.Int1>
return %8 : $(FakeOptional<Builtin.Int1>, FakeOptional<Builtin.Int1>)
}
// CHECK-LABEL: sil @enum_promotion_case2
// CHECK: bb0([[B_PTR:%[0-9]+]]
// CHECK-NEXT: [[ALLOCA:%[0-9]+]] = alloc_stack $FakeOptional<B>
// CHECK-NEXT: strong_retain [[B_PTR]]
// CHECK-NEXT: [[ENUM:%[0-9]+]] = enum $FakeOptional<B>, #FakeOptional.some!enumelt, [[B_PTR]] : $B
// CHECK-NEXT: store [[ENUM]] to [[ALLOCA]] : $*FakeOptional<B>
// CHECK-NEXT: [[RESULT:%[0-9]+]] = load [[ALLOCA]]
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: strong_release [[B_PTR]]
// CHECK-NEXT: return [[RESULT]]
sil @enum_promotion_case2 : $@convention(thin) (@owned B) -> @owned FakeOptional<B> {
bb0(%0 : $B):
%2 = alloc_stack $FakeOptional<B>
%3 = init_enum_data_addr %2 : $*FakeOptional<B>, #FakeOptional.some!enumelt
store %0 to %3 : $*B
// This instruction between the store and the inject_enum_addr should not prevent
// the optimization.
strong_retain %0 : $B
inject_enum_addr %2 : $*FakeOptional<B>, #FakeOptional.some!enumelt
%7 = load %2 : $*FakeOptional<B>
dealloc_stack %2 : $*FakeOptional<B>
strong_release %0 : $B
return %7 : $FakeOptional<B>
}
// (ref-to-object-pointer-inst (object-pointer-to-ref-inst x) typeof(x)) -> x
// CHECK-LABEL: sil @unchecked_ref_cast_round_trip : $@convention(thin) (B) -> B {
// CHECK: bb0
// CHECK-NEXT: return
sil @unchecked_ref_cast_round_trip : $@convention(thin) (B) -> B {
bb0(%0 : $B):
%1 = unchecked_ref_cast %0 : $B to $Builtin.NativeObject
%2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $B
return %2 : $B
}
// (upcast X2->X (ref-to-object-pointer-inst (object-pointer-to-ref-inst x) typeof(x))) -> x
// CHECK-LABEL: sil @upcast_unchecked_ref_cast_round_trip : $@convention(thin) (E) -> E {
// CHECK: bb0
// CHECK-NEXT: return
sil @upcast_unchecked_ref_cast_round_trip : $@convention(thin) (E) -> E {
bb0(%0 : $E):
%1 = upcast %0 : $E to $B
%2 = unchecked_ref_cast %1 : $B to $Builtin.NativeObject
%3 = unchecked_ref_cast %2 : $Builtin.NativeObject to $E
return %3 : $E
}
// CHECK-LABEL: sil @unchecked_enum_data_of_enum : $@convention(thin) () -> Builtin.Int1 {
// CHECK: bb0
// CHECK-NEXT: integer_literal
// CHECK-NEXT: return
sil @unchecked_enum_data_of_enum : $@convention(thin) () -> Builtin.Int1 {
bb0:
%0 = integer_literal $Builtin.Int1, 0
%1 = enum $FakeOptional<Builtin.Int1>, #FakeOptional.some!enumelt, %0 : $Builtin.Int1
%2 = unchecked_enum_data %1 : $FakeOptional<Builtin.Int1>, #FakeOptional.some!enumelt
return %2 : $Builtin.Int1
}
// CHECK-LABEL: sil @unchecked_addr_cast_formation : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
// CHECK: bb0([[INPUT_PTR:%[0-9]+]] : $*Builtin.NativeObject):
// CHECK-NEXT: [[ADDR_CAST:%[0-9]+]] = unchecked_addr_cast [[INPUT_PTR]] : $*Builtin.NativeObject to $*Builtin.Word
// CHECK-NEXT: [[RETURN_VALUE:%[0-9]+]] = load [[ADDR_CAST]] : $*Builtin.Word
// CHECK-NEXT: return [[RETURN_VALUE]]
sil @unchecked_addr_cast_formation : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
bb0(%0 : $*Builtin.NativeObject):
%1 = address_to_pointer %0 : $*Builtin.NativeObject to $Builtin.RawPointer
%2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Builtin.Word
%3 = load %2 : $*Builtin.Word
return %3 : $Builtin.Word
}
// CHECK-LABEL: sil @unchecked_addr_cast_forwarding : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
// CHECK: bb0([[INPUT_PTR:%[0-9]+]] : $*Builtin.NativeObject):
// CHECK-NEXT: [[ADDR_CAST:%[0-9]+]] = unchecked_addr_cast [[INPUT_PTR]] : $*Builtin.NativeObject to $*Builtin.Word
// CHECK-NEXT: debug_value [[ADDR_CAST]]
// CHECK-NEXT: [[RETURN_VALUE:%[0-9]+]] = load [[ADDR_CAST]] : $*Builtin.Word
// CHECK-NEXT: return [[RETURN_VALUE]]
sil @unchecked_addr_cast_forwarding : $@convention(thin) (@inout Builtin.NativeObject) -> Builtin.Word {
bb0(%0 : $*Builtin.NativeObject):
%1 = unchecked_addr_cast %0 : $*Builtin.NativeObject to $*Builtin.RawPointer
%2 = unchecked_addr_cast %1 : $*Builtin.RawPointer to $*Builtin.Word
debug_value %2 : $*Builtin.Word // should not prevent the optimization
%3 = load %2 : $*Builtin.Word
return %3 : $Builtin.Word
}
class F : E {}
// CHECK-LABEL: sil @unchecked_ref_cast_forwarding : $@convention(thin) (B) -> F {
// CHECK: bb0([[INPUT_REF:%[0-9]+]] : $B):
// CHECK-NEXT: [[CAST_REF:%[0-9]+]] = unchecked_ref_cast [[INPUT_REF]] : $B to $F
// CHECK-NEXT: return
sil @unchecked_ref_cast_forwarding : $@convention(thin) (B) -> F {
bb0(%0 : $B):
%1 = unchecked_ref_cast %0 : $B to $E
%2 = unchecked_ref_cast %1 : $E to $F
return %2 : $F
}
// CHECK-LABEL: sil @unchecked_ref_cast_formation : $@convention(thin) (B) -> F {
// CHECK: bb0([[INPUT_REF:%[0-9]+]] : $B):
// CHECK-NEXT: [[CAST_REF:%[0-9]+]] = unchecked_ref_cast [[INPUT_REF]] : $B to $F
// CHECK-NEXT: return
sil @unchecked_ref_cast_formation : $@convention(thin) (B) -> F {
bb0(%0 : $B):
%1 = ref_to_raw_pointer %0 : $B to $Builtin.RawPointer
%2 = raw_pointer_to_ref %1 : $Builtin.RawPointer to $F
return %2 : $F
}
// CHECK-LABEL: sil @upcast_unchecked_ref_cast_roundtrip : $@convention(thin) (B) -> B {
// CHECK: bb0(
// CHECK-NEXT: return
sil @upcast_unchecked_ref_cast_roundtrip : $@convention(thin) (B) -> B {
bb0(%0 : $B):
%1 = unchecked_ref_cast %0 : $B to $E
%2 = upcast %1 : $E to $B
return %2 : $B
}
// CHECK-LABEL: sil @unchecked_ref_cast_upcast_roundtrip : $@convention(thin) (E) -> E {
// CHECK: bb0
// CHECK-NEXT: return
sil @unchecked_ref_cast_upcast_roundtrip : $@convention(thin) (E) -> E {
bb0(%0 : $E):
%1 = upcast %0 : $E to $B
%2 = unchecked_ref_cast %1 : $B to $E
return %2 : $E
}
// CHECK-LABEL: sil @unchecked_ref_cast_open_existential_ref : $@convention(thin) (AnyObject) -> AnyObject {
// CHECK: bb0(%0 : $AnyObject):
// CHECK-NEXT: return %0 : $AnyObject
sil @unchecked_ref_cast_open_existential_ref : $@convention(thin) (AnyObject) -> AnyObject {
bb0(%0 : $AnyObject):
%1 = open_existential_ref %0 : $AnyObject to $@opened("F06A1466-8414-11E5-81D5-685B35C48C83", AnyObject) Self
%2 = unchecked_ref_cast %1 : $@opened("F06A1466-8414-11E5-81D5-685B35C48C83", AnyObject) Self to $AnyObject
return %2 : $AnyObject
}
// CHECK-LABEL: sil @unchecked_ref_cast_upcast_combine : $@convention(thin) (E) -> Builtin.NativeObject {
// CHECK: bb0
// CHECK-NEXT: unchecked_ref_cast
// CHECK-NEXT: return
sil @unchecked_ref_cast_upcast_combine : $@convention(thin) (E) -> Builtin.NativeObject {
bb0(%0 : $E):
%1 = upcast %0 : $E to $B
%2 = unchecked_ref_cast %1 : $B to $Builtin.NativeObject
return %2 : $Builtin.NativeObject
}
// CHECK-LABEL: sil @unchecked_take_enum_data_addr_promotion : $@convention(thin) (@inout FakeOptional<B>) -> B {
// CHECK: bb0(%0 : $*FakeOptional<B>):
// CHECK-NEXT: load
// CHECK-NEXT: switch_enum
// CHECK: bb1:
// CHECK-NEXT: load
// CHECK-NEXT: unchecked_enum_data
// CHECK-NEXT: return
sil @unchecked_take_enum_data_addr_promotion : $@convention(thin) (@inout FakeOptional<B>) -> B {
bb0(%0 : $*FakeOptional<B>):
switch_enum_addr %0 : $*FakeOptional<B>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
%2 = unchecked_take_enum_data_addr %0 : $*FakeOptional<B>, #FakeOptional.some!enumelt
debug_value %2 : $*B // should not prevent the optimization
%3 = load %2 : $*B
return %3 : $B
bb2:
unreachable
}
sil @weird_function : $@convention(thin) (@inout E, E, Builtin.Int1) -> ()
// CHECK-LABEL: sil @convert_function_simplification : $@convention(thin) (@inout B, B, Builtin.Int1) -> () {
// CHECK: bb0([[ADDR:%[0-9]+]] : $*B, [[REF:%[0-9]+]] : $B, [[NA:%[0-9]+]] : $Builtin.Int1):
// CHECK-NEXT: function_ref weird_function
// CHECK-NEXT: [[FUN:%[0-9]+]] = function_ref @weird_function : $@convention(thin) (@inout E, E, Builtin.Int1) -> ()
// CHECK-NEXT: [[ADDR_CAST:%[0-9]+]] = unchecked_addr_cast %0 : $*B to $*E
// CHECK-NEXT: [[REF_CAST:%[0-9]+]] = unchecked_ref_cast %1 : $B to $E
// CHECK-NEXT: apply [[FUN]]([[ADDR_CAST]], [[REF_CAST]], [[NA]])
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @convert_function_simplification : $@convention(thin) (@inout B, B, Builtin.Int1) -> () {
bb0(%0 : $*B, %1 : $B, %2 : $Builtin.Int1):
%3 = function_ref @weird_function : $@convention(thin) (@inout E, E, Builtin.Int1) -> ()
%4 = convert_function %3 : $@convention(thin) (@inout E, E, Builtin.Int1) -> () to $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
%5 = apply %4(%0, %1, %2) : $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
%6 = tuple()
return %6 : $()
}
// Check that convert_function simplifications are not applied in certain cases.
@objc class MyNSObj { }
class AnotherClass : MyNSObj { }
sil @MyNSObj_self : $@convention(method) (@guaranteed MyNSObj) -> @owned MyNSObj
sil shared [transparent] [serialized] [reabstraction_thunk] @reabstraction_thunk1 : $@convention(thin) (@in (), @owned @callee_owned () -> @owned AnotherClass) -> @out AnotherClass {
bb0(%0 : $*AnotherClass, %1 : $*(), %2 : $@callee_owned () -> @owned AnotherClass):
%3 = apply %2() : $@callee_owned () -> @owned AnotherClass
store %3 to %0 : $*AnotherClass
%5 = tuple ()
return %5 : $()
}
// @nonobjc curry thunk of MyNSObj.self()
sil shared [serialized] [thunk] @curry_thunk_for_MyNSObj_self : $@convention(thin) (@owned MyNSObj) -> @owned @callee_owned () -> @owned MyNSObj {
bb0(%0 : $MyNSObj):
// function_ref @nonobjc MyNSObj.self()
%1 = function_ref @MyNSObj_self : $@convention(method) (@guaranteed MyNSObj) -> @owned MyNSObj
%2 = partial_apply %1(%0) : $@convention(method) (@guaranteed MyNSObj) -> @owned MyNSObj
return %2 : $@callee_owned () -> @owned MyNSObj
}
// Check that convert_function is eliminated if the result type of the converted function is different from the apply result type.
// CHECK-LABEL: sil {{.*}} @peephole_convert_function_result_change : $@convention(thin) (@in AnotherClass) -> @out @callee_owned (@in ()) -> @out AnotherClass {
// CHECK: [[F1:%[0-9]+]] = function_ref @curry_thunk_for_MyNSObj_self
// CHECK: [[APPLY:%[0-9]+]] = apply [[F1]]
// CHECK: [[CONV_RESULT:%[0-9]+]] = convert_function [[APPLY]]
// CHECK: [[FUN:%[0-9]+]] = function_ref @reabstraction_thunk1
// CHECK: [[CF:%[0-9]+]] = partial_apply [[FUN]]([[CONV_RESULT]])
// CHECK: // end sil function 'peephole_convert_function_result_change'
sil shared [transparent] [reabstraction_thunk] @peephole_convert_function_result_change : $@convention(thin) (@in AnotherClass) -> @out @callee_owned (@in ()) -> @out AnotherClass {
bb0(%0 : $*@callee_owned (@in ()) -> @out AnotherClass, %1 : $*AnotherClass):
// function_ref @nonobjc curry thunk of MyNSObj.self()
%2 = function_ref @curry_thunk_for_MyNSObj_self : $@convention(thin) (@owned MyNSObj) -> @owned @callee_owned () -> @owned MyNSObj
%3 = convert_function %2 : $@convention(thin) (@owned MyNSObj) -> @owned @callee_owned () -> @owned MyNSObj to $@convention(thin) (@owned AnotherClass) -> @owned @callee_owned () -> @owned AnotherClass
%5 = load %1 : $*AnotherClass
%6 = apply %3(%5) : $@convention(thin) (@owned AnotherClass) -> @owned @callee_owned () -> @owned AnotherClass
// function_ref thunk for @callee_owned () -> (@owned AnotherClass)
%7 = function_ref @reabstraction_thunk1 : $@convention(thin) (@in (), @owned @callee_owned () -> @owned AnotherClass) -> @out AnotherClass
%8 = partial_apply %7(%6) : $@convention(thin) (@in (), @owned @callee_owned () -> @owned AnotherClass) -> @out AnotherClass
store %8 to %0 : $*@callee_owned (@in ()) -> @out AnotherClass
%10 = tuple ()
return %10 : $()
} // end sil function 'peephole_convert_function_result_change'
sil @convertible_result_with_error : $@convention(thin) () -> (@owned AnotherClass, @error Error)
// TODO
sil @peephole_convert_function_result_change_with_error : $@convention(thin) () -> () {
entry:
%f = function_ref @convertible_result_with_error : $@convention(thin) () -> (@owned AnotherClass, @error Error)
%c = convert_function %f : $@convention(thin) () -> (@owned AnotherClass, @error Error) to $@convention(thin) () -> (@owned MyNSObj, @error Error)
try_apply %c() : $@convention(thin) () -> (@owned MyNSObj, @error Error), normal success, error failure
success(%r : $MyNSObj):
strong_release %r : $MyNSObj
br exit
failure(%e : $Error):
strong_release %e : $Error
br exit
exit:
return undef : $()
}
sil @convertible_indirect_result : $@convention(thin) (@guaranteed MyNSObj) -> @out AnotherClass
// CHECK-LABEL: sil @peephole_convert_function_indirect_result :
// CHECK: bb0([[A:%.*]] : $AnotherClass):
// CHECK: [[F:%.*]] = function_ref @convertible_indirect_result :
// CHECK: [[B:%.*]] = alloc_stack $MyNSObj
// CHECK: [[B_CONV:%.*]] = unchecked_addr_cast [[B]]
// CHECK: [[A_CONV:%.*]] = upcast [[A]]
// CHECK: apply [[F]]([[B_CONV]], [[A_CONV]])
sil @peephole_convert_function_indirect_result : $@convention(thin) (@guaranteed AnotherClass) -> @owned MyNSObj {
entry(%a : $AnotherClass):
%f = function_ref @convertible_indirect_result : $@convention(thin) (@guaranteed MyNSObj) -> @out AnotherClass
%c = convert_function %f : $@convention(thin) (@guaranteed MyNSObj) -> @out AnotherClass to $@convention(thin) (@guaranteed AnotherClass) -> @out MyNSObj
%b = alloc_stack $*MyNSObj
apply %c(%b, %a) : $@convention(thin) (@guaranteed AnotherClass) -> @out MyNSObj
%r = load %b : $*MyNSObj
dealloc_stack %b : $*MyNSObj
return %r : $MyNSObj
}
sil @createMyInt : $@convention(thin) (Builtin.Int32) -> @out MyInt
// CHECK-LABEL: sil @convert_function_of_closure :
// CHECK: [[F:%.*]] = function_ref @createMyInt
// CHECK: [[S:%.*]] = alloc_stack $MyInt
// CHECK: apply [[F]]([[S]], %0)
// CHECK-NOT: strong_release
// CHECK: } // end sil function 'convert_function_of_closure'
sil @convert_function_of_closure : $@convention(thin) (Builtin.Int32) -> () {
bb0(%0 : $Builtin.Int32):
%1 = function_ref @createMyInt : $@convention(thin) (Builtin.Int32) -> @out MyInt
%2 = partial_apply [callee_guaranteed] %1(%0) : $@convention(thin) (Builtin.Int32) -> @out MyInt
%3 = convert_function %2 : $@callee_guaranteed () -> @out MyInt to $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <MyInt>
%4 = convert_escape_to_noescape %3 : $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <MyInt> to $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <MyInt>
%5 = alloc_stack $MyInt
%6 = apply %4(%5) : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <MyInt>
dealloc_stack %5 : $*MyInt
strong_release %2 : $@callee_guaranteed () -> @out MyInt
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: sil @upcast_formation : $@convention(thin) (@inout E, E, @inout B) -> B {
// CHECK: bb0
// CHECK-NEXT: upcast
// CHECK-NEXT: load
// CHECK-NEXT: upcast
// CHECK-NEXT: store
// CHECK-NEXT: return
sil @upcast_formation : $@convention(thin) (@inout E, E, @inout B) -> (B) {
bb0(%0 : $*E, %1 : $E, %2 : $*B):
%3 = unchecked_addr_cast %0 : $*E to $*B
%4 = unchecked_ref_cast %1 : $E to $B
%5 = load %3 : $*B
store %5 to %2 : $*B
return %4 : $B
}
// CHECK-LABEL: sil @dont_form_upcast_when_casts_are_identity : $@convention(thin) (@inout E, E, @inout E) -> E {
// CHECK: bb0
// CHECK-NEXT: load
// CHECK-NEXT: store
// CHECK-NEXT: return
sil @dont_form_upcast_when_casts_are_identity : $@convention(thin) (@inout E, E, @inout E) -> E {
bb0(%0 : $*E, %1 : $E, %2 : $*E):
%3 = unchecked_addr_cast %0 : $*E to $*E
%4 = unchecked_ref_cast %1 : $E to $E
%5 = load %3 : $*E
store %5 to %2 : $*E
return %4 : $E
}
// CHECK-LABEL: sil @indexrawpointer_to_indexaddr : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> Int8 {
// CHECK: bb0
// CHECK-NEXT: pointer_to_address
// CHECK-NEXT: index_addr
// CHECK-NEXT: load
// CHECK-NEXT: return
sil @indexrawpointer_to_indexaddr : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> Int8 {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%3 = metatype $@thick Int8.Type
%4 = builtin "strideof"<Int8>(%3 : $@thick Int8.Type) : $Builtin.Word
%6 = integer_literal $Builtin.Int1, -1
%7 = builtin "smul_with_overflow_Word"(%4 : $Builtin.Word, %1 : $Builtin.Word, %6 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
%8 = tuple_extract %7 : $(Builtin.Word, Builtin.Int1), 0
%9 = index_raw_pointer %0 : $Builtin.RawPointer, %8 : $Builtin.Word
%10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*Int8
%11 = load %10 : $*Int8
return %11 : $Int8
}
// CHECK-LABEL: sil @indexrawpointer_to_indexaddr_strideof : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> Int8 {
// CHECK: bb0
// CHECK-NEXT: pointer_to_address
// CHECK-NEXT: index_addr
// CHECK-NEXT: load
// CHECK-NEXT: return
sil @indexrawpointer_to_indexaddr_strideof : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> Int8 {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%3 = metatype $@thick Int8.Type
%4 = builtin "strideof"<Int8>(%3 : $@thick Int8.Type) : $Builtin.Word
%6 = integer_literal $Builtin.Int1, -1
%7 = builtin "smul_with_overflow_Word"(%4 : $Builtin.Word, %1 : $Builtin.Word, %6 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
%8 = tuple_extract %7 : $(Builtin.Word, Builtin.Int1), 0
%9 = index_raw_pointer %0 : $Builtin.RawPointer, %8 : $Builtin.Word
%10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*Int8
%11 = load %10 : $*Int8
return %11 : $Int8
}
// CHECK-LABEL: sil @indexrawpointer_to_indexaddr_mismatched_metatype : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> Int32 {
// CHECK-NOT: index_addr
sil @indexrawpointer_to_indexaddr_mismatched_metatype : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> Int32 {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%3 = metatype $@thick Int8.Type
%4 = builtin "strideof"<Int8>(%3 : $@thick Int8.Type) : $Builtin.Word
%6 = integer_literal $Builtin.Int1, -1
%7 = builtin "smul_with_overflow_Word"(%4 : $Builtin.Word, %1 : $Builtin.Word, %6 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
%8 = tuple_extract %7 : $(Builtin.Word, Builtin.Int1), 0
%9 = index_raw_pointer %0 : $Builtin.RawPointer, %8 : $Builtin.Word
%10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*Int32
%11 = load %10 : $*Int32
return %11 : $Int32
}
// CHECK-LABEL: sil @indexrawpointer_to_indexaddr_with_casts : $@convention(thin) (Builtin.RawPointer, Builtin.Int64) -> Int32
// CHECK: pointer_to_address
// CHECK-NEXT: builtin "truncOrBitCast_Int64_Word"
// CHECK-NEXT: index_addr
// CHECK-NEXT: load
// CHECK-NEXT: return
sil @indexrawpointer_to_indexaddr_with_casts : $@convention(thin) (Builtin.RawPointer, Builtin.Int64) -> Int32 {
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.Int64):
%2 = integer_literal $Builtin.Int1, -1
%3 = metatype $@thick Int32.Type
%4 = builtin "strideof"<Int32>(%3 : $@thick Int32.Type) : $Builtin.Word
%5 = builtin "zextOrBitCast_Word_Int64"(%4 : $Builtin.Word) : $Builtin.Int64
%6 = builtin "smul_with_overflow_Int64"(%1 : $Builtin.Int64, %5 : $Builtin.Int64, %2 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%7 = tuple_extract %6 : $(Builtin.Int64, Builtin.Int1), 0
%8 = builtin "truncOrBitCast_Int64_Word"(%7 : $Builtin.Int64) : $Builtin.Word
%9 = index_raw_pointer %0 : $Builtin.RawPointer, %8 : $Builtin.Word
%10 = pointer_to_address %9 : $Builtin.RawPointer to [strict] $*Int32
%11 = load %10 : $*Int32
return %11 : $Int32
}
// CHECK-LABEL: sil @max_int_ult : $@convention(thin) (Builtin.Int32) -> Builtin.Int32
// CHECK-NOT: builtin "cmp_ult_Int32"
// CHECK: integer_literal $Builtin.Int1, 0
sil @max_int_ult : $@convention(thin) (Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int32):
%minint = integer_literal $Builtin.Int32, -1
%cmp = builtin "cmp_ult_Int32"(%minint : $Builtin.Int32, %0 : $Builtin.Int32) : $Builtin.Int1
cond_br %cmp, bb1, bb2
bb1:
%badret = integer_literal $Builtin.Int32, 0
br bb3(%badret : $Builtin.Int32)
bb2:
%goodret = integer_literal $Builtin.Int32, 1
br bb3(%goodret : $Builtin.Int32)
bb3(%ret : $Builtin.Int32):
return %ret : $Builtin.Int32
}
// CHECK-LABEL: sil @max_int_ule : $@convention(thin) (Builtin.Int32) -> Builtin.Int32
// CHECK: builtin "cmp_ule_Int32"
// CHECK-NOT: integer_literal $Builtin.Int1, 0
sil @max_int_ule : $@convention(thin) (Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int32):
%minint = integer_literal $Builtin.Int32, -1
%cmp = builtin "cmp_ule_Int32"(%minint : $Builtin.Int32, %0 : $Builtin.Int32) : $Builtin.Int1
cond_br %cmp, bb1, bb2
bb1:
%badret = integer_literal $Builtin.Int32, 0
br bb3(%badret : $Builtin.Int32)
bb2:
%goodret = integer_literal $Builtin.Int32, 1
br bb3(%goodret : $Builtin.Int32)
bb3(%ret : $Builtin.Int32):
return %ret : $Builtin.Int32
}
// CHECK-LABEL: sil @trunc_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int32
// CHECK-NOT: builtin "zextOrBitCast_Int16_Int64"
// CHECK-NOT: builtin "truncOrBitCast_Int64_Int32"
// CHECK: builtin "zextOrBitCast_Int16_Int32"
// CHECK-NEXT: return
sil @trunc_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int16):
%zext = builtin "zextOrBitCast_Int16_Int64"(%0 : $Builtin.Int16) : $Builtin.Int64
%trunc = builtin "truncOrBitCast_Int64_Int32"(%zext : $Builtin.Int64) : $Builtin.Int32
return %trunc : $Builtin.Int32
}
// CHECK-LABEL: sil @zext_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int64
// CHECK-NOT: builtin "zextOrBitCast_Int16_Int32"
// CHECK-NOT: builtin "zextOrBitCast_Int32_Int64"
// CHECK: builtin "zextOrBitCast_Int16_Int64"
// CHECK-NEXT: return
sil @zext_of_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int64 {
bb0(%0 : $Builtin.Int16):
%zext1 = builtin "zextOrBitCast_Int16_Int32"(%0 : $Builtin.Int16) : $Builtin.Int32
%zext2 = builtin "zextOrBitCast_Int32_Int64"(%zext1 : $Builtin.Int32) : $Builtin.Int64
return %zext2 : $Builtin.Int64
}
// CHECK-LABEL: sil @trunc_of_zext_then_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int16
// CHECK-NOT: builtin "zextOrBitCast_Int16_Int64"
// CHECK-NOT: builtin "truncOrBitCast_Int64_Int32"
// CHECK-NOT: builtin "zextOrBitCast_Int32_Int64"
// CHECK-NOT: builtin "truncOrBitCast_Int64_Int16"
// CHECK: return
sil @trunc_of_zext_then_zext : $@convention(thin) (Builtin.Int16) -> Builtin.Int16 {
bb0(%0 : $Builtin.Int16):
%zext = builtin "zextOrBitCast_Int16_Int64"(%0 : $Builtin.Int16) : $Builtin.Int64
%trunc = builtin "truncOrBitCast_Int64_Int32"(%zext : $Builtin.Int64) : $Builtin.Int32
%zext2 = builtin "zextOrBitCast_Int32_Int64"(%trunc : $Builtin.Int32) : $Builtin.Int64
%trunc2 = builtin "truncOrBitCast_Int64_Int16"(%zext2 : $Builtin.Int64) : $Builtin.Int16
return %trunc2 : $Builtin.Int16
}
sil @eliminate_dead_thin_to_thick_function_fun : $@convention(thin) () -> ()
// CHECK-LABEL: sil @eliminate_dead_thin_to_thick_function : $@convention(thin) () -> () {
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @eliminate_dead_thin_to_thick_function : $@convention(thin) () -> () {
bb0:
%0 = function_ref @eliminate_dead_thin_to_thick_function_fun : $@convention(thin) () -> ()
%1 = thin_to_thick_function %0 : $@convention(thin) () -> () to $@callee_owned () -> ()
strong_release %1 : $@callee_owned () -> ()
%2 = thin_to_thick_function %0 : $@convention(thin) () -> () to $@callee_owned () -> ()
strong_retain %2 : $@callee_owned () -> ()
%3 = tuple()
return %3 : $()
}
// CHECK-LABEL: sil @eliminate_thin_to_thick_apply : $@convention(thin) () -> () {
// CHECK: bb0
// CHECK: function_ref @eliminate_dead_thin_to_thick_function_fun
// CHECK-NEXT: apply
// CHECK-NEXT: return
sil @eliminate_thin_to_thick_apply : $@convention(thin) () -> () {
bb0:
%0 = function_ref @eliminate_dead_thin_to_thick_function_fun : $@convention(thin) () -> ()
%1 = thin_to_thick_function %0 : $@convention(thin) () -> () to $@callee_guaranteed () -> ()
%2 = apply %1() : $@callee_guaranteed () -> ()
return %2 : $()
}
// CHECK-LABEL: sil @ref_ops_of_enum_is_equivalent_to_ref_ops_of_payload : $@convention(thin) (Builtin.NativeObject) -> FakeOptional<Builtin.NativeObject> {
// CHECK: bb0
// CHECK-NEXT: enum
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb1
// CHECK: bb1
// CHECK-NEXT: strong_release
// CHECK-NEXT: return
sil @ref_ops_of_enum_is_equivalent_to_ref_ops_of_payload : $@convention(thin) (Builtin.NativeObject) -> FakeOptional<Builtin.NativeObject> {
bb0(%0 : $Builtin.NativeObject):
%1 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %0 : $Builtin.NativeObject
retain_value %1 : $FakeOptional<Builtin.NativeObject>
br bb1
bb1:
release_value %1 : $FakeOptional<Builtin.NativeObject>
return %1 : $FakeOptional<Builtin.NativeObject>
}
// CHECK-LABEL: sil @loadable_payload_address_only_enum_payload_promotion : $@convention(thin) (@in AddressOnlyEnum) -> Builtin.Int32 {
// CHECK: bb0
// CHECK-NEXT: unchecked_take_enum_data_addr
// CHECK-NEXT: load
// CHECK-NEXT: return
sil @loadable_payload_address_only_enum_payload_promotion : $@convention(thin) (@in AddressOnlyEnum) -> Builtin.Int32 {
bb0(%0 : $*AddressOnlyEnum):
%1 = unchecked_take_enum_data_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.Loadable!enumelt
%2 = load %1 : $*Builtin.Int32
return %2 : $Builtin.Int32
}
// CHECK-LABEL: sil @dead_unchecked_take_enum_data_addr
// CHECK: bb0(%0 : $*AddressOnlyEnum):
// CHECK-NEXT: destroy_addr %0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @dead_unchecked_take_enum_data_addr : $@convention(thin) (@in AddressOnlyEnum) -> () {
bb0(%0 : $*AddressOnlyEnum):
%1 = unchecked_take_enum_data_addr %0 : $*AddressOnlyEnum, #AddressOnlyEnum.Loadable!enumelt
destroy_addr %1 : $*Builtin.Int32
%r = tuple ()
return %r : $()
}
sil @partial_apply_arg_fun : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> () {
bb0(%0 : $Builtin.Int32, %1 : $Builtin.Int32):
%2 = tuple()
return %2 : $()
}
sil @partial_apply_generic_func : $@convention(thin) <T> () -> () {
bb0:
%0 = tuple()
return %0 : $()
}
sil @partial_apply_nothing : $@convention(thin) () -> () {
%0 = tuple()
return %0 : $()
}
// CHECK-LABEL: sil @partial_apply_without_subs_or_args_is_thin_to_thick
// CHECK: bb0:
// CHECK-NEXT: function_ref partial_apply_nothing
// CHECK-NEXT: function_ref @partial_apply_nothing
// CHECK-NEXT: thin_to_thick_function
// CHECK-NEXT: function_ref partial_apply_arg_fun
// CHECK-NEXT: function_ref @partial_apply_arg_fun
// CHECK-NEXT: integer_literal
// CHECK-NEXT: partial_apply
// CHECK-NEXT: function_ref partial_apply_generic_func
// CHECK-NEXT: function_ref @partial_apply_generic_func
// CHECK-NEXT: partial_apply
sil @partial_apply_without_subs_or_args_is_thin_to_thick : $@convention(thin) () -> (@callee_owned () -> (), @callee_owned (Builtin.Int32) -> (), @callee_owned () -> ()) {
bb0:
%0 = function_ref @partial_apply_nothing : $@convention(thin) () -> ()
%1 = partial_apply %0() : $@convention(thin) () -> ()
%2 = function_ref @partial_apply_arg_fun : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> ()
%3 = integer_literal $Builtin.Int32, 0
%4 = partial_apply %2(%3) : $@convention(thin) (Builtin.Int32, Builtin.Int32) -> ()
%5 = function_ref @partial_apply_generic_func : $@convention(thin) <T> () -> ()
%6 = partial_apply %5<Builtin.Int32>() : $@convention(thin) <T> () -> ()
%7 = tuple(%1 : $@callee_owned () -> (), %4 : $@callee_owned (Builtin.Int32) -> (), %6 : $@callee_owned () -> ())
return %7 : $(@callee_owned () -> (), @callee_owned (Builtin.Int32) -> (), @callee_owned () -> ())
}
/// Global initializers might have side-effects. We cannot delete such unused
/// calls.
// CHECK-LABEL: sil @not_dead_global_init_call : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: [[FUN:%.*]] = function_ref
// CHECK-NEXT: apply [[FUN]]()
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @not_dead_global_init_call : $@convention(thin) () -> () {
bb0:
%0 = function_ref @global_init_fun : $@convention(thin) () -> Builtin.RawPointer
%1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @sub_pointers : $@convention(thin) (Builtin.RawPointer) -> Builtin.Word
// CHECK: bb0
// CHECK-NEXT: integer_literal
// CHECK-NEXT: return
sil @sub_pointers : $@convention(thin) (Builtin.RawPointer) -> Builtin.Word {
bb0(%0 : $Builtin.RawPointer):
%1 = integer_literal $Builtin.Word, 0
%23 = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Word
%26 = builtin "ptrtoint_Word"(%23 : $Builtin.RawPointer) : $Builtin.Word
%27 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
%28 = builtin "sub_Word"(%26 : $Builtin.Word, %27 : $Builtin.Word) : $Builtin.Word
return %28 : $Builtin.Word
}
// CHECK-LABEL: sil @sub_same_value : $@convention(thin) (Builtin.RawPointer) -> Builtin.Word
// CHECK: bb0
// CHECK-NEXT: integer_literal
// CHECK-NEXT: return
sil @sub_same_value : $@convention(thin) (Builtin.RawPointer) -> Builtin.Word {
bb0(%0 : $Builtin.RawPointer):
%27 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
%28 = builtin "sub_Word"(%27 : $Builtin.Word, %27 : $Builtin.Word) : $Builtin.Word
return %28 : $Builtin.Word
}
sil @generic_call_with_indirect_result : $@convention(thin) <T> (@in T) -> @out T
sil @generic_call_without_indirect_result : $@convention(thin) <T> (@in T) -> Bool
sil @generic_call_with_direct_result : $@convention(thin) <T> (T) -> T
// CHECK-LABEL: sil @generic_partialapply : $@convention(thin) () -> () {
// CHECK-NOT: partial_apply
sil @generic_partialapply : $@convention(thin) () -> () {
bb0:
%0 = function_ref @generic_call_with_indirect_result : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
%1 = function_ref @generic_call_without_indirect_result : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Bool
%2 = partial_apply %0<Builtin.Int32>() : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
%3 = alloc_stack $Builtin.Int32
%4 = alloc_stack $Builtin.Int32
%5 = apply %2(%3, %4) : $@callee_owned (@in Builtin.Int32) -> @out Builtin.Int32
%6 = partial_apply %1<Builtin.Int32>() : $@convention(thin) <τ_0_0> (@in τ_0_0) -> Bool
%7 = apply %6(%3) : $@callee_owned (@in Builtin.Int32) -> Bool
%8 = integer_literal $Builtin.Int32, 0
%9 = function_ref @generic_call_with_direct_result : $@convention(thin) <τ_0_0> (τ_0_0) -> τ_0_0
%10 = partial_apply %9<Builtin.Int32>() : $@convention(thin) <τ_0_0> (τ_0_0) -> τ_0_0
%11 = apply %10(%8) : $@callee_owned (Builtin.Int32) -> Builtin.Int32
%12 = partial_apply %9<Builtin.Int32>(%8) : $@convention(thin) <τ_0_0> (τ_0_0) -> τ_0_0
%13 = apply %12() : $@callee_owned () -> Builtin.Int32
dealloc_stack %4 : $*Builtin.Int32
dealloc_stack %3 : $*Builtin.Int32
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @bitcast_round_trips : $@convention(thin) (Builtin.NativeObject, Builtin.RawPointer) -> (Builtin.NativeObject, Builtin.RawPointer) {
// CHECK-NOT: unchecked_ref_cast
// CHECK-NOT: unchecked_trivial_bit_cast
sil @bitcast_round_trips : $@convention(thin) (Builtin.NativeObject, Builtin.RawPointer) -> (Builtin.NativeObject, Builtin.RawPointer) {
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.RawPointer):
%2 = unchecked_ref_cast %0 : $Builtin.NativeObject to $Optional<Builtin.NativeObject>
%3 = unchecked_ref_cast %2 : $Optional<Builtin.NativeObject> to $Builtin.NativeObject
%4 = unchecked_trivial_bit_cast %1 : $Builtin.RawPointer to $Builtin.Word
%5 = unchecked_trivial_bit_cast %4 : $Builtin.Word to $Builtin.RawPointer
%6 = tuple(%3 : $Builtin.NativeObject, %5 : $Builtin.RawPointer)
return %6 : $(Builtin.NativeObject, Builtin.RawPointer)
}
// CHECK-LABEL: sil @bitcast_combines : $@convention(thin) (Builtin.NativeObject, Builtin.RawPointer) -> (B, Optional<Builtin.Word>) {
// CHECK: unchecked_ref_cast
// CHECK-NOT: unchecked_bit_cast
// CHECK: unchecked_trivial_bit_cast
// CHECK-NOT: unchecked_trivial_bit_cast
sil @bitcast_combines : $@convention(thin) (Builtin.NativeObject, Builtin.RawPointer) -> (B, Optional<Builtin.Word>) {
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.RawPointer):
%2 = unchecked_ref_cast %0 : $Builtin.NativeObject to $Optional<Builtin.NativeObject>
%3 = unchecked_ref_cast %2 : $Optional<Builtin.NativeObject> to $B
%4 = unchecked_trivial_bit_cast %1 : $Builtin.RawPointer to $Builtin.Word
%5 = unchecked_trivial_bit_cast %4 : $Builtin.Word to $Optional<Builtin.Word>
%6 = tuple(%3 : $B, %5 : $Optional<Builtin.Word>)
return %6 : $(B, Optional<Builtin.Word>)
}
// CHECK-LABEL: sil @bitwise_combines : $@convention(thin) (Builtin.NativeObject, Builtin.RawPointer) -> (Optional<Builtin.NativeObject>, Builtin.RawPointer, Optional<Builtin.NativeObject>) {
// CHECK: bb0
// CHECK-NEXT: unchecked_bitwise_cast
// CHECK-NEXT: unchecked_trivial_bit_cast
// CHECK-NEXT: unchecked_ref_cast
sil @bitwise_combines : $@convention(thin) (Builtin.NativeObject, Builtin.RawPointer) -> (Optional<Builtin.NativeObject>, Builtin.RawPointer, Optional<Builtin.NativeObject>) {
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.RawPointer):
// combine
%2 = unchecked_bitwise_cast %1 : $Builtin.RawPointer to $Builtin.Word
%3 = unchecked_bitwise_cast %2 : $Builtin.Word to $Optional<Builtin.NativeObject>
// promote trivial
%4 = unchecked_bitwise_cast %0 : $Builtin.NativeObject to $Builtin.RawPointer
// promote ref
%5 = unchecked_bitwise_cast %0 : $Builtin.NativeObject to $Optional<Builtin.NativeObject>
%6 = tuple(%3 : $Optional<Builtin.NativeObject>, %4 : $Builtin.RawPointer, %5 : $Optional<Builtin.NativeObject>)
return %6 : $(Optional<Builtin.NativeObject>, Builtin.RawPointer, Optional<Builtin.NativeObject>)
}
//CHECK-LABEL: @remove_pointer_compare_to_zero
//CHECK-NOT: apply
//CHECK-NOT: cond_fail
//CHECK: return
sil @remove_pointer_compare_to_zero : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = string_literal utf8 "ss"
%2 = integer_literal $Builtin.Word, 0
%4 = builtin "inttoptr_Word"(%2 : $Builtin.Word) : $Builtin.RawPointer
%6 = builtin "cmp_eq_RawPointer"(%1 : $Builtin.RawPointer, %4 : $Builtin.RawPointer) : $Builtin.Int1
cond_fail %6 : $Builtin.Int1
%8 = tuple ()
return %8 : $()
}
//CHECK-LABEL: @remove_pointer_compare_to_zero_NE
//CHECK-NOT: apply
//CHECK: cond_fail
//CHECK: unreachable
sil @remove_pointer_compare_to_zero_NE : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%1 = string_literal utf8 "ss"
%2 = integer_literal $Builtin.Word, 0
%4 = builtin "inttoptr_Word"(%2 : $Builtin.Word) : $Builtin.RawPointer
%6 = builtin "cmp_ne_RawPointer"(%1 : $Builtin.RawPointer, %4 : $Builtin.RawPointer) : $Builtin.Int1
cond_fail %6 : $Builtin.Int1
%8 = tuple ()
return %8 : $()
}
//CHECK-LABEL: @remove_pointer_compare_to_zero_arith
//CHECK-NOT: apply
//CHECK-NOT: cond_fail
//CHECK: return
sil @remove_pointer_compare_to_zero_arith : $@convention(thin) (Builtin.Word) -> () {
bb0(%0 : $Builtin.Word):
%1 = string_literal utf8 "ss"
%2 = integer_literal $Builtin.Word, 0
%3 = integer_literal $Builtin.Word, 4
%4 = integer_literal $Builtin.Int1, -1
%6 = builtin "smul_with_overflow_Word"(%0 : $Builtin.Word, %2 : $Builtin.Word, %4 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
%7 = tuple_extract %6 : $(Builtin.Word, Builtin.Int1), 0
%9 = builtin "inttoptr_Word"(%7 : $Builtin.Word) : $Builtin.RawPointer
%11 = builtin "cmp_eq_RawPointer"(%1 : $Builtin.RawPointer, %9 : $Builtin.RawPointer) : $Builtin.Int1
cond_fail %11 : $Builtin.Int1
%13 = tuple ()
return %13 : $()
}
// CHECK-LABEL: sil @nonnil
sil @nonnil : $@convention(thin) () -> Builtin.Int1 {
bb0:
// CHECK: bb0
// CHECK-NOT: select_enum
%1 = integer_literal $Builtin.Int32, 8
%2 = struct $Int32 (%1 : $Builtin.Int32)
%3 = enum $Optional<Int32>, #Optional.some!enumelt, %2 : $Int32
%t = integer_literal $Builtin.Int1, -1
%f = integer_literal $Builtin.Int1, 0
// CHECK: [[ONE:%[^ ]+]] = integer_literal $Builtin.Int1, -1
%5 = select_enum %3 : $Optional<Int32>, case #Optional.some!enumelt: %t, case #Optional.none!enumelt: %f : $Builtin.Int1
// CHECK: return [[ONE]]
return %5 : $Builtin.Int1
}
// CHECK-LABEL: sil @isnil
sil @isnil : $@convention(thin) () -> Builtin.Int1 {
bb0:
// CHECK: bb0
// CHECK-NOT: select_enum
%1 = enum $Optional<Int>, #Optional.none!enumelt
%t = integer_literal $Builtin.Int1, -1
%f = integer_literal $Builtin.Int1, 0
// CHECK: [[ZERO:%[^ ]+]] = integer_literal $Builtin.Int1, 0
%5 = select_enum %1 : $Optional<Int>, case #Optional.some!enumelt: %t, case #Optional.none!enumelt: %f : $Builtin.Int1
// CHECK: return [[ZERO]]
return %5 : $Builtin.Int1
}
class ZZZ {
@objc deinit
init()
}
struct SSS {
}
//CHECK-LABEL: sil @test_delete_readonly_owned
//CHECK: bb0(%0 : $ZZZ):
//CHECK-NEXT: strong_release %0
//CHECK-NEXT: tuple
//CHECK-NEXT: return
sil @test_delete_readonly_owned : $@convention(thin) (@owned ZZZ) -> () {
bb0(%0 : $ZZZ):
%2 = function_ref @read_only_owned : $@convention(thin) (@owned ZZZ) -> () // user: %4
%4 = apply %2(%0) : $@convention(thin) (@owned ZZZ) -> ()
%6 = tuple () // user: %7
return %6 : $() // id: %7
}
sil [readonly] @read_only_owned : $@convention(thin) (@owned ZZZ) -> ()
//CHECK-LABEL: sil @test_delete_readonly_guaranteed
//CHECK: bb0(%0 : $ZZZ):
//CHECK-NEXT: tuple
//CHECK-NEXT: return
sil @test_delete_readonly_guaranteed : $@convention(thin) (@guaranteed ZZZ) -> () {
bb0(%0 : $ZZZ):
%2 = function_ref @read_only_guaranteed : $@convention(thin) (@guaranteed ZZZ) -> () // user: %4
%4 = apply %2(%0) : $@convention(thin) (@guaranteed ZZZ) -> ()
%6 = tuple () // user: %7
return %6 : $() // id: %7
}
sil [readonly] @read_only_guaranteed : $@convention(thin) (@guaranteed ZZZ) -> ()
//CHECK-LABEL: sil @test_delete_readonly_in
//CHECK: bb0(%0 : $*SSS):
//CHECK-NEXT: destroy_addr %0
//CHECK-NEXT: tuple
//CHECK-NEXT: return
sil @test_delete_readonly_in : $@convention(thin) (@in SSS) -> () {
bb0(%0 : $*SSS):
%2 = function_ref @read_only_in : $@convention(thin) (@in SSS) -> () // user: %4
%4 = apply %2(%0) : $@convention(thin) (@in SSS) -> ()
%6 = tuple () // user: %7
return %6 : $() // id: %7
}
sil [readonly] @read_only_in : $@convention(thin) (@in SSS) -> ()
struct MyError : Error {
}
sil [readonly] @readonly_throwing : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error)
sil [readonly] @readonly_owned : $@convention(thin) (@owned B) -> @owned B
sil @returns_param : $@convention(thin) (@owned B) -> @owned B
// CHECK-LABEL: sil @delete_readonly_insert_release_after_arc_uses_simple
// CHECK: apply
// CHECK-NEXT: strong_retain
// CHECK-NEXT: strong_release
// CHECK-NEXT: return
sil @delete_readonly_insert_release_after_arc_uses_simple : $@convention(thin) (@owned B) -> @owned B {
bb0(%0 : $B):
%fu = function_ref @returns_param : $@convention(thin) (@owned B) -> @owned B
%ru = apply %fu(%0) : $@convention(thin) (@owned B) -> @owned B
%f = function_ref @readonly_owned : $@convention(thin) (@owned B) -> @owned B
%r = apply %f(%0) : $@convention(thin) (@owned B) -> @owned B
strong_retain %ru : $B // This is actually %0
strong_release %r : $B
return %0 : $B
}
// CHECK-LABEL: sil @delete_readonly_insert_release_after_arc_uses_multibb
// CHECK: apply
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: strong_release
// CHECK: bb2:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: strong_release
// CHECK: bb3:
// CHECK-NEXT: return
sil @delete_readonly_insert_release_after_arc_uses_multibb : $@convention(thin) (@owned B) -> @owned B {
bb0(%0 : $B):
%fu = function_ref @returns_param : $@convention(thin) (@owned B) -> @owned B
%ru = apply %fu(%0) : $@convention(thin) (@owned B) -> @owned B
%f = function_ref @readonly_owned : $@convention(thin) (@owned B) -> @owned B
%r = apply %f(%0) : $@convention(thin) (@owned B) -> @owned B
cond_br undef, bb1, bb2
bb1:
strong_retain %ru : $B // This is actually %0
strong_release %r : $B
br bb3
bb2:
strong_retain %ru : $B // This is actually %0
strong_release %r : $B
br bb3
bb3:
return %0 : $B
}
// CHECK-LABEL: sil @dont_delete_readonly_function_dealloc_ref_simple
// CHECK: apply
// CHECK-NEXT: dealloc_stack_ref
// CHECK: return
sil @dont_delete_readonly_function_dealloc_ref_simple : $@convention(thin) () -> () {
bb0:
%3 = alloc_ref [stack] $B
%f = function_ref @readonly_owned : $@convention(thin) (@owned B) -> @owned B
%r = apply %f(%3) : $@convention(thin) (@owned B) -> @owned B
dealloc_stack_ref %3 : $B
strong_release %r : $B
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil @dont_delete_readonly_function_dealloc_ref_multibb
// CHECK: apply
// CHECK: dealloc_stack_ref
// CHECK-NEXT: strong_release
// CHECK: dealloc_stack_ref
// CHECK-NEXT: strong_release
// CHECK: return
sil @dont_delete_readonly_function_dealloc_ref_multibb : $@convention(thin) () -> () {
bb0:
%3 = alloc_ref [stack] $B
%f = function_ref @readonly_owned : $@convention(thin) (@owned B) -> @owned B
%r = apply %f(%3) : $@convention(thin) (@owned B) -> @owned B
cond_br undef, bb1, bb2
bb1:
dealloc_stack_ref %3 : $B
strong_release %r : $B
br bb3
bb2:
dealloc_stack_ref %3 : $B
strong_release %r : $B
br bb3
bb3:
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil @delete_readonly_function_dealloc_ref_simple
// CHECK-NOT: apply
// CHECK: return
sil @delete_readonly_function_dealloc_ref_simple : $@convention(thin) () -> () {
bb0:
%3 = alloc_ref [stack] $B
%f = function_ref @readonly_owned : $@convention(thin) (@owned B) -> @owned B
%r = apply %f(%3) : $@convention(thin) (@owned B) -> @owned B
strong_release %r : $B
dealloc_stack_ref %3 : $B
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil @delete_readonly_function_dealloc_ref_multibb
// CHECK-NOT: apply
// CHECK: return
sil @delete_readonly_function_dealloc_ref_multibb : $@convention(thin) () -> () {
bb0:
%3 = alloc_ref [stack] $B
%f = function_ref @readonly_owned : $@convention(thin) (@owned B) -> @owned B
%r = apply %f(%3) : $@convention(thin) (@owned B) -> @owned B
cond_br undef, bb1, bb2
bb1:
strong_release %r : $B
dealloc_stack_ref %3 : $B
br bb3
bb2:
strong_release %r : $B
dealloc_stack_ref %3 : $B
br bb3
bb3:
%10 = tuple ()
return %10 : $()
}
//CHECK-LABEL: sil @test_delete_readonly_try_apply
//CHECK: bb0(%0 : $ZZZ):
//CHECK-NEXT: [[IL:%[0-9]+]] = integer_literal $Builtin.Int1, 0
//CHECK-NEXT: cond_br [[IL]], bb1, bb2
//CHECK: bb1:
//CHECK-NEXT: strong_release %0
//CHECK-NEXT: br bb3
//CHECK: bb2:
//CHECK-NEXT: strong_release %0
//CHECK-NEXT: br bb3
//CHECK: bb3:
//CHECK: return
sil @test_delete_readonly_try_apply : $@convention(thin) (@owned ZZZ) -> () {
bb0(%0 : $ZZZ):
%2 = function_ref @readonly_throwing : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error)
try_apply %2(%0) : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error), normal bb1, error bb2
bb1(%4 : $ZZZ):
strong_release %4 : $ZZZ
br bb3
bb2(%8 : $Error):
strong_release %8 : $Error
br bb3
bb3:
%6 = tuple ()
return %6 : $()
}
//CHECK-LABEL: sil @test_dont_delete_readonly_try_apply1
//CHECK: try_apply %{{[0-9]+}}(%0)
sil @test_dont_delete_readonly_try_apply1 : $@convention(thin) (@owned ZZZ) -> () {
bb0(%0 : $ZZZ):
%2 = function_ref @readonly_throwing : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error)
try_apply %2(%0) : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error), normal bb1, error bb2
bb1(%4 : $ZZZ):
strong_release %4 : $ZZZ
br bb3
bb2(%8 : $Error):
// Additional instructions in error block.
%u = function_ref @unknown : $@convention(thin) () -> ()
%r = apply %u() : $@convention(thin) () -> ()
strong_release %8 : $Error
br bb3
bb3:
%6 = tuple ()
return %6 : $()
}
//CHECK-LABEL: sil @test_dont_delete_readonly_try_apply2
//CHECK: try_apply %{{[0-9]+}}(%0)
sil @test_dont_delete_readonly_try_apply2 : $@convention(thin) (@owned ZZZ) -> () {
bb0(%0 : $ZZZ):
%2 = function_ref @readonly_throwing : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error)
try_apply %2(%0) : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error), normal bb1, error bb2
bb1(%4 : $ZZZ):
// Additional instructions in normal return block.
%u = function_ref @unknown : $@convention(thin) () -> ()
%r = apply %u() : $@convention(thin) () -> ()
strong_release %4 : $ZZZ
br bb3
bb2(%8 : $Error):
strong_release %8 : $Error
br bb3
bb3:
%6 = tuple ()
return %6 : $()
}
//CHECK-LABEL: sil @test_dont_delete_readonly_try_apply3
//CHECK: try_apply %{{[0-9]+}}(%0)
sil @test_dont_delete_readonly_try_apply3 : $@convention(thin) (@owned ZZZ) -> () {
bb0(%0 : $ZZZ):
%2 = function_ref @readonly_throwing : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error)
try_apply %2(%0) : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error), normal bb1, error bb2
bb1(%4 : $ZZZ):
strong_release %4 : $ZZZ
br bb3
bb2(%8 : $Error):
strong_release %8 : $Error
// Normal and error block don't have a common successor block.
br bb4
bb3:
%u = function_ref @unknown : $@convention(thin) () -> ()
%r = apply %u() : $@convention(thin) () -> ()
br bb4
bb4:
%6 = tuple ()
return %6 : $()
}
//CHECK-LABEL: sil @test_dont_delete_readonly_try_apply4
//CHECK: try_apply %{{[0-9]+}}(%0)
sil @test_dont_delete_readonly_try_apply4 : $@convention(thin) (@owned ZZZ, @owned ZZZ) -> @owned ZZZ {
bb0(%0 : $ZZZ, %1 : $ZZZ):
%2 = function_ref @readonly_throwing : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error)
try_apply %2(%0) : $@convention(thin) (@owned ZZZ) -> (ZZZ, @error Error), normal bb1, error bb2
bb1(%4 : $ZZZ):
strong_release %4 : $ZZZ
br bb3(%0 : $ZZZ)
bb2(%8 : $Error):
strong_release %8 : $Error
// Normal and error block don't use the same block arguments for the common successor.
br bb3(%1 : $ZZZ)
bb3(%a : $ZZZ):
return %a : $ZZZ
}
struct FakeInt16 {
var val : Builtin.Int16
}
struct FakeInt32 {
var val : Builtin.Int32
}
// CHECK-LABEL: sil @loadable_switchenumaddr_promotion : $@convention(thin) (@in FakeOptional<Builtin.RawPointer>) -> () {
// CHECK-NOT: switch_enum_addr
// CHECK: load
// CHECK-NEXT: switch_enum
// CHECK-NOT: switch_enum_addr
sil @loadable_switchenumaddr_promotion : $@convention(thin) (@in FakeOptional<Builtin.RawPointer>) -> () {
bb0(%0 : $*FakeOptional<Builtin.RawPointer>):
switch_enum_addr %0 : $*FakeOptional<Builtin.RawPointer>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @resilient_enum_case_propagation
// CHECK: bb0:
// CHECK: br bb2
// CHECK: bb1:
// CHECK: return
sil @resilient_enum_case_propagation : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = alloc_stack $FloatingPointRoundingRule
inject_enum_addr %0 : $*FloatingPointRoundingRule, #FloatingPointRoundingRule.toNearestOrEven!enumelt
%2 = alloc_stack $FloatingPointRoundingRule
copy_addr %0 to [init] %2 : $*FloatingPointRoundingRule
destroy_addr %0 : $*FloatingPointRoundingRule
switch_enum_addr %2 : $*FloatingPointRoundingRule, case #FloatingPointRoundingRule.toNearestOrAwayFromZero!enumelt: bb1, default bb2
bb1:
%6 = integer_literal $Builtin.Int64, 1
br bb3(%6 : $Builtin.Int64)
bb2:
destroy_addr %2 : $*FloatingPointRoundingRule
%9 = integer_literal $Builtin.Int64, 0
br bb3(%9 : $Builtin.Int64)
bb3(%11 : $Builtin.Int64):
dealloc_stack %2 : $*FloatingPointRoundingRule
dealloc_stack %0 : $*FloatingPointRoundingRule
return %11 : $Builtin.Int64
}
@objc(XX) protocol XX {
}
class XXImpl : XX {
@objc deinit
init()
}
// CHECK-LABEL: sil @unowned_round_trips : $@convention(thin) (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) -> (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) {
// CHECK: bb0(
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @unowned_round_trips : $@convention(thin) (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) -> (B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject) {
bb0(%0 : $B, %1 : $@sil_unowned B, %2 : $AnyObject, %3: $@sil_unmanaged AnyObject):
%4 = ref_to_unowned %0 : $B to $@sil_unowned B
%5 = unowned_to_ref %4 : $@sil_unowned B to $B
%6 = unowned_to_ref %1 : $@sil_unowned B to $B
%7 = ref_to_unowned %6 : $B to $@sil_unowned B
%8 = ref_to_unmanaged %2 : $AnyObject to $@sil_unmanaged AnyObject
%9 = unmanaged_to_ref %8 : $@sil_unmanaged AnyObject to $AnyObject
%10 = unmanaged_to_ref %3 : $@sil_unmanaged AnyObject to $AnyObject
%11 = ref_to_unmanaged %10 : $AnyObject to $@sil_unmanaged AnyObject
%9999 = tuple(%5 : $B, %7 : $@sil_unowned B, %9 : $AnyObject, %11 : $@sil_unmanaged AnyObject)
return %9999 : $(B, @sil_unowned B, AnyObject, @sil_unmanaged AnyObject)
}
// CHECK-LABEL: sil @collapse_existential_pack_unpack_unchecked_ref_cast
// CHECK: bb0([[Ref:%.*]]: $MyClass):
// CHECK-NOT: init_existential_ref
// CHECK-NOT: open_existential_ref
// CHECK: unchecked_ref_cast [[Ref]]
sil @collapse_existential_pack_unpack_unchecked_ref_cast : $@convention(thin) (MyClass) -> Builtin.NativeObject {
bb0(%0: $MyClass):
%1 = init_existential_ref %0 : $MyClass : $MyClass, $AnyObject
%2 = open_existential_ref %1 : $AnyObject to $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self
%3 = unchecked_ref_cast %2 : $@opened("2CAE06CE-5F10-11E4-AF13-C82A1428F987", AnyObject) Self to $Builtin.NativeObject
strong_retain %3: $Builtin.NativeObject
return %3 : $Builtin.NativeObject
}
// CHECK-LABEL: sil @load_fixlifetime_address
// CHECK: [[Stck:%.*]] = alloc_stack
// CHECK-NOT: fix_lifetime [[Stck]]#1
// CHECK: [[StckVal:%.*]] = load [[Stck]]
// CHECK: fix_lifetime [[StckVal]]
sil @load_fixlifetime_address : $@convention(thin) (Builtin.NativeObject) -> () {
bb0(%0: $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
store %0 to %1: $*Builtin.NativeObject
fix_lifetime %1 : $*Builtin.NativeObject
dealloc_stack %1 : $*Builtin.NativeObject
%6 = tuple ()
return %6 : $()
}
struct GenContainer<T> {
}
sil public_external [serialized] @materializeForSetClosure : $@convention(thin) <T> (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout GenContainer<T>, @thick GenContainer<T>.Type) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $*Builtin.UnsafeValueBuffer, %2 : $*GenContainer<T>, %3 : $@thick GenContainer<T>.Type):
unreachable
}
// CHECK-LABEL: sil @remove_dead_code_after_cond_fail :
// CHECK: [[Ref:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: cond_fail [[Ref]]
// CHECK-NEXT: unreachable
// CHECK: } // end sil function 'remove_dead_code_after_cond_fail'
sil @remove_dead_code_after_cond_fail : $@convention(thin) () -> (Int32) {
bb0:
%0 = integer_literal $Builtin.Int32, -2
%1 = integer_literal $Builtin.Int1, -1
cond_fail %1 : $Builtin.Int1
%3 = struct $Int32 (%0 : $Builtin.Int32)
return %3 : $Int32
}
// CHECK-LABEL: sil @dont_remove_code_after_cond_fail
// CHECK: bb0([[Cond:%.*]] : $Builtin.Int1):
// CHECK-NEXT: [[Ref:%.*]] = integer_literal $Builtin.Int32, -2
// CHECK-NEXT: cond_fail [[Cond]]
// CHECK-NEXT: [[Ret:%.*]] = struct $Int32 ([[Ref]] : $Builtin.Int32)
// CHECK-NEXT: return [[Ret]]
sil @dont_remove_code_after_cond_fail : $@convention(thin) (Builtin.Int1) -> (Int32) {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int32, -2
cond_fail %0 : $Builtin.Int1
%3 = struct $Int32 (%1 : $Builtin.Int32)
return %3 : $Int32
}
// CHECK-LABEL: sil @builtin_array_opt_index_raw_pointer_to_index_addr
// CHECK: [[MT:%.*]] = metatype $@thick Int32.Type
// CHECK: [[ONE:%.*]] = integer_literal $Builtin.Word, 1
// CHECK: [[PTA1:%.*]] = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int32
// CHECK: [[CAST1:%.*]] = builtin "truncOrBitCast_Int64_Word"(%0 : $Builtin.Int64)
// CHECK: [[IAD1:%.*]] = index_addr [[PTA1]] : $*Int32, [[CAST1]] : $Builtin.Word
// CHECK: [[ATP1:%.*]] = address_to_pointer [[IAD1]] : $*Int32 to $Builtin.RawPointer
// CHECK: [[PTA2:%.*]] = pointer_to_address %2 : $Builtin.RawPointer to [strict] $*Int32
// CHECK: [[CAST2:%.*]] = builtin "truncOrBitCast_Int64_Word"(%0 : $Builtin.Int64)
// CHECK: [[IAD2:%.*]] = index_addr [[PTA2]] : $*Int32, [[CAST2]] : $Builtin.Word
// CHECK: [[ATP2:%.*]] = address_to_pointer [[IAD2]] : $*Int32 to $Builtin.RawPointer
// CHECK: builtin "takeArrayFrontToBack"<Int32>([[MT]] : $@thick Int32.Type, [[ATP1]] : $Builtin.RawPointer, [[ATP2]] : $Builtin.RawPointer, [[ONE]] : $Builtin.Word) : $()
// CHECK: return
sil @builtin_array_opt_index_raw_pointer_to_index_addr : $@convention(thin) (Builtin.Int64, Builtin.RawPointer, Builtin.RawPointer) -> () {
bb0(%0 : $Builtin.Int64, %1 : $Builtin.RawPointer, %2 : $Builtin.RawPointer):
%4 = metatype $@thick Int32.Type
%5 = integer_literal $Builtin.Word, 1
%6 = integer_literal $Builtin.Int1, 0
%7 = builtin "strideof"<Int32>(%4 : $@thick Int32.Type) : $Builtin.Word
%14 = builtin "zextOrBitCast_Word_Int64"(%7 : $Builtin.Word) : $Builtin.Int64
%8 = builtin "smul_with_overflow_Word"(%14 : $Builtin.Int64, %0 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%9 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 0
%15 = builtin "truncOrBitCast_Int64_Word"(%9 : $Builtin.Int64) : $Builtin.Word
%10 = index_raw_pointer %1 : $Builtin.RawPointer, %15 : $Builtin.Word
%11 = index_raw_pointer %2 : $Builtin.RawPointer, %15 : $Builtin.Word
%12 = builtin "takeArrayFrontToBack"<Int32>(%4 : $@thick Int32.Type, %10 : $Builtin.RawPointer, %11 : $Builtin.RawPointer, %5 : $Builtin.Word) : $()
%13 = tuple ()
return %13 : $()
}
// Make sure we do not crash here. This ensures that when checking for
// tuple_extract, we check if we have an argument or not.
sil @builtin_array_opt_index_raw_pointer_to_index_addr_no_crash : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> Builtin.Word {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%2 = index_raw_pointer %0 : $Builtin.RawPointer, %1 : $Builtin.Word
%3 = pointer_to_address %2 : $Builtin.RawPointer to [strict] $*Builtin.Word
%4 = load %3 : $*Builtin.Word
return %4 : $Builtin.Word
}
// CHECK-LABEL: sil @cmp_zext_peephole
// CHECK: bb0([[Arg1:%.*]] : $Builtin.Word, [[Arg2:%.*]] : $Builtin.Word):
// CHECK: [[ZA1:%.*]] = builtin "zextOrBitCast_Word_Int64"([[Arg1]] : $Builtin.Word) : $Builtin.Int64
// CHECK: [[ZA2:%.*]] = builtin "zextOrBitCast_Word_Int64"([[Arg2]] : $Builtin.Word) : $Builtin.Int64
// CHECK: builtin "cmp_eq_Word"([[Arg1]] : $Builtin.Word, [[Arg2]] : $Builtin.Word)
// CHECK: builtin "cmp_ne_Word"([[Arg1]] : $Builtin.Word, [[Arg2]] : $Builtin.Word)
// CHECK: builtin "cmp_ule_Word"([[Arg1]] : $Builtin.Word, [[Arg2]] : $Builtin.Word)
// CHECK: builtin "cmp_ult_Word"([[Arg1]] : $Builtin.Word, [[Arg2]] : $Builtin.Word)
// CHECK: builtin "cmp_uge_Word"([[Arg1]] : $Builtin.Word, [[Arg2]] : $Builtin.Word)
// CHECK: builtin "cmp_ugt_Word"([[Arg1]] : $Builtin.Word, [[Arg2]] : $Builtin.Word)
// CHECK: builtin "cmp_sle_Int64"([[ZA1]] : $Builtin.Int64, [[ZA2]] : $Builtin.Int64)
// CHECK: builtin "cmp_slt_Int64"([[ZA1]] : $Builtin.Int64, [[ZA2]] : $Builtin.Int64)
// CHECK: builtin "cmp_sge_Int64"([[ZA1]] : $Builtin.Int64, [[ZA2]] : $Builtin.Int64)
// CHECK: builtin "cmp_sgt_Int64"([[ZA1]] : $Builtin.Int64, [[ZA2]] : $Builtin.Int64)
sil @cmp_zext_peephole : $@convention(thin) (Builtin.Word, Builtin.Word) -> () {
bb0(%0 : $Builtin.Word, %1 : $Builtin.Word):
%2 = builtin "zextOrBitCast_Word_Int64"(%0 : $Builtin.Word) : $Builtin.Int64
%3 = builtin "zextOrBitCast_Word_Int64"(%1 : $Builtin.Word) : $Builtin.Int64
%4 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %4 : $Builtin.Int1
%6 = builtin "cmp_ne_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %6 : $Builtin.Int1
%8 = builtin "cmp_ule_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %8 : $Builtin.Int1
%10 = builtin "cmp_ult_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %10 : $Builtin.Int1
%12 = builtin "cmp_uge_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %12 : $Builtin.Int1
%14 = builtin "cmp_ugt_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %14 : $Builtin.Int1
%16 = builtin "cmp_sle_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %16 : $Builtin.Int1
%18 = builtin "cmp_slt_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %18 : $Builtin.Int1
%20 = builtin "cmp_sge_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %20 : $Builtin.Int1
%22 = builtin "cmp_sgt_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
cond_fail %22 : $Builtin.Int1
%24 = tuple()
return %24 : $()
}
// CHECK-LABEL: sil @alloc_ref_dynamic_with_metatype
// CHECK: bb0
// CHECK-NOT: alloc_ref_dynamic
// CHECK-NEXT: alloc_ref $B
// CHECK-NEXT: strong_release
// CHECK: return
sil @alloc_ref_dynamic_with_metatype : $() -> () {
%1 = metatype $@thick B.Type
%2 = alloc_ref_dynamic %1 : $@thick B.Type, $B
strong_release %2 : $B
%4 = tuple()
return %4 : $()
}
// CHECK: sil @alloc_ref_dynamic_with_metatype_generic
// CHECK: metatype
// CHECK: upcast
// CHECK: alloc_ref_dynamic
// CHECK: return
sil @alloc_ref_dynamic_with_metatype_generic : $<T where T : B>() -> () {
%1 = metatype $@thick T.Type
%2 = upcast %1 : $@thick T.Type to $@thick B.Type
%3 = alloc_ref_dynamic %2 : $@thick B.Type, $B
strong_release %3 : $B
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: sil @alloc_ref_dynamic_with_upcast_metatype
// CHECK: bb0
// CHECK-NOT: alloc_ref_dynamic
// CHECK-NEXT: [[R:%[0-9]+]] = alloc_ref $E
// CHECK-NEXT: [[C:%[0-9]+]] = upcast [[R]] : $E to $B
// CHECK-NEXT: return [[C]]
sil @alloc_ref_dynamic_with_upcast_metatype : $() -> B {
%1 = metatype $@thick E.Type
%2 = upcast %1 : $@thick E.Type to $@thick B.Type
%3 = alloc_ref_dynamic %2 : $@thick B.Type, $B
return %3 : $B
}
// CHECK-LABEL: @alloc_ref_dynamic_after_successful_checked_cast_br
// CHECK: checked_cast_br
// CHECK: bb1
// CHECK-NOT: alloc_ref_dynamic
// CHECK: alloc_ref $B
sil @alloc_ref_dynamic_after_successful_checked_cast_br : $(@thick B.Type) -> Builtin.Int32 {
bb0(%1 : $@thick B.Type):
checked_cast_br [exact] @thick B.Type in %1 : $@thick B.Type to B.Type, bb1, bb2
bb1(%2 : $@thick B.Type):
%3 = alloc_ref_dynamic %2 : $@thick B.Type, $B
strong_release %3 : $B
%4 = integer_literal $Builtin.Int32, 1
br bb3 (%4 : $Builtin.Int32)
bb2:
%5 = integer_literal $Builtin.Int32, 2
br bb3 (%5 : $Builtin.Int32)
bb3 (%10: $Builtin.Int32):
return %10 : $Builtin.Int32
}
// CHECK-LABEL: @alloc_ref_dynamic_upcast_after_successful_checked_cast_br
// CHECK: checked_cast_br
// CHECK: bb1
// CHECK-NOT: alloc_ref_dynamic
// CHECK: [[R:%[0-9]+]] = alloc_ref $E
// CHECK-NEXT: strong_release [[R]]
sil @alloc_ref_dynamic_upcast_after_successful_checked_cast_br : $(@thick B.Type) -> Builtin.Int32 {
bb0(%1 : $@thick B.Type):
checked_cast_br [exact] @thick B.Type in %1 : $@thick B.Type to E.Type, bb1, bb2
bb1(%2 : $@thick E.Type):
%3 = upcast %2 : $@thick E.Type to $@thick B.Type
%4 = alloc_ref_dynamic %3 : $@thick B.Type, $B
strong_release %4 : $B
%5 = integer_literal $Builtin.Int32, 1
br bb3 (%5 : $Builtin.Int32)
bb2:
%6 = integer_literal $Builtin.Int32, 2
br bb3 (%6 : $Builtin.Int32)
bb3 (%10: $Builtin.Int32):
return %10 : $Builtin.Int32
}
// CHECK-LABEL: sil @delete_dead_alloc_stack
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @delete_dead_alloc_stack : $(@inout B) -> () {
bb0(%0 : $*B):
%1 = alloc_stack $B
copy_addr %0 to [init] %1 : $*B
destroy_addr %1 : $*B
dealloc_stack %1 : $*B
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @delete_dead_alloc_ref
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @delete_dead_alloc_ref : $() -> () {
bb0:
%1 = alloc_ref $B
set_deallocating %1 : $B
fix_lifetime %1 : $B
dealloc_ref %1 : $B
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @delete_dead_alloc_stack2
// CHECK: bb0
// CHECK-NEXT: destroy_addr %0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @delete_dead_alloc_stack2 : $(@in B) -> () {
bb0(%0 : $*B):
%1 = alloc_stack $B
copy_addr [take] %0 to [init] %1 : $*B
destroy_addr %1 : $*B
dealloc_stack %1 : $*B
%2 = tuple()
return %2 : $()
}
sil @use_b : $@convention(thin) (@inout B) -> ()
// CHECK-LABEL: sil @dont_delete_dead_alloc_stack
// CHECK: bb0
// CHECK-NEXT: alloc_stack
// CHECK-NEXT: copy_addr
// CHECK: return
sil @dont_delete_dead_alloc_stack : $(@inout B) -> () {
bb0(%0 : $*B):
%1 = alloc_stack $B
copy_addr %0 to [init] %1 : $*B
%2 = function_ref @use_b : $@convention(thin) (@inout B) -> ()
%3 = apply %2(%1) : $@convention(thin) (@inout B) -> ()
destroy_addr %1 : $*B
dealloc_stack %1 : $*B
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: sil @moved_retain_prevents_alloc_stack_deletion1
// CHECK: copy_addr
// CHECK: strong_retain
// CHECK: destroy_addr
// CHECK: } // end sil function 'moved_retain_prevents_alloc_stack_deletion1'
sil @moved_retain_prevents_alloc_stack_deletion1 : $@convention(thin) (@guaranteed B) -> () {
bb0(%0 : $B):
%3 = alloc_stack $B
%4 = alloc_stack $B
store %0 to %4 : $*B
copy_addr [take] %4 to [init] %3 : $*B
dealloc_stack %4 : $*B
strong_retain %0 : $B
destroy_addr %3 : $*B
dealloc_stack %3 : $*B
%14 = tuple ()
return %14 : $()
}
// CHECK-LABEL: sil @moved_retain_prevents_alloc_stack_deletion2
// CHECK: copy_addr
// CHECK: bb1:
// CHECK: strong_retain
// CHECK: destroy_addr
// CHECK: bb2:
// CHECK: strong_retain
// CHECK: destroy_addr
// CHECK: } // end sil function 'moved_retain_prevents_alloc_stack_deletion2'
sil @moved_retain_prevents_alloc_stack_deletion2 : $@convention(thin) (@guaranteed B) -> () {
bb0(%0 : $B):
%3 = alloc_stack $B
%4 = alloc_stack $B
store %0 to %4 : $*B
copy_addr [take] %4 to [init] %3 : $*B
dealloc_stack %4 : $*B
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $B
destroy_addr %3 : $*B
dealloc_stack %3 : $*B
br bb3
bb2:
strong_retain %0 : $B
destroy_addr %3 : $*B
dealloc_stack %3 : $*B
br bb3
bb3:
%14 = tuple ()
return %14 : $()
}
// CHECK-LABEL: sil @retain_is_after_stack_location
// CHECK-NOT: copy_addr
// CHECK: } // end sil function 'retain_is_after_stack_location'
sil @retain_is_after_stack_location : $@convention(thin) (@guaranteed B) -> () {
bb0(%0 : $B):
%3 = alloc_stack $B
%4 = alloc_stack $B
store %0 to %4 : $*B
copy_addr [take] %4 to [init] %3 : $*B
dealloc_stack %4 : $*B
cond_br undef, bb1, bb2
bb1:
destroy_addr %3 : $*B
strong_retain %0 : $B
dealloc_stack %3 : $*B
br bb3
bb2:
destroy_addr %3 : $*B
strong_retain %0 : $B
dealloc_stack %3 : $*B
br bb3
bb3:
%14 = tuple ()
return %14 : $()
}
// CHECK-LABEL: sil @moved_retain_prevents_alloc_stack_deletion3
// CHECK: copy_addr
// CHECK: bb2:
// CHECK: strong_retain
// CHECK: destroy_addr
// CHECK: } // end sil function 'moved_retain_prevents_alloc_stack_deletion3'
sil @moved_retain_prevents_alloc_stack_deletion3 : $@convention(thin) (@guaranteed B) -> () {
bb0(%0 : $B):
%3 = alloc_stack $B
%4 = alloc_stack $B
store %0 to %4 : $*B
copy_addr [take] %4 to [init] %3 : $*B
dealloc_stack %4 : $*B
br bb1
bb1:
cond_br undef, bb1, bb2
bb2:
strong_retain %0 : $B
destroy_addr %3 : $*B
dealloc_stack %3 : $*B
%14 = tuple ()
return %14 : $()
}
protocol someProtocol {
var i: Int { get }
}
// CHECK-LABEL: sil @witness_archetype
// CHECK: bb0
// CHECK-NEXT: alloc_stack $T
// CHECK-NEXT: copy_addr
// CHECK-NEXT: destroy_addr
// CHECK-NEXT: [[T0:%.*]] = witness_method $T
// CHECK-NEXT: apply [[T0]]<T>
// CHECK: return
sil @witness_archetype : $@convention(thin) <T where T : someProtocol> (@in T) -> () {
bb0(%0 : $*T):
%3 = alloc_stack $someProtocol // users: %4, %7, %10, %13, %15
%4 = init_existential_addr %3 : $*someProtocol, $T // user: %5
copy_addr %0 to [init] %4 : $*T // id: %5
destroy_addr %0 : $*T // id: %6
%7 = open_existential_addr immutable_access %3 : $*someProtocol to $*@opened("105977B0-D8EB-11E4-AC00-3C0754644993", someProtocol) Self // users: %8, %9
%8 = witness_method $@opened("105977B0-D8EB-11E4-AC00-3C0754644993", someProtocol) Self, #someProtocol.i!getter, %7 : $*@opened("105977B0-D8EB-11E4-AC00-3C0754644993", someProtocol) Self : $@convention(witness_method: someProtocol) <τ_0_0 where τ_0_0 : someProtocol> (@in_guaranteed τ_0_0) -> Int // user: %9
%9 = apply %8<@opened("105977B0-D8EB-11E4-AC00-3C0754644993", someProtocol) Self>(%7) : $@convention(witness_method: someProtocol) <τ_0_0 where τ_0_0 : someProtocol> (@in_guaranteed τ_0_0) -> Int
destroy_addr %3 : $*someProtocol // id: %13
dealloc_stack %3 : $*someProtocol // id: %15
%16 = tuple () // user: %17
return %16 : $() // id: %17
}
protocol P {
}
protocol Q : P {
}
struct T : Q {
init()
}
// CHECK-LABEL: sil @silcombine_checked_cast_addr_br_on_metatype_into_checked_cast_br_on_metatype
// CHECK: bb0:
// CHECK: metatype $@thick T.Type
// CHECK-NOT: checked_cast_addr_br
// CHECK: checked_cast_br
// CHECK: bb1(%[[ARG:[0-9]+]] : $@thick any Q.Type)
// CHECK: store %[[ARG]] to {{.*}} : $*@thick any Q.Type
// CHECK: }
sil @silcombine_checked_cast_addr_br_on_metatype_into_checked_cast_br_on_metatype : $@convention(thin) () -> Bool {
bb0:
%1 = metatype $@thick T.Type
%2 = init_existential_metatype %1 : $@thick T.Type, $@thick P.Type
%3 = alloc_stack $@thick P.Type
store %2 to %3 : $*@thick P.Type
%5 = alloc_stack $@thick Q.Type
checked_cast_addr_br take_always P.Type in %3 : $*@thick P.Type to Q.Type in %5 : $*@thick Q.Type, bb1, bb3
bb1:
%7 = integer_literal $Builtin.Int1, -1
br bb2(%7 : $Builtin.Int1)
bb2(%9 : $Builtin.Int1):
dealloc_stack %5 : $*@thick Q.Type
dealloc_stack %3 : $*@thick P.Type
%12 = struct $Bool (%9 : $Builtin.Int1)
return %12 : $Bool
bb3:
%14 = integer_literal $Builtin.Int1, 0
br bb2(%14 : $Builtin.Int1)
}
// Make sure we do not crash on this and remove everything, except a trivial retain/release pair.
// CHECK-LABEL: sil @partial_apply_retain_removal : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0
// CHECK-NEXT: strong_retain %0
// CHECK-NEXT: strong_release %0
// CHECK-NEXT: return
sil @partial_apply_retain_removal : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : $Builtin.NativeObject):
%1 = function_ref @user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%2 = partial_apply %1(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
strong_retain %0 : $Builtin.NativeObject
strong_release %2 : $@callee_owned @convention(thick) () -> ()
return %0 : $Builtin.NativeObject
}
// CHECK-LABEL: sil @test_cmp_xor_canonicalization
// CHECK:bb0([[ARG:%.*]] : $Builtin.Int1
// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK: [[FALSE:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK: [[EQ:%.*]] = builtin "cmp_eq_Int1"([[ARG]] : $Builtin.Int1, [[FALSE]]
// CHECK: [[NOT:%.*]] = builtin "xor_Int1"([[EQ]] : $Builtin.Int1, [[TRUE]] : $Builtin.Int1)
// CHECK: return [[NOT]]
sil @test_cmp_xor_canonicalization : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, -1
%2 = builtin "cmp_eq_Int1"(%0 : $Builtin.Int1, %1 : $Builtin.Int1) : $Builtin.Int1
return %2 : $Builtin.Int1
}
struct NStruct {
var a:Int
var b:Int
}
final class NClass {
init(news: NStruct)
var s: NStruct
}
// CHECK-LABEL: sil @narrow_load_with_debug_value
// CHECK: bb0(%0 : $NClass):
// CHECK: debug_value %0
// CHECK: [[C:%[0-9]+]] = ref_element_addr %0
// CHECK: [[S:%[0-9]+]] = struct_element_addr [[C]]
// CHECK: [[R:%[0-9]+]] = load [[S]]
// CHECK: return [[R]]
sil @narrow_load_with_debug_value : $@convention(thin) (@owned NClass) -> Int {
bb0(%0 : $NClass):
debug_value %0 : $NClass, let, name "c" // id: %1
%2 = ref_element_addr %0 : $NClass, #NClass.s // user: %3
%3 = load %2 : $*NStruct // users: %4, %5
debug_value %3 : $NStruct, let, name "xx" // id: %4
%5 = struct_extract %3 : $NStruct, #NStruct.a // user: %7
strong_release %0 : $NClass // id: %6
return %5 : $Int // id: %7
}
// CHECK-LABEL: sil @lower_retainrelease_value_of_unowned_to_unowned_retainrelease : $@convention(thin) (@owned @sil_unowned NClass, @owned @sil_unowned NClass) -> @owned @sil_unowned NClass {
// CHECK: unowned_retain
// CHECK: unowned_release
// CHECK: unowned_release
sil @lower_retainrelease_value_of_unowned_to_unowned_retainrelease : $@convention(thin) (@owned @sil_unowned NClass, @owned @sil_unowned NClass) -> @owned @sil_unowned NClass {
bb0(%0 : $@sil_unowned NClass, %1 : $@sil_unowned NClass):
retain_value %0 : $@sil_unowned NClass
release_value %1 : $@sil_unowned NClass
release_value %0 : $@sil_unowned NClass
return %0 : $@sil_unowned NClass
}
enum VendingMachineError: Error {
case InvalidSelection
case InsufficientFunds(required: Double)
case OutOfStock
}
// Check that we can delete exceptions if we can inline the `throw`
// block into the `try` block.
// CHECK-LABEL: @RemoveUnusedException
// CHECK-NOT: alloc_existential_box
// CHECK-NOT: enum $VendingMachineError
// CHECK: return
sil hidden @RemoveUnusedException : $@convention(thin) (Int32) -> (Double, @error Error) {
bb0(%0 : $Int32):
debug_value %0 : $Int32, let, name "x" // id: %1
%2 = integer_literal $Builtin.Int32, 10 // user: %4
%3 = struct_extract %0 : $Int32, #Int32._value // user: %4
%4 = builtin "cmp_sgt_Int32"(%3 : $Builtin.Int32, %2 : $Builtin.Int32) : $Builtin.Int1 // user: %5
cond_br %4, bb1, bb2 // id: %5
bb1: // Preds: bb0
%6 = alloc_existential_box $Error, $VendingMachineError // users: %8, %9, %13
%6a = project_existential_box $VendingMachineError in %6 : $Error
%7 = enum $VendingMachineError, #VendingMachineError.OutOfStock!enumelt // user: %8
store %7 to %6a : $*VendingMachineError // id: %8
debug_value %6 : $Error, let, name "error" // id: %9
%10 = float_literal $Builtin.FPIEEE80, 0x3FFF8000000000000000 // 1 // user: %11
%11 = builtin "fptrunc_FPIEEE80_FPIEEE64"(%10 : $Builtin.FPIEEE80) : $Builtin.FPIEEE64 // user: %12
%12 = struct $Double (%11 : $Builtin.FPIEEE64) // user: %14
strong_release %6 : $Error // id: %13
br bb3(%12 : $Double) // id: %14
bb2: // Preds: bb0
%15 = float_literal $Builtin.FPIEEE80, 0x40008000000000000000 // 2 // user: %16
%16 = builtin "fptrunc_FPIEEE80_FPIEEE64"(%15 : $Builtin.FPIEEE80) : $Builtin.FPIEEE64 // user: %17
%17 = struct $Double (%16 : $Builtin.FPIEEE64) // user: %18
br bb3(%17 : $Double) // id: %18
bb3(%19 : $Double): // Preds: bb1 bb2
return %19 : $Double // id: %20
}
enum ErrorEnum: Error {
case errorCase(label: [Error])
case other
}
// CHECK-LABEL: sil @insert_compensating_release_at_release_of_box
// CHECK: [[L:%[0-9]+]] = load
// CHECK-NEXT: [[T:%[0-9]+]] = tuple
// CHECK-NEXT: retain_value [[L]]
// CHECK-NEXT: release_value [[T]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @insert_compensating_release_at_release_of_box : $@convention(method) (@in_guaranteed Array<Error>) -> () {
bb0(%0 : $*Array<Error>):
%20 = load %0 : $*Array<Error>
%22 = tuple $(label: Array<Error>) (%20)
%23 = enum $ErrorEnum, #ErrorEnum.errorCase!enumelt, %22 : $(label: Array<Error>)
%36 = alloc_existential_box $Error, $ErrorEnum
%37 = project_existential_box $ErrorEnum in %36 : $Error
store %23 to %37 : $*ErrorEnum
retain_value %20 : $Array<Error>
strong_release %36 : $Error
%52 = tuple ()
return %52 : $()
}
struct TestError: Error {
var payload: AnyObject
}
struct OtherError: Error {
var payload: AnyObject
}
// CHECK-LABEL: sil @unconditional_existential_box_cast :
// CHECK-NOT: unconditional_checked_cast_addr
// CHECK: retain_value %0
// CHECK-NOT: unconditional_checked_cast_addr
// CHECK: [[E:%[0-9]+]] = alloc_stack $any Error
// CHECK-NOT: unconditional_checked_cast_addr
// CHECK: [[T:%[0-9]+]] = alloc_stack $TestError
// CHECK-NEXT: destroy_addr [[E]]
// CHECK-NEXT: store %0 to [[T]]
// CHECK-NEXT: struct_element_addr
// CHECK-NOT: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast'
sil @unconditional_existential_box_cast : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $TestError
unconditional_checked_cast_addr Error in %5 : $*Error to TestError in %7 : $*TestError
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
}
sil @unknown_use_of_TestError : $@convention(thin) (@inout TestError) -> ()
// CHECK-LABEL: sil @unconditional_existential_box_cast_unknown_user1
// CHECK: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast_unknown_user1'
sil @unconditional_existential_box_cast_unknown_user1 : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%u = function_ref @unknown_use_of_TestError : $@convention(thin) (@inout TestError) -> ()
%r = apply %u(%2) : $@convention(thin) (@inout TestError) -> ()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $TestError
unconditional_checked_cast_addr Error in %5 : $*Error to TestError in %7 : $*TestError
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
}
sil @unknown_use_of_box : $@convention(thin) (Error) -> ()
// CHECK-LABEL: sil @unconditional_existential_box_cast_unknown_user2
// CHECK: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast_unknown_user2'
sil @unconditional_existential_box_cast_unknown_user2 : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%u = function_ref @unknown_use_of_box : $@convention(thin) (Error) -> ()
%r = apply %u(%1) : $@convention(thin) (Error) -> ()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $TestError
unconditional_checked_cast_addr Error in %5 : $*Error to TestError in %7 : $*TestError
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
}
sil @unknown_use_of_Error : $@convention(thin) (@inout Error) -> ()
// CHECK-LABEL: sil @unconditional_existential_box_cast_unknown_user3
// CHECK: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast_unknown_user3'
sil @unconditional_existential_box_cast_unknown_user3 : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%u = function_ref @unknown_use_of_Error : $@convention(thin) (@inout Error) -> ()
%r = apply %u(%5) : $@convention(thin) (@inout Error) -> ()
%7 = alloc_stack $TestError
unconditional_checked_cast_addr Error in %5 : $*Error to TestError in %7 : $*TestError
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
}
// CHECK-LABEL: sil @unconditional_existential_box_cast_multiple_stores1
// CHECK: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast_multiple_stores1'
sil @unconditional_existential_box_cast_multiple_stores1 : $@convention(thin) (@guaranteed TestError, @guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError, %0a : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
store %0a to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $TestError
unconditional_checked_cast_addr Error in %5 : $*Error to TestError in %7 : $*TestError
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
}
// CHECK-LABEL: sil @unconditional_existential_box_cast_multiple_stores2
// CHECK: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast_multiple_stores2'
sil @unconditional_existential_box_cast_multiple_stores2 : $@convention(thin) (@guaranteed TestError, @owned Error) -> @owned AnyObject {
bb0(%0 : $TestError, %0a : $Error):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
store %1 to %5 : $*Error
store %0a to %5 : $*Error
%7 = alloc_stack $TestError
unconditional_checked_cast_addr Error in %5 : $*Error to TestError in %7 : $*TestError
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
}
// CHECK-LABEL: sil @unconditional_existential_box_cast_wrong_type
// CHECK: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast_wrong_type'
sil @unconditional_existential_box_cast_wrong_type : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $OtherError
unconditional_checked_cast_addr Error in %5 : $*Error to OtherError in %7 : $*OtherError
%10 = struct_element_addr %7 : $*OtherError, #OtherError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*OtherError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
}
// CHECK-LABEL: sil @unconditional_existential_box_cast_not_dominating :
// CHECK: retain_value %0
// CHECK: [[E:%[0-9]+]] = alloc_stack $any Error
// CHECK: [[T:%[0-9]+]] = alloc_stack $TestError
// CHECK-NEXT: destroy_addr [[E]]
// CHECK-NEXT: store %0 to [[T]]
// CHECK-NEXT: struct_element_addr
// CHECK-NOT: unconditional_checked_cast_addr
// CHECK: } // end sil function 'unconditional_existential_box_cast_not_dominating'
sil @unconditional_existential_box_cast_not_dominating : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
cond_br undef, bb1, bb2
bb1:
store %0 to %2 : $*TestError
br bb2
bb2:
cond_br undef, bb3, bb4
bb3:
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $TestError
unconditional_checked_cast_addr Error in %5 : $*Error to TestError in %7 : $*TestError
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
bb4:
%20 = integer_literal $Builtin.Int1, -1
cond_fail %20 : $Builtin.Int1
unreachable
}
// CHECK-LABEL: sil @conditional_existential_box_cast
// CHECK: retain_value %0
// CHECK: [[E:%[0-9]+]] = alloc_stack $any Error
// CHECK: [[T:%[0-9]+]] = alloc_stack $TestError
// CHECK-NEXT: store %0 to [[T]]
// CHECK-NEXT: [[I:%[0-9]+]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: cond_br [[I]], bb1, bb2
// CHECK-NOT: checked_cast_addr_br
// CHECK: } // end sil function 'conditional_existential_box_cast'
sil @conditional_existential_box_cast : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $TestError
checked_cast_addr_br copy_on_success Error in %5 : $*Error to TestError in %7 : $*TestError, bb1, bb2
bb1:
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
bb2:
%20 = integer_literal $Builtin.Int1, -1
cond_fail %20 : $Builtin.Int1
unreachable
}
// CHECK-LABEL: sil @taking_conditional_existential_box_cast
// CHECK: retain_value %0
// CHECK: [[E:%[0-9]+]] = alloc_stack $any Error
// CHECK: [[T:%[0-9]+]] = alloc_stack $TestError
// CHECK-NEXT: destroy_addr [[E]]
// CHECK-NEXT: store %0 to [[T]]
// CHECK-NEXT: [[I:%[0-9]+]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: cond_br [[I]], bb1, bb2
// CHECK-NOT: checked_cast_addr_br
// CHECK: } // end sil function 'taking_conditional_existential_box_cast'
sil @taking_conditional_existential_box_cast : $@convention(thin) (@guaranteed TestError) -> @owned AnyObject {
bb0(%0 : $TestError):
%1 = alloc_existential_box $Error, $TestError
%2 = project_existential_box $TestError in %1 : $Error
store %0 to %2 : $*TestError
%4 = builtin "willThrow"(%1 : $Error) : $()
%5 = alloc_stack $Error
strong_retain %1 : $Error
store %1 to %5 : $*Error
%7 = alloc_stack $TestError
checked_cast_addr_br take_on_success Error in %5 : $*Error to TestError in %7 : $*TestError, bb1, bb2
bb1:
%10 = struct_element_addr %7 : $*TestError, #TestError.payload
%11 = load %10 : $*AnyObject
strong_release %1 : $Error
dealloc_stack %7 : $*TestError
dealloc_stack %5 : $*Error
return %11 : $AnyObject
bb2:
%20 = integer_literal $Builtin.Int1, -1
cond_fail %20 : $Builtin.Int1
unreachable
}
sil [reabstraction_thunk] @_TTRXFo_oSS_dSb_XFo_iSS_iSb_ : $@convention(thin) (@in String, @owned @callee_owned (@owned String) -> Bool) -> @out Bool
sil [reabstraction_thunk] @_TTRXFo_iSS_iSb_XFo_oSS_dSb_ : $@convention(thin) (@owned String, @owned @callee_owned (@in String) -> @out Bool) -> Bool
// CHECK-LABEL: sil @remove_identity_reabstraction_thunks
// CHECK: [[STK:%.*]] = alloc_stack $@callee_owned (@owned String) -> Bool
// CHECK-NOT: partial_apply
// CHECK: store %0 to [[STK]]
// CHECK: [[LD:%.*]] = load [[STK]]
// CHECK: strong_release [[LD]]
// CHECK: dealloc_stack [[STK]]
sil @remove_identity_reabstraction_thunks : $@convention(thin) (@owned @callee_owned (@owned String) -> Bool) -> () {
bb0(%0 : $@callee_owned (@owned String) -> Bool):
%1 = alloc_stack $@callee_owned (@owned String) -> Bool
// function_ref reabstraction thunk helper from @callee_owned (@owned Swift.String) -> (@unowned Swift.Bool) to @callee_owned (@in Swift.String) -> (@out Swift.Bool)
%2 = function_ref @_TTRXFo_oSS_dSb_XFo_iSS_iSb_ : $@convention(thin) (@in String, @owned @callee_owned (@owned String) -> Bool) -> @out Bool
%3 = partial_apply %2(%0) : $@convention(thin) (@in String, @owned @callee_owned (@owned String) -> Bool) -> @out Bool
debug_value %3 : $@callee_owned (@in String) -> @out Bool
// function_ref reabstraction thunk helper from @callee_owned (@in Swift.String) -> (@out Swift.Bool) to @callee_owned (@owned Swift.String) -> (@unowned Swift.Bool)
%4 = function_ref @_TTRXFo_iSS_iSb_XFo_oSS_dSb_ : $@convention(thin) (@owned String, @owned @callee_owned (@in String) -> @out Bool) -> Bool
%5 = partial_apply %4(%3) : $@convention(thin) (@owned String, @owned @callee_owned (@in String) -> @out Bool) -> Bool
store %5 to %1 : $*@callee_owned (@owned String) -> Bool
%6 = load %1 : $*@callee_owned (@owned String) -> Bool
strong_release %6 : $@callee_owned (@owned String) -> Bool
dealloc_stack %1 : $*@callee_owned (@owned String) -> Bool
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil @remove_unused_convert_function
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @remove_unused_convert_function : $@convention(thin) (@inout B, B, Builtin.Int1) -> () {
bb0(%0 : $*B, %1 : $B, %2 : $Builtin.Int1):
%3 = function_ref @weird_function : $@convention(thin) (@inout E, E, Builtin.Int1) -> ()
%4 = convert_function %3 : $@convention(thin) (@inout E, E, Builtin.Int1) -> () to $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
retain_value %4: $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
release_value %4: $@convention(thin) (@inout B, B, Builtin.Int1) -> ()
%7 = tuple()
return %7 : $()
}
// Make sure that we do not crash when determining if a value is not zero and
// has a value that cannot be stored in a UInt64. The specific issue is that we
// were using getZExtValue before which assumes that an APInt can be stored in a
// UInt64.
//
// CHECK-LABEL: sil @large_int_zero_comparison : $@convention(thin) () -> Builtin.Int1 {
// CHECK: [[CMP_RESULT:%.*]] = integer_literal $Builtin.Int1, 0
// CHECK: return [[CMP_RESULT]]
sil @large_int_zero_comparison : $@convention(thin) () -> Builtin.Int1 {
bb0:
%0 = integer_literal $Builtin.Int1024, 0
%1 = integer_literal $Builtin.Int1024, 0xFFFFFFFFFFFFFFFFFFFF
%2 = builtin "cmp_eq_Int1024"(%0 : $Builtin.Int1024, %1 : $Builtin.Int1024) : $Builtin.Int1
return %2 : $Builtin.Int1
}
sil @callee : $@convention(thin) (Double, @in_guaranteed Int) -> ()
sil @generic_callee : $@convention(thin) <T, U> (@in T, @in U) -> ()
sil @noreturn_func : $@convention(thin) () -> Never
// CHECK-LABEL: sil @remove_destroy_array
// CHECK-NOT: destroyArray
// CHECK: return
sil @remove_destroy_array : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%4 = metatype $@thick Int32.Type
%8 = builtin "destroyArray"<Int32>(%4 : $@thick Int32.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.Word) : $()
%90 = tuple ()
return %90 : $()
}
// CHECK-LABEL: sil @dont_remove_destroy_array_of_nontrivial_type
// CHECK: builtin "destroyArray"
// CHECK: return
sil @dont_remove_destroy_array_of_nontrivial_type : $@convention(thin) (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%4 = metatype $@thick B.Type
%8 = builtin "destroyArray"<B>(%4 : $@thick B.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.Word) : $()
%90 = tuple ()
return %90 : $()
}
// CHECK-LABEL: sil @dont_remove_destroy_array_of_generic_type
// CHECK: builtin "destroyArray"
// CHECK: return
sil @dont_remove_destroy_array_of_generic_type : $@convention(thin) <Memory> (Builtin.RawPointer, Builtin.Word) -> () {
bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
%4 = metatype $@thick Memory.Type
%8 = builtin "destroyArray"<Memory>(%4 : $@thick Memory.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.Word) : $()
%90 = tuple ()
return %90 : $()
}
// CHECK-LABEL: sil @enum_promotion_case3
// CHECK: bb0([[B_PTR:%[0-9]+]]
// CHECK-NEXT: [[ALLOCA:%[0-9]+]] = alloc_stack $FakeOptional<B>
// CHECK-NEXT: strong_release [[B_PTR]]
// CHECK-NEXT: [[ENUM:%[0-9]+]] = enum $FakeOptional<B>, #FakeOptional.some!enumelt, [[B_PTR]] : $B
// CHECK-NEXT: store [[ENUM]] to [[ALLOCA]] : $*FakeOptional<B>
// CHECK-NEXT: [[RESULT:%[0-9]+]] = load [[ALLOCA]]
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: strong_release [[B_PTR]]
// CHECK-NEXT: return [[RESULT]]
sil @enum_promotion_case3 : $@convention(thin) (@owned B) -> @owned FakeOptional<B> {
bb0(%0 : $B):
%2 = alloc_stack $FakeOptional<B>
%3 = init_enum_data_addr %2 : $*FakeOptional<B>, #FakeOptional.some!enumelt
store %0 to %3 : $*B
// This instruction between the store and the inject_enum_addr should not prevent
// the optimization.
strong_release %0 : $B
inject_enum_addr %2 : $*FakeOptional<B>, #FakeOptional.some!enumelt
%7 = load %2 : $*FakeOptional<B>
dealloc_stack %2 : $*FakeOptional<B>
strong_release %0 : $B
return %7 : $FakeOptional<B>
}
sil @init_enum : $@convention(thin) () -> @out B
// Localize the initialization of the enum payload to enable mem2reg for the enum.
// CHECK-LABEL: sil @enum_promotion_case4
// CHECK: [[V1:%.*]] = alloc_stack $FakeOptional
// CHECK: [[V2:%.*]] = function_ref @init_enum
// CHECK: [[V3:%.*]] = alloc_stack $B
// CHECK: apply [[V2]]([[V3]])
// CHECK: [[V4:%.*]] = load [[V3]]
// CHECK: [[V5:%.*]] = enum $FakeOptional<B>, #FakeOptional.some!enumelt, [[V4]]
// CHECK: store [[V5]] to [[V1]]
sil @enum_promotion_case4 : $@convention(thin) () -> @owned FakeOptional<B> {
bb0:
%2 = alloc_stack $FakeOptional<B>
%3 = init_enum_data_addr %2 : $*FakeOptional<B>, #FakeOptional.some!enumelt
%4 = function_ref @init_enum : $@convention(thin) () -> @out B
%5 = apply %4(%3) : $@convention(thin) () -> @out B
inject_enum_addr %2 : $*FakeOptional<B>, #FakeOptional.some!enumelt
%7 = load %2 : $*FakeOptional<B>
dealloc_stack %2 : $*FakeOptional<B>
return %7 : $FakeOptional<B>
}
struct MyErrorType {}
protocol Socket {
static func newWithConfig() throws -> Builtin.Int32
}
class ClientSocket : Socket {
final class func newWithConfig() throws -> Builtin.Int32
}
// CHECK-LABEL: static_existential
// CHECK:bb0:
// CHECK: [[META:%.*]] = metatype $@thick ClientSocket.Type
// CHECK: [[WM:%.*]] = witness_method $ClientSocket
// CHECK: try_apply [[WM]]<ClientSocket>([[META]])
sil @static_existential : $@convention(thin) () -> (Builtin.Int32, @error MyErrorType) {
bb0:
%0 = metatype $@thick ClientSocket.Type
%1 = init_existential_metatype %0 : $@thick ClientSocket.Type, $@thick Socket.Type
%2 = open_existential_metatype %1 : $@thick Socket.Type to $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", Socket) Self).Type
%3 = witness_method $@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", Socket) Self, #Socket.newWithConfig, %2 : $@thick (@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", Socket) Self).Type : $@convention(witness_method: Socket) <τ_0_0 where τ_0_0 : Socket> (@thick τ_0_0.Type) -> (Builtin.Int32, @error MyErrorType)
try_apply %3<@opened("82105EE0-DCB0-11E5-865D-C8E0EB309913", Socket) Self>(%2) : $@convention(witness_method: Socket) <τ_0_0 where τ_0_0 : Socket> (@thick τ_0_0.Type) -> (Builtin.Int32, @error MyErrorType), normal bb1, error bb2
bb1(%4 : $Builtin.Int32):
return %4 : $Builtin.Int32
bb2(%5 : $MyErrorType):
throw %5 : $MyErrorType
}
protocol PM {
var sum: Int { get nonmutating set }
func done()
}
extension PM {
func plus() -> Self
func minus()
}
public final class VV {
@_hasStorage final var m: PM { get set }
init()
deinit
}
sil @plus : $@convention(method) <Self where Self : PM> (@in_guaranteed Self) -> @out Self
sil @minus : $@convention(method) <Self where Self : PM> (@in_guaranteed Self) -> ()
// CHECK-LABEL: sil @silcombine_dont_change_allocstack_for_opened_archetypes
// CHECK-NOT: alloc_stack{{.*}}opened
// CHECK: open_existential_addr immutable_access {{%[0-9]+}} : $*any PM to $*@opened("090C3DB0-1C76-11E6-81C4-B8E856428C60", any PM) Self
// CHECK: return
sil @silcombine_dont_change_allocstack_for_opened_archetypes : $@convention(thin) (@owned VV) -> () {
bb0(%0 : $VV):
%8 = alloc_stack $PM, let, name "x"
%9 = ref_element_addr %0 : $VV, #VV.m
%10 = alloc_stack $PM
copy_addr %9 to [init] %10 : $*PM
%12 = open_existential_addr immutable_access %10 : $*PM to $*@opened("090C3DB0-1C76-11E6-81C4-B8E856428C60", PM) Self
%13 = init_existential_addr %8 : $*PM, $@opened("090C3DB0-1C76-11E6-81C4-B8E856428C60", PM) Self
%14 = function_ref @plus : $@convention(method) <τ_0_0 where τ_0_0 : PM> (@in_guaranteed τ_0_0) -> @out τ_0_0
%15 = apply %14<@opened("090C3DB0-1C76-11E6-81C4-B8E856428C60", PM) Self>(%13, %12) : $@convention(method) <τ_0_0 where τ_0_0 : PM> (@in_guaranteed τ_0_0) -> @out τ_0_0
destroy_addr %10 : $*PM
dealloc_stack %10 : $*PM
%20 = function_ref @minus : $@convention(method) <τ_0_0 where τ_0_0 : PM> (@in_guaranteed τ_0_0) -> ()
%21 = apply %20<@opened("090C3DB0-1C76-11E6-81C4-B8E856428C60", PM) Self>(%13) : $@convention(method) <τ_0_0 where τ_0_0 : PM> (@in_guaranteed τ_0_0) -> ()
destroy_addr %8 : $*PM
dealloc_stack %8 : $*PM
strong_release %0 : $VV
%26 = tuple ()
return %26 : $()
}
sil @any_to_object : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject
// CHECK-LABEL: sil @dont_crash_when_propagating_existentials
// CHECK: [[EM:%[0-9]+]] = init_existential_metatype %0
// CHECK: [[S:%[0-9]+]] = alloc_stack $Any
// CHECK: [[M:%[0-9]+]] = open_existential_metatype [[EM]]
// CHECK: [[E:%[0-9]+]] = init_existential_addr [[S]]
// CHECK: store [[M]] to [[E]]
// CHECK: apply {{%[0-9]+}}<(@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134", AnyObject) Self).Type>([[E]])
// CHECK: } // end sil function 'dont_crash_when_propagating_existentials'
sil @dont_crash_when_propagating_existentials : $@convention(thin) () -> @owned AnyObject {
bb0:
%0 = metatype $@thick C.Type
%1 = init_existential_metatype %0 : $@thick C.Type, $@thick AnyObject.Type
%3 = alloc_stack $Any, let, name "object"
%4 = open_existential_metatype %1 : $@thick AnyObject.Type to $@thick (@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134", AnyObject) Self).Type
%5 = init_existential_addr %3 : $*Any, $(@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134", AnyObject) Self).Type
store %4 to %5 : $*@thick (@opened("5F99B72C-EC40-11EA-9534-8C8590A6A134", AnyObject) Self).Type
%7 = open_existential_addr immutable_access %3 : $*Any to $*@opened("5F9F1B04-EC40-11EA-9534-8C8590A6A134", Any) Self
%8 = function_ref @any_to_object : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject
%9 = apply %8<@opened("5F9F1B04-EC40-11EA-9534-8C8590A6A134", Any) Self>(%7) : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0) -> @owned AnyObject
destroy_addr %3 : $*Any
dealloc_stack %3 : $*Any
return %9 : $AnyObject
}
// CHECK-LABEL: sil @remove_unused_alloc_ref
// CHECK-NEXT: bb0
// CHECK-NEXT: %0 = tuple ()
// CHECK-NEXT: return %0 : $()
sil @remove_unused_alloc_ref : $@convention(thin) () -> () {
bb0:
%1 = alloc_ref $B
dealloc_ref %1 : $B
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: sil @remove_unused_alloc_ref_stack
// CHECK-NEXT: bb0
// CHECK-NEXT: %0 = tuple ()
// CHECK-NEXT: return %0 : $()
sil @remove_unused_alloc_ref_stack : $@convention(thin) () -> () {
bb0:
%1 = alloc_ref [stack] $B
set_deallocating %1 : $B
dealloc_stack_ref %1 : $B
%3 = tuple ()
return %3 : $()
}
// Int1_const == x -> x == Int1_const
// CHECK-LABEL: sil @canonicalize_bool_eq_checks
sil @canonicalize_bool_eq_checks : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, 0
%2 = builtin "cmp_eq_Int1"(%1 : $Builtin.Int1, %0 : $Builtin.Int1) : $Builtin.Int1
return %2 : $Builtin.Int1
}
// Int1_const != x -> x != Int1_const
// CHECK-LABEL: sil @canonicalize_bool_ne_checks
sil @canonicalize_bool_ne_checks : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
bb0(%0 : $Builtin.Int1):
%1 = integer_literal $Builtin.Int1, 0
%2 = builtin "cmp_ne_Int1"(%1 : $Builtin.Int1, %0 : $Builtin.Int1) : $Builtin.Int1
return %2 : $Builtin.Int1
}
// cond_br(xor(x, 1)), t_label, f_label -> cond_br x, f_label, t_label
// CHECK-LABEL: sil @negate_branch_condition_xor1
// CHECK: bb0
// CHECK-NEXT: cond_br %0, bb2, bb1
sil @negate_branch_condition_xor1 : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%5 = integer_literal $Builtin.Int1, -1
%9 = builtin "xor_Int1"(%0 : $Builtin.Int1, %5 : $Builtin.Int1) : $Builtin.Int1
cond_br %9, bb1, bb2 // id: %10
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
// cond_br(xor(1, x)), t_label, f_label -> cond_br x, f_label, t_label
// CHECK-LABEL: sil @negate_branch_condition_xor2
// CHECK: bb0
// CHECK-NEXT: cond_br %0, bb2, bb1
sil @negate_branch_condition_xor2 : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%5 = integer_literal $Builtin.Int1, -1
%9 = builtin "xor_Int1"(%5 : $Builtin.Int1, %0 : $Builtin.Int1) : $Builtin.Int1
cond_br %9, bb1, bb2 // id: %10
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
// cond_br(x == 0), t_label, f_label -> cond_br x, f_label, t_label
// CHECK-LABEL: sil @negate_branch_condition_eq_false
// CHECK: bb0
// CHECK-NEXT: cond_br %0, bb2, bb1
sil @negate_branch_condition_eq_false : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%5 = integer_literal $Builtin.Int1, 0
%9 = builtin "cmp_eq_Int1"(%0 : $Builtin.Int1, %5 : $Builtin.Int1) : $Builtin.Int1
cond_br %9, bb1, bb2 // id: %10
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
// cond_br(x != -1), t_label, f_label -> cond_br x, f_label, t_label
// CHECK-LABEL: sil @negate_branch_condition_ne_true
// CHECK: bb0
// CHECK-NEXT: cond_br %0, bb2, bb1
sil @negate_branch_condition_ne_true : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%5 = integer_literal $Builtin.Int1, -1
%9 = builtin "cmp_ne_Int1"(%0 : $Builtin.Int1, %5 : $Builtin.Int1) : $Builtin.Int1
cond_br %9, bb1, bb2 // id: %10
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
// CHECK-LABEL: sil @switch_value_to_cond_br_1
// CHECK: bb0({{.*}}):
// CHECK-NEXT: cond_br %0, bb1, bb2
sil @switch_value_to_cond_br_1 : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%t1 = integer_literal $Builtin.Int1, -1
switch_value %0 : $Builtin.Int1, case %t1: bb1, default bb2
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
// CHECK-LABEL: sil @switch_value_to_cond_br_2
// CHECK: bb0({{.*}}):
// CHECK-NEXT: cond_br %0, bb2, bb1
sil @switch_value_to_cond_br_2 : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%f1 = integer_literal $Builtin.Int1, 0
switch_value %0 : $Builtin.Int1, case %f1: bb1, default bb2
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
// CHECK-LABEL: sil @switch_value_to_cond_br_3
// CHECK: bb0({{.*}}):
// CHECK-NEXT: cond_br %0, bb1, bb2
sil @switch_value_to_cond_br_3 : $@convention(thin) (Builtin.Int1) -> Int32 {
bb0(%0 : $Builtin.Int1):
%t1 = integer_literal $Builtin.Int1, -1
%f1 = integer_literal $Builtin.Int1, 0
switch_value %0 : $Builtin.Int1, case %t1: bb1, case %f1: bb2
bb1: // Preds: bb0
%1 = integer_literal $Builtin.Int32, 0
%2 = struct $Int32 (%1 : $Builtin.Int32) // user: %12
br bb3(%2 : $Int32) // id: %12
bb2: // Preds: bb0
%3 = integer_literal $Builtin.Int32, 1
%4 = struct $Int32 (%3 : $Builtin.Int32) // user: %12
br bb3(%4 : $Int32) // id: %15
bb3(%16 : $Int32): // Preds: bb1 bb2
return %16 : $Int32 // id: %17
}
protocol Prot0 : class {
static func newWithConfig() throws -> Builtin.Int32
}
protocol Prot1 : Prot0 {
@_nonoverride static func newWithConfig() throws -> Builtin.Int32
}
protocol Prot2 : Prot1 {
static func newWithConfig() throws -> Builtin.Int32
}
sil @getMetaType : $@convention(thin) () -> @thick Prot2.Type
// CHECK-LABEL: meta_existential
// CHECK:bb0:
// CHECK: [[APPLY:%.*]] = apply {{%.*}}() : $@convention(thin) () -> @thick any Prot2.Type
// CHECK: [[OE:%.*]] = open_existential_metatype [[APPLY]] : $@thick any Prot2.Type to $@thick (@opened("690DA5F6-B5EA-11E7-B144-685B3593C496", any Prot1) Self).Type
// CHECK: [[WM:%.*]] = witness_method $@opened("690DA5F6-B5EA-11E7-B144-685B3593C496", any Prot1) Self, #Prot1.newWithConfig : <Self where Self : Prot1> (Self.Type) -> () throws -> Builtin.Int32, [[OE]] : $@thick (@opened("690DA5F6-B5EA-11E7-B144-685B3593C496", any Prot1) Self).Type : $@convention(witness_method: Prot1) <τ_0_0 where τ_0_0 : Prot1> (@thick τ_0_0.Type) -> (Builtin.Int32, @error MyErrorType)
// CHECK: try_apply [[WM]]<@opened("690DA5F6-B5EA-11E7-B144-685B3593C496", any Prot1) Self>([[OE]]) : $@convention(witness_method: Prot1) <τ_0_0 where τ_0_0 : Prot1> (@thick τ_0_0.Type) -> (Builtin.Int32, @error MyErrorType)
sil @meta_existential : $@convention(thin) () -> (Builtin.Int32, @error MyErrorType) {
bb0:
%fref = function_ref @getMetaType : $@convention(thin) () -> @thick Prot2.Type
%apply = apply %fref() : $@convention(thin) () -> @thick Prot2.Type
%open = open_existential_metatype %apply : $@thick Prot2.Type to $@thick (@opened("690DA5F6-B5EA-11E7-B144-685B3593C496", Prot1) Self).Type
%1 = init_existential_metatype %open : $@thick (@opened("690DA5F6-B5EA-11E7-B144-685B3593C496", Prot1) Self).Type, $@thick Prot1.Type
%2 = open_existential_metatype %1 : $@thick Prot1.Type to $@thick (@opened("92105EE0-DCB0-11E5-865D-C8E0EB309913", Prot1) Self).Type
%3 = witness_method $@opened("92105EE0-DCB0-11E5-865D-C8E0EB309913", Prot1) Self, #Prot1.newWithConfig, %2 : $@thick (@opened("92105EE0-DCB0-11E5-865D-C8E0EB309913", Prot1) Self).Type : $@convention(witness_method: Prot1) <τ_0_0 where τ_0_0 : Prot1> (@thick τ_0_0.Type) -> (Builtin.Int32, @error MyErrorType)
try_apply %3<@opened("92105EE0-DCB0-11E5-865D-C8E0EB309913", Prot1) Self>(%2) : $@convention(witness_method: Prot1) <τ_0_0 where τ_0_0 : Prot1> (@thick τ_0_0.Type) -> (Builtin.Int32, @error MyErrorType), normal bb1, error bb2
bb1(%4 : $Builtin.Int32):
return %4 : $Builtin.Int32
bb2(%5 : $MyErrorType):
throw %5 : $MyErrorType
}
// CHECK-LABEL: sil @mark_dependence_base
// CHECK: bb0(
// CHECK-NOT: init_existential_ref
// CHECK-NOT: enum
// CHECK-NEXT: mark_dependence
// CHECK-NEXT: load
// CHECK: return
sil @mark_dependence_base : $@convention(thin) (@inout Builtin.Int64, @owned B) -> Builtin.Int64 {
bb0(%0 : $*Builtin.Int64, %1 : $B):
%x = init_existential_ref %1 : $B : $B, $AnyObject
%2 = enum $Optional<AnyObject>, #Optional.some!enumelt, %x : $AnyObject
%3 = mark_dependence %0 : $*Builtin.Int64 on %2 : $Optional<AnyObject>
%4 = load %3 : $*Builtin.Int64
return %4 : $Builtin.Int64
}
// CHECK-LABEL: sil @mark_dependence_trivial_object_base :
// CHECK: bb0(
// CHECK-NEXT: strong_retain
// CHECK-NEXT: return
// CHECK: } // end sil function 'mark_dependence_trivial_object_base'
sil @mark_dependence_trivial_object_base : $@convention(thin) (@guaranteed B) -> @owned B {
bb0(%0 : $B):
strong_retain %0 : $B
%1 = enum $Optional<Int>, #Optional.none!enumelt
%2 = mark_dependence %0 : $B on %1 : $Optional<Int>
return %2 : $B
}
protocol _NSArrayCore {}
// CHECK-LABEL: sil @mark_dependence_base2
// CHECK: bb0(
// CHECK-NOT: open_existential_ref
// CHECK-NOT: enum
// CHECK-NEXT: mark_dependence
// CHECK-NEXT: load
// CHECK: return
sil @mark_dependence_base2 : $@convention(thin) (@inout Builtin.Int64, @owned B) -> Builtin.Int64 {
bb0(%0 : $*Builtin.Int64, %1 : $B):
%2 = init_existential_ref %1 : $B : $B, $AnyObject
%3 = open_existential_ref %2 : $AnyObject to $@opened("B674783A-EF08-11E7-97D6-8C85900CB088", _NSArrayCore) Self
%5 = mark_dependence %0 : $*Builtin.Int64 on %3 : $@opened("B674783A-EF08-11E7-97D6-8C85900CB088", _NSArrayCore) Self
%4 = load %5 : $*Builtin.Int64
return %4 : $Builtin.Int64
}
// Test to see if we can constant fold a classify_bridge_object on a Swift class
// to false.
// CHECK-LABEL: sil @test_classify_fold
// CHECK-NOT: classify_bridge_object
// CHECK: integer_literal $Builtin.Int1, 0
// CHECK-NEXT: return
sil @test_classify_fold : $@convention(thin) (@owned _ContiguousArrayStorage<B>) -> Builtin.Int1 {
bb0(%0 : $_ContiguousArrayStorage<B>):
%1 = unchecked_ref_cast %0 : $_ContiguousArrayStorage<B> to $Builtin.BridgeObject
%2 = classify_bridge_object %1 : $Builtin.BridgeObject
%3 = tuple_extract %2 : $(Builtin.Int1, Builtin.Int1), 0
return %3 : $Builtin.Int1
}
// CHECK-LABEL: sil @bridge_cast_noop_fold
// CHECK: bb0(%0
// CHECK-NEXT: %1 = upcast %0
// CHECK-NEXT: return %1
sil @bridge_cast_noop_fold : $@convention(thin) (@owned _ContiguousArrayStorage<B>) -> __ContiguousArrayStorageBase {
bb0(%0 : $_ContiguousArrayStorage<B>):
%1 = unchecked_ref_cast %0 : $_ContiguousArrayStorage<B> to $Builtin.BridgeObject
%2 = bridge_object_to_ref %1 : $Builtin.BridgeObject to $__ContiguousArrayStorageBase
return %2 : $__ContiguousArrayStorageBase
}
sil @returnInt : $@convention(thin) () -> Builtin.Int32
// CHECK-LABEL: sil @optimize_convert_escape_to_noescape
// CHECK: [[FN:%.*]] = function_ref @returnInt
// CHECK: apply [[FN]]()
sil @optimize_convert_escape_to_noescape : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = function_ref @returnInt : $@convention(thin) () -> Builtin.Int32
%1 = thin_to_thick_function %0 : $@convention(thin) () -> Builtin.Int32 to $@callee_guaranteed () -> Builtin.Int32
%2 = convert_escape_to_noescape %1 : $@callee_guaranteed () -> Builtin.Int32 to $@noescape @callee_guaranteed () -> Builtin.Int32
%4 = apply %2() : $@noescape @callee_guaranteed () -> Builtin.Int32
return %4 : $Builtin.Int32
}
// Test the following transformation:
// (convert_escape_to_noescape (convert_function (thin_to_thick_function x))) =>
// (convert_escape_to_noescape (thin_to_thick_function (convert_function x)))
sil @returnIndirectInt : $@convention(thin) () -> @out Builtin.Int32
// CHECK-LABEL: sil @optimize_convert_escape_to_noescape_convert_function1 : $@convention(thin) () -> Builtin.Int32
// CHECK: [[FN_REF:%.*]] = function_ref @returnIndirectInt : $@convention(thin) () -> @out Builtin.Int32
// CHECK: [[INDIRECT_RESULT:%.*]] = alloc_stack $Builtin.Int32
// CHECK: apply [[FN_REF]]([[INDIRECT_RESULT]]) : $@convention(thin) () -> @out Builtin.Int32
// CHECK: [[RESULT:%.*]] = load [[INDIRECT_RESULT]] : $*Builtin.Int32
// CHECK: dealloc_stack [[INDIRECT_RESULT]] : $*Builtin.Int32
// CHECK: return [[RESULT]] : $Builtin.Int32
sil @optimize_convert_escape_to_noescape_convert_function1 : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = function_ref @returnIndirectInt : $@convention(thin) () -> @out Builtin.Int32
%1 = thin_to_thick_function %0 : $@convention(thin) () -> @out Builtin.Int32 to $@callee_guaranteed () -> @out Builtin.Int32
%2 = convert_function %1 : $@callee_guaranteed () -> @out Builtin.Int32 to $@callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%3 = convert_escape_to_noescape %2: $@callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32> to $@noescape @callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%4 = alloc_stack $Builtin.Int32
%5 = apply %3(%4) : $@noescape @callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%6 = load %4 : $*Builtin.Int32
dealloc_stack %4 : $*Builtin.Int32
return %6 : $Builtin.Int32
}
sil @dummyUser : $(@callee_guaranteed @substituted<A> () -> @out A for <Builtin.Int32>) -> ()
// CHECK-LABEL: sil @optimize_convert_escape_to_noescape_convert_function2 : $@convention(thin) () -> Builtin.Int32
// CHECK: thin_to_thick_function
// CHECK: convert_function
sil @optimize_convert_escape_to_noescape_convert_function2 : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = function_ref @returnIndirectInt : $@convention(thin) () -> @out Builtin.Int32
%1 = thin_to_thick_function %0 : $@convention(thin) () -> @out Builtin.Int32 to $@callee_guaranteed () -> @out Builtin.Int32
%2 = convert_function %1 : $@callee_guaranteed () -> @out Builtin.Int32 to $@callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%3 = function_ref @dummyUser : $@convention(thin) (@callee_guaranteed @substituted<A> () -> @out A for <Builtin.Int32>) -> ()
apply %3(%2) : $@convention(thin) (@callee_guaranteed @substituted<A> () -> @out A for <Builtin.Int32>) -> ()
%5 = convert_escape_to_noescape %2: $@callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32> to $@noescape @callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%6 = alloc_stack $Builtin.Int32
%7 = apply %5(%6) : $@noescape @callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%8 = load %6 : $*Builtin.Int32
dealloc_stack %6 : $*Builtin.Int32
return %8 : $Builtin.Int32
}
sil @dummyUser2 : $(@noescape @callee_guaranteed @substituted<A> () -> @out A for <Builtin.Int32>) -> ()
// CHECK-LABEL: sil @optimize_convert_escape_to_noescape_convert_function3 : $@convention(thin) () -> Builtin.Int32
// CHECK: thin_to_thick_function
// CHECK: convert_function
sil @optimize_convert_escape_to_noescape_convert_function3 : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = function_ref @returnIndirectInt : $@convention(thin) () -> @out Builtin.Int32
%1 = thin_to_thick_function %0 : $@convention(thin) () -> @out Builtin.Int32 to $@callee_guaranteed () -> @out Builtin.Int32
%2 = convert_function %1 : $@callee_guaranteed () -> @out Builtin.Int32 to $@callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%3 = convert_escape_to_noescape %2: $@callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32> to $@noescape @callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%4 = function_ref @dummyUser2 : $@convention(thin) (@noescape @callee_guaranteed @substituted<A> () -> @out A for <Builtin.Int32>) -> ()
apply %4(%3) : $@convention(thin) (@noescape @callee_guaranteed @substituted<A> () -> @out A for <Builtin.Int32>) -> ()
%6 = alloc_stack $Builtin.Int32
%7 = apply %3(%6) : $@noescape @callee_guaranteed @substituted <A> () -> @out A for <Builtin.Int32>
%8 = load %6 : $*Builtin.Int32
dealloc_stack %6 : $*Builtin.Int32
return %8 : $Builtin.Int32
}
// CHECK-LABEL: sil @optimize_arc_with_value_to_bridge_object
// CHECK: bb0(%0 : $Builtin.Int64):
// CHECK-NEXT: struct $UInt64
// CHECK-NEXT: value_to_bridge_object
// CHECK-NEXT: return
sil @optimize_arc_with_value_to_bridge_object : $@convention(thin) (Builtin.Int64) -> Builtin.BridgeObject {
bb0(%0 : $Builtin.Int64):
%1 = struct $UInt64 (%0 : $Builtin.Int64)
%2 = value_to_bridge_object %1 : $UInt64
strong_retain %2 : $Builtin.BridgeObject
return %2 : $Builtin.BridgeObject
}
struct MyStringObj {
@_hasStorage var a: UInt64
@_hasStorage var b: Builtin.BridgeObject
}
struct MyStringGuts {
@_hasStorage var o: MyStringObj
}
struct MyString {
@_hasStorage var g: MyStringGuts
}
// CHECK-LABEL: sil @optimize_arc_with_value_to_bridge_object2
// CHECK: bb0(%0 : $UInt64):
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: } // end sil function 'optimize_arc_with_value_to_bridge_object2'
sil @optimize_arc_with_value_to_bridge_object2 : $@convention(thin) (UInt64) -> () {
bb0(%0 : $UInt64):
%1 = integer_literal $Builtin.Int64, -1945555039024054272
%2 = value_to_bridge_object %1 : $Builtin.Int64
%3 = struct $MyStringObj (%0 : $UInt64, %2 : $Builtin.BridgeObject)
%4 = struct $MyStringGuts (%3 : $MyStringObj)
%5 = struct $MyString (%4 : $MyStringGuts)
release_value %5 : $MyString
%7 = tuple ()
return %7 : $()
}
enum EnumWithPayload {
case A(UInt64)
case B(AnyObject)
case C
}
// CHECK-LABEL: sil @optimize_arc_with_trivial_payload_enum
// CHECK: bb0(%0 : $UInt64):
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: } // end sil function 'optimize_arc_with_trivial_payload_enum'
sil @optimize_arc_with_trivial_payload_enum : $@convention(thin) (UInt64) -> () {
bb0(%0 : $UInt64):
%1 = enum $EnumWithPayload, #EnumWithPayload.A!enumelt, %0 : $UInt64
release_value %1 : $EnumWithPayload
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil @optimize_arc_with_trivial_enum
// CHECK: bb0:
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: } // end sil function 'optimize_arc_with_trivial_enum'
sil @optimize_arc_with_trivial_enum : $@convention(thin) () -> () {
bb0:
%1 = enum $EnumWithPayload, #EnumWithPayload.C!enumelt
release_value %1 : $EnumWithPayload
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil @dont_remove_release_of_nontrivial_enum
// CHECK: strong_release %0
// CHECK: } // end sil function 'dont_remove_release_of_nontrivial_enum'
sil @dont_remove_release_of_nontrivial_enum : $@convention(thin) (@guaranteed AnyObject) -> () {
bb0(%0 : $AnyObject):
%1 = enum $EnumWithPayload, #EnumWithPayload.B!enumelt, %0 : $AnyObject
release_value %1 : $EnumWithPayload
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: sil @optimize_stringObject_bit_operations
// CHECK: bb0:
// CHECK-NEXT: %0 = integer_literal $Builtin.Int64, 4611686018427387904
// CHECK-NEXT: return %0
sil @optimize_stringObject_bit_operations : $@convention(thin) () -> Builtin.Int64 {
bb0:
%2 = string_literal utf8 "thequickbrownfoxjumpsoverthelazydogusingasmanycharacteraspossible123456789"
%5 = builtin "ptrtoint_Word"(%2 : $Builtin.RawPointer) : $Builtin.Word
%6 = builtin "zextOrBitCast_Word_Int64"(%5 : $Builtin.Word) : $Builtin.Int64
%9 = integer_literal $Builtin.Int64, 13835058055282163712
%10 = builtin "stringObjectOr_Int64"(%6 : $Builtin.Int64, %9 : $Builtin.Int64) : $Builtin.Int64
%11 = struct $UInt64 (%10 : $Builtin.Int64)
%12 = value_to_bridge_object %11 : $UInt64
%33 = unchecked_trivial_bit_cast %12 : $Builtin.BridgeObject to $UInt64
%34 = integer_literal $Builtin.Int64, 6917529027641081856
%35 = struct_extract %33 : $UInt64, #UInt64._value
%36 = builtin "and_Int64"(%35 : $Builtin.Int64, %34 : $Builtin.Int64) : $Builtin.Int64
return %36 : $Builtin.Int64
}
// CHECK-LABEL: sil @dont_optimize_stringObject_bit_operations1
// CHECK: builtin "stringObjectOr_Int64"
// CHECK: builtin "and_Int64"
sil @dont_optimize_stringObject_bit_operations1 : $@convention(thin) (Builtin.RawPointer) -> Builtin.Int64 {
bb0(%2 : $Builtin.RawPointer):
%5 = builtin "ptrtoint_Word"(%2 : $Builtin.RawPointer) : $Builtin.Word
%6 = builtin "zextOrBitCast_Word_Int64"(%5 : $Builtin.Word) : $Builtin.Int64
%9 = integer_literal $Builtin.Int64, -9223372036854775808
%10 = builtin "stringObjectOr_Int64"(%6 : $Builtin.Int64, %9 : $Builtin.Int64) : $Builtin.Int64
%11 = struct $UInt64 (%10 : $Builtin.Int64)
%12 = value_to_bridge_object %11 : $UInt64
%33 = unchecked_trivial_bit_cast %12 : $Builtin.BridgeObject to $UInt64
%34 = integer_literal $Builtin.Int64, 4611686018427387904
%35 = struct_extract %33 : $UInt64, #UInt64._value
%36 = builtin "and_Int64"(%35 : $Builtin.Int64, %34 : $Builtin.Int64) : $Builtin.Int64
return %36 : $Builtin.Int64
}
// CHECK-LABEL: sil @dont_optimize_stringObject_bit_operations2
// CHECK: builtin "stringObjectOr_Int64"
// CHECK: builtin "and_Int64"
sil @dont_optimize_stringObject_bit_operations2 : $@convention(thin) () -> Builtin.Int64 {
bb0:
%2 = string_literal utf8 "thequickbrownfoxjumpsoverthelazydogusingasmanycharacteraspossible123456789"
%5 = builtin "ptrtoint_Word"(%2 : $Builtin.RawPointer) : $Builtin.Word
%6 = builtin "zextOrBitCast_Word_Int64"(%5 : $Builtin.Word) : $Builtin.Int64
%9 = integer_literal $Builtin.Int64, 13835058055282163712
%10 = builtin "stringObjectOr_Int64"(%6 : $Builtin.Int64, %9 : $Builtin.Int64) : $Builtin.Int64
%11 = struct $UInt64 (%10 : $Builtin.Int64)
%12 = value_to_bridge_object %11 : $UInt64
%33 = unchecked_trivial_bit_cast %12 : $Builtin.BridgeObject to $UInt64
%34 = integer_literal $Builtin.Int64, 1152921504606846975
%35 = struct_extract %33 : $UInt64, #UInt64._value
%36 = builtin "and_Int64"(%35 : $Builtin.Int64, %34 : $Builtin.Int64) : $Builtin.Int64
return %36 : $Builtin.Int64
}
// CHECK-LABEL: sil @conversion_to_and_from_bridge_object
// CHECK: bb0(%0 : $Builtin.Int64):
// CHECK-NEXT: return %0
sil @conversion_to_and_from_bridge_object : $@convention(thin) (Builtin.Int64) -> (Builtin.Int64) {
bb0(%0 : $Builtin.Int64):
%1 = struct $UInt64 (%0 : $Builtin.Int64)
%2 = value_to_bridge_object %1 : $UInt64
%3 = bridge_object_to_word %2 : $Builtin.BridgeObject to $Builtin.Word
%4 = builtin "zextOrBitCast_Word_Int64"(%3 : $Builtin.Word) : $Builtin.Int64
return %4 : $Builtin.Int64
}
// <rdar://46746188> crash in swift_getObjCClassFromObject
// class TestDocument: NSPersistentDocument {
// override init() {
// super.init()
// }
// convenience init(type: String) throws {
// self.init()
// }
// }
// After inlining the __allocating_init, we have two uses of the value_metatype.
// The second use goes through a thick_to_objc_metatype. When SILCombine replaces
// thick_to_objc_metatype with value_metatype, it cannot extend the liverange
// of value_metatype's operand.
@objc class TestObjCInit {
init()
convenience init(type: String) throws
}
// CHECK-LABEL: sil hidden [thunk] @objc_init_partial_dealloc : $@convention(objc_method) (@owned TestObjCInit) -> Optional<TestObjCInit> {
// CHECK: bb0(%0 : $TestObjCInit):
// CHECK: [[VMT2:%.*]] = value_metatype $@objc_metatype TestObjCInit.Type, %0 : $TestObjCInit
// CHECK: [[VMT:%.*]] = value_metatype $@thick TestObjCInit.Type, %0 : $TestObjCInit
// CHECK: dealloc_partial_ref %0 : $TestObjCInit, [[VMT]] : $@thick TestObjCInit.Type
// CHECK-NOT: value_metatype
// CHECK: [[O:%.*]] = alloc_ref_dynamic [objc] [[VMT2]] : $@objc_metatype TestObjCInit.Type, $TestObjCInit
// CHECK: [[M:%.*]] = objc_method [[O]] : $TestObjCInit, #TestObjCInit.init!initializer.foreign : (TestObjCInit.Type) -> () -> TestObjCInit, $@convention(objc_method) (@owned TestObjCInit) -> @owned TestObjCInit
// CHECK: apply [[M]]([[O]]) : $@convention(objc_method) (@owned TestObjCInit) -> @owned TestObjCInit
// CHECK-LABEL: } // end sil function 'objc_init_partial_dealloc'
sil hidden [thunk] @objc_init_partial_dealloc : $@convention(objc_method) (@owned TestObjCInit) -> Optional<TestObjCInit> {
bb0(%2 : $TestObjCInit):
%8 = value_metatype $@thick TestObjCInit.Type, %2 : $TestObjCInit
dealloc_partial_ref %2 : $TestObjCInit, %8 : $@thick TestObjCInit.Type
%11 = thick_to_objc_metatype %8 : $@thick TestObjCInit.Type to $@objc_metatype TestObjCInit.Type
%12 = alloc_ref_dynamic [objc] %11 : $@objc_metatype TestObjCInit.Type, $TestObjCInit
%13 = objc_method %12 : $TestObjCInit, #TestObjCInit.init!initializer.foreign : (TestObjCInit.Type) -> () -> TestObjCInit, $@convention(objc_method) (@owned TestObjCInit) -> @owned TestObjCInit
%14 = apply %13(%12) : $@convention(objc_method) (@owned TestObjCInit) -> @owned TestObjCInit
%19 = enum $Optional<TestObjCInit>, #Optional.some!enumelt, %14 : $TestObjCInit
return %19 : $Optional<TestObjCInit>
}
// CHECK-LABEL: sil @isConcrete_true : $@convention(thin) (@thin MyInt.Type) -> Builtin.Int1 {
// CHECK: bb0(%0 : $@thin MyInt.Type):
// CHECK: [[RESULT:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'isConcrete_true'
sil @isConcrete_true : $@convention(thin) (@thin MyInt.Type) -> Builtin.Int1 {
bb0(%0 : $@thin MyInt.Type):
%1 = builtin "isConcrete"(%0 : $@thin MyInt.Type) : $Builtin.Int1
return %1 : $Builtin.Int1
}
// CHECK-LABEL: sil @isConcrete_false : $@convention(thin) <T> (@thin T.Type) -> Builtin.Int1 {
// CHECK: bb0(%0 : $@thin T.Type):
// CHECK: [[RESULT:%.*]] = builtin "isConcrete"<T>(%0 : $@thin T.Type) : $Builtin.Int1
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'isConcrete_false'
sil @isConcrete_false : $@convention(thin) <T> (@thin T.Type) -> Builtin.Int1 {
bb0(%0 : $@thin T.Type):
// FIXME: Explicit specialization is required here when it shouldn't be
%1 = builtin "isConcrete"<T>(%0 : $@thin T.Type) : $Builtin.Int1
return %1 : $Builtin.Int1
}
// CHECK-LABEL: sil @convert_function_substitution : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out ()) -> ()
// CHECK: bb0(%0 : $@callee_guaranteed () -> @out ()):
// CHECK: apply %0
sil @convert_function_substitution : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out ()) -> () {
bb0(%0 : $@callee_guaranteed () -> @out ()):
%1 = convert_function %0 : $@callee_guaranteed () -> @out () to $@callee_guaranteed @substituted <A> () -> @out A for <()>
%2 = alloc_stack $()
apply %1(%2) : $@callee_guaranteed @substituted <A> () -> @out A for <()>
dealloc_stack %2 : $*()
return undef : $()
}
// CHECK-LABEL: sil @convert_function_substitution_pa :
sil @convert_function_substitution_pa : $@convention(thin) (@guaranteed @callee_guaranteed (@in Int, @in Int) -> @out (), @in Int) -> @owned @callee_guaranteed () -> @out () {
bb0(%0 : $@callee_guaranteed (@in Int, @in Int) -> @out (), %1 : $*Int):
%2 = convert_function %0 : $@callee_guaranteed (@in Int, @in Int) -> @out () to $@callee_guaranteed @substituted <A, B, C> (@in A, @in B) -> @out C for <Int, Int, ()>
%3 = partial_apply [callee_guaranteed] %2(%1) : $@callee_guaranteed @substituted <A, B, C> (@in A, @in B) -> @out C for <Int, Int, ()>
%4 = partial_apply [callee_guaranteed] %3(%1) : $@callee_guaranteed @substituted <A, B, C> (@in A) -> @out C for <Int, Int, ()>
%5 = convert_function %4 : $@callee_guaranteed @substituted <A, B, C> () -> @out C for <Int, Int, ()> to $@callee_guaranteed () -> @out ()
return %5 : $@callee_guaranteed () -> @out ()
}
// Test builtin "is_same_metatype" folding.
protocol SomeP {}
public enum SpecialEnum : SomeP {}
// CHECK-LABEL: sil @testFoldBuiltinIsSameMetatype : $@convention(thin) (@thick SpecialEnum.Type) -> Bool {
// CHECK-NEXT: bb0(%0 : $@thick SpecialEnum.Type):
// CHECK-NEXT: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
// CHECK-NEXT: struct $Bool ([[TRUE]] : $Builtin.Int1)
// CHECK-NEXT: return
// CHECK-LABEL: } // end sil function 'testFoldBuiltinIsSameMetatype'
sil @testFoldBuiltinIsSameMetatype : $@convention(thin) (@thick SpecialEnum.Type) -> Bool {
bb0(%0 : $@thick SpecialEnum.Type):
%1 = init_existential_metatype %0 : $@thick SpecialEnum.Type, $@thick Any.Type
%3 = builtin "is_same_metatype"(%1 : $@thick Any.Type, %1 : $@thick Any.Type) : $Builtin.Int1
%4 = struct $Bool (%3 : $Builtin.Int1)
return %4 : $Bool
}
struct IntTuple {
@_hasStorage var t: (Int64, Int64)
}
sil_global [let] @initialized_let_global : $Int64 = {
%0 = integer_literal $Builtin.Int64, 27
%initval = struct $Int64 (%0 : $Builtin.Int64)
}
sil_global @initialized_var_global : $Int64 = {
%0 = integer_literal $Builtin.Int64, 27
%initval = struct $Int64 (%0 : $Builtin.Int64)
}
sil_global [let] @initialized_tuple_global : $IntTuple = {
%0 = integer_literal $Builtin.Int64, 27
%1 = integer_literal $Builtin.Int64, 28
%2 = struct $Int64 (%0 : $Builtin.Int64)
%3 = struct $Int64 (%1 : $Builtin.Int64)
%4 = tuple (%2 : $Int64, %3 : $Int64)
%initval = struct $IntTuple (%4 : $(Int64, Int64))
}
// CHECK-LABEL: sil @load_from_global_let
// CHECK: [[I:%.*]] = integer_literal $Builtin.Int64, 27
// CHECK: [[R:%.*]] = struct $Int64 ([[I]] : $Builtin.Int64)
// CHECK: return [[R]]
// CHECK: } // end sil function 'load_from_global_let'
sil @load_from_global_let : $@convention(thin) () -> Int64 {
bb0:
%0 = global_addr @initialized_let_global : $*Int64
%1 = load %0 : $*Int64
return %1 : $Int64
}
// CHECK-LABEL: sil @load_from_global_with_projections
// CHECK: [[I:%.*]] = integer_literal $Builtin.Int64, 28
// CHECK: return [[I]]
// CHECK: } // end sil function 'load_from_global_with_projections'
sil @load_from_global_with_projections : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = global_addr @initialized_tuple_global : $*IntTuple
%1 = struct_element_addr %0 : $*IntTuple, #IntTuple.t
%2 = tuple_element_addr %1 : $*(Int64, Int64), 1
%3 = struct_element_addr %2 : $*Int64, #Int64._value
%4 = load %3 : $*Builtin.Int64
return %4 : $Builtin.Int64
}
// CHECK-LABEL: sil @load_from_global_without_projections
// CHECK-DAG: [[I1:%.*]] = integer_literal $Builtin.Int64, 27
// CHECK-DAG: [[I2:%.*]] = integer_literal $Builtin.Int64, 28
// CHECK-DAG: [[S1:%.*]] = struct $Int64 ([[I1]] : $Builtin.Int64)
// CHECK-DAG: [[S2:%.*]] = struct $Int64 ([[I2]] : $Builtin.Int64)
// CHECK-DAG: [[T:%.*]] = tuple ([[S1]] : $Int64, [[S2]] : $Int64)
// CHECK-DAG: [[IT:%.*]] = struct $IntTuple ([[T]] : $(Int64, Int64))
// CHECK: return [[IT]]
// CHECK: } // end sil function 'load_from_global_without_projections'
sil @load_from_global_without_projections : $@convention(thin) () -> IntTuple {
bb0:
%0 = global_addr @initialized_tuple_global : $*IntTuple
%1 = load %0 : $*IntTuple
return %1 : $IntTuple
}
// CHECK-LABEL: sil @load_from_global_var
// CHECK: global_addr
// CHECK-NEXT: load
// CHECK-NEXT: return
// CHECK: } // end sil function 'load_from_global_var'
sil @load_from_global_var : $@convention(thin) () -> Int64 {
bb0:
%0 = global_addr @initialized_var_global : $*Int64
%1 = load %0 : $*Int64
return %1 : $Int64
}
sil @convert_raw_pointer_to_nativeobject : $@convention(thin) (Builtin.RawPointer) -> @owned Builtin.NativeObject
// To eliminate the convert_function below we need to convert the try_apply to
// an apply. We do not delete edges like this in SILCombine with ownership and
// are trying to reduce it without ownership. So make sure we don't optimize
// this. This should be done in a different pass that handles CFG issues.
//
// CHECK-LABEL: sil @do_not_eliminate_error_adding_convert_function_used_by_try_apply_nonownership : $@convention(thin) (Builtin.RawPointer) -> @owned Builtin.NativeObject {
// CHECK: convert_function
// CHECK: try_apply
// CHECK: } // end sil function 'do_not_eliminate_error_adding_convert_function_used_by_try_apply_nonownership'
sil @do_not_eliminate_error_adding_convert_function_used_by_try_apply_nonownership : $@convention(thin) (Builtin.RawPointer) -> @owned Builtin.NativeObject {
bb0(%0 : $Builtin.RawPointer):
%f = function_ref @convert_raw_pointer_to_nativeobject : $@convention(thin) (Builtin.RawPointer) -> @owned Builtin.NativeObject
%t = thin_to_thick_function %f : $@convention(thin) (Builtin.RawPointer) -> @owned Builtin.NativeObject to $@noescape @callee_guaranteed (Builtin.RawPointer) -> @owned Builtin.NativeObject
%c = convert_function %t : $@noescape @callee_guaranteed (Builtin.RawPointer) -> @owned Builtin.NativeObject to $@noescape @callee_guaranteed (Builtin.RawPointer) -> (@owned Builtin.NativeObject, @error Error)
try_apply %c(%0) : $@noescape @callee_guaranteed (Builtin.RawPointer) -> (@owned Builtin.NativeObject, @error Error), normal bb1, error bb2
bb1(%result : $Builtin.NativeObject):
return %result : $Builtin.NativeObject
bb2(%error : $Error):
unreachable
}
sil_global private @outlined_global : $_ContiguousArrayStorage<Int>
// CHECK-LABEL: sil @test_global_value
// CHECK-NOT: retain
// CHECK-NOT: release
// CHECK-NOT: debug_value
// CHECK: } // end sil function 'test_global_value'
sil @test_global_value : $@convention(thin) () -> Int {
bb0:
%0 = global_value @outlined_global : $_ContiguousArrayStorage<Int>
strong_retain %0 : $_ContiguousArrayStorage<Int>
debug_value %0 : $_ContiguousArrayStorage<Int>, let, name "x"
%2 = upcast %0 : $_ContiguousArrayStorage<Int> to $__ContiguousArrayStorageBase
strong_retain %2 : $__ContiguousArrayStorageBase
%13 = ref_tail_addr [immutable] %2 : $__ContiguousArrayStorageBase, $Int
%16 = load %13 : $*Int
strong_release %2 : $__ContiguousArrayStorageBase
strong_release %0 : $_ContiguousArrayStorage<Int>
return %16 : $Int
} // end sil function 'test_global_value'
final class Kp1 {
@_hasStorage @_hasInitialValue final var b: Kp2? { get set }
@objc deinit
init()
}
class Kp2 {
@_hasStorage @_hasInitialValue var s: String { get set }
@objc deinit
init()
}
sil @kpgetter : $@convention(thin) (@in_guaranteed Kp2) -> @out String
sil @kpsetter : $@convention(thin) (@in_guaranteed String, @in_guaranteed Kp2) -> ()
sil @swift_getAtKeyPath : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed KeyPath<τ_0_0, τ_0_1>) -> @out τ_0_1
// Test keypath optimization for optional chaining with accesses scopes.
// E.g. \.a?.b (on a class)
//
// CHECK-LABEL: sil @test_optional_chaining_keypath
// CHECK: [[BA:%[0-9]+]] = begin_access
// CHECK: switch_enum {{.*}} case #Optional.none!enumelt: bb2, case #Optional.some!enumelt: bb1
// CHECK: bb1:
// CHECK: apply
// CHECK: end_access [[BA]]
// CHECK: bb2:
// CHECK: end_access [[BA]]
// CHECK: bb3:
// CHECK: } // end sil function 'test_optional_chaining_keypath'
sil @test_optional_chaining_keypath : $@convention(thin) (@in_guaranteed Kp1) -> @out Optional<String> {
bb0(%0 : $*Optional<String>, %1 : $*Kp1):
%kp = keypath $KeyPath<Kp1, Optional<String>>, (root $Kp1; stored_property #Kp1.b : $Optional<Kp2>; optional_chain : $Kp2; settable_property $String, id #Kp2.s!getter : (Kp2) -> () -> String, getter @kpgetter : $@convention(thin) (@in_guaranteed Kp2) -> @out String, setter @kpsetter : $@convention(thin) (@in_guaranteed String, @in_guaranteed Kp2) -> (); optional_wrap : $Optional<String>)
%f = function_ref @swift_getAtKeyPath : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed KeyPath<τ_0_0, τ_0_1>) -> @out τ_0_1
%a = apply %f<Kp1, Optional<String>>(%0, %1, %kp) : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0, @guaranteed KeyPath<τ_0_0, τ_0_1>) -> @out τ_0_1
strong_release %kp : $KeyPath<Kp1, Optional<String>>
%r = tuple ()
return %r : $()
}