blob: 1dc396d4b8793292a2704dfaf545911efd6c7ab1 [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -mandatory-inlining | %FileCheck %s
sil_stage raw
import Builtin
import Swift
//////////////////
// Declarations //
//////////////////
sil @int_user : $@convention(thin) (Builtin.Int32) -> ()
sil @in_guaranteed_user : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> ()
sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
class Klass {}
enum FakeOptional<T> {
case some(T)
case none
}
///////////
// Tests //
///////////
sil [ossa] [transparent] @load_store_borrow_ossa_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
%2 = alloc_stack $Builtin.NativeObject
store_borrow %1 to %2 : $*Builtin.NativeObject
end_borrow %1 : $Builtin.NativeObject
%f = function_ref @in_guaranteed_user : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> ()
apply %f(%2) : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> ()
dealloc_stack %2 : $*Builtin.NativeObject
%3 = alloc_stack $Builtin.NativeObject
store %0 to [init] %3 : $*Builtin.NativeObject
%4 = load_borrow %3 : $*Builtin.NativeObject
%f2 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %f2(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %4 : $Builtin.NativeObject
destroy_addr %3 : $*Builtin.NativeObject
dealloc_stack %3 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @load_store_borrow_ossa_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: store [[ARG]] to [[STACK]]
// CHECK: apply {{%.*}}([[STACK]])
// CHECK: dealloc_stack [[STACK]]
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK: store [[ARG]] to [[STACK]]
// CHECK: [[LOADED_ARG:%.*]] = load [[STACK]]
// CHECK: apply {{%.*}}([[LOADED_ARG]])
// CHECK: destroy_addr [[STACK]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: } // end sil function 'load_store_borrow_ossa_caller'
sil @load_store_borrow_ossa_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
%1 = function_ref @load_store_borrow_ossa_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %1(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%9999 = tuple()
return %9999 : $()
}
sil [ossa] [transparent] @load_store_ossa_nontrivial_callee : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $Builtin.NativeObject):
%2 = alloc_stack $Builtin.NativeObject
store %0 to [init] %2 : $*Builtin.NativeObject
%1a = copy_value %1 : $Builtin.NativeObject
store %1a to [assign] %2 : $*Builtin.NativeObject
%3 = load [copy] %2 : $*Builtin.NativeObject
destroy_value %3 : $Builtin.NativeObject
%4 = load [take] %2 : $*Builtin.NativeObject
destroy_value %4 : $Builtin.NativeObject
dealloc_stack %2 : $*Builtin.NativeObject
destroy_value %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @load_store_ossa_nontrivial_caller : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG0:%.*]] : ${{.*}}, [[ARG1:%.*]] :
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.NativeObject
//
// First we do a store init into the stack.
// CHECK: store [[ARG0]] to [[STACK]]
//
// Then we are performing a store assign, so we load the old value, store the
// new value, and release the old value.
// CHECK: strong_retain [[ARG1]]
// CHECK: [[OLD_VALUE:%.*]] = load [[STACK]]
// CHECK: store [[ARG1]] to [[STACK]]
// CHECK: strong_release [[OLD_VALUE]]
//
// Then we are performing a load [copy] + destroy.
//
// CHECK: [[COPIED_VALUE:%.*]] = load [[STACK]]
// CHECK: strong_retain [[COPIED_VALUE]]
// CHECK: release_value [[COPIED_VALUE]]
//
// Finally, we perform a load_take + destroy.
//
// CHECK: [[NEW_VALUE:%.*]] = load [[STACK]]
// CHECK: release_value [[NEW_VALUE]]
// CHECK: dealloc_stack [[STACK]]
// CHECK: release_value [[ARG1]]
// CHECK: } // end sil function 'load_store_ossa_nontrivial_caller'
sil @load_store_ossa_nontrivial_caller : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.NativeObject):
%2 = function_ref @load_store_ossa_nontrivial_callee : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> ()
apply %2(%0, %1) : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> ()
%9999 = tuple()
return %9999 : $()
}
sil [ossa] [transparent] @load_store_ossa_trivial_callee : $@convention(thin) (Builtin.Int32) -> () {
bb0(%0 : $Builtin.Int32):
%1 = alloc_stack $Builtin.Int32
store %0 to [trivial] %1 : $*Builtin.Int32
%2 = load [trivial] %1 : $*Builtin.Int32
%f = function_ref @int_user : $@convention(thin) (Builtin.Int32) -> ()
apply %f(%2) : $@convention(thin) (Builtin.Int32) -> ()
dealloc_stack %1 : $*Builtin.Int32
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @load_store_ossa_trivial_caller : $@convention(thin) (Builtin.Int32) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[STACK:%.*]] = alloc_stack $Builtin.Int32
// CHECK: store [[ARG]] to [[STACK]]
// CHECK: [[LOADED_ARG:%.*]] = load [[STACK]]
// CHECK: apply {{%.*}}([[LOADED_ARG]])
// CHECK: } // end sil function 'load_store_ossa_trivial_caller'
sil @load_store_ossa_trivial_caller : $@convention(thin) (Builtin.Int32) -> () {
bb0(%0 : $Builtin.Int32):
%f = function_ref @load_store_ossa_trivial_callee : $@convention(thin) (Builtin.Int32) -> ()
apply %f(%0) : $@convention(thin) (Builtin.Int32) -> ()
%9999 = tuple()
return %9999 : $()
}
struct NativeObjectPair {
var x: Builtin.NativeObject
var y: Builtin.NativeObject
}
sil [ossa] [transparent] @destructure_callee : $@convention(thin) (@owned (NativeObjectPair, NativeObjectPair)) -> () {
bb0(%0 : @owned $(NativeObjectPair, NativeObjectPair)):
%1 = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
(%2, %3) = destructure_tuple %0 : $(NativeObjectPair, NativeObjectPair)
(%4, %5) = destructure_struct %2 : $NativeObjectPair
(%6, %7) = destructure_struct %3 : $NativeObjectPair
apply %1(%4): $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %1(%5): $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %1(%6): $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %1(%7): $@convention(thin) (@owned Builtin.NativeObject) -> ()
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @destructure_caller : $@convention(thin) (@owned (NativeObjectPair, NativeObjectPair)) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK: [[FUNC:%.*]] = function_ref @owned_user :
// CHECK: [[ARG0:%.*]] = tuple_extract [[ARG]]
// CHECK: [[ARG1:%.*]] = tuple_extract [[ARG]]
// CHECK: [[ARG00:%.*]] = struct_extract [[ARG0]]
// CHECK: [[ARG01:%.*]] = struct_extract [[ARG0]]
// CHECK: [[ARG10:%.*]] = struct_extract [[ARG1]]
// CHECK: [[ARG11:%.*]] = struct_extract [[ARG1]]
// CHECK: apply [[FUNC]]([[ARG00]])
// CHECK: apply [[FUNC]]([[ARG01]])
// CHECK: apply [[FUNC]]([[ARG10]])
// CHECK: apply [[FUNC]]([[ARG11]])
// CHECK: } // end sil function 'destructure_caller'
sil @destructure_caller : $@convention(thin) (@owned (NativeObjectPair, NativeObjectPair)) -> () {
bb0(%0 : $(NativeObjectPair, NativeObjectPair)):
%1 = function_ref @destructure_callee : $@convention(thin) (@owned (NativeObjectPair, NativeObjectPair)) -> ()
apply %1(%0) : $@convention(thin) (@owned (NativeObjectPair, NativeObjectPair)) -> ()
%9999 = tuple()
return %9999 : $()
}
// Test out functionality that we use to work around weird semantics of
// destructors.
sil [ossa] [transparent] @special_case_callee : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1 = unchecked_ownership_conversion %0 : $Builtin.NativeObject, @guaranteed to @owned
end_lifetime %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @special_case_caller : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: } // end sil function 'special_case_caller'
sil @special_case_caller : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
%1 = function_ref @special_case_callee : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%9999 = tuple()
return %9999 : $()
}
// Test out functionality that we use to work around weird semantics of
// destructors.
sil [ossa] [transparent] @unmanaged_rr_callee : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
unmanaged_retain_value %0 : $Builtin.NativeObject
unmanaged_release_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @unmanaged_rr_caller : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: retain_value [[ARG]]
// CHECK-NEXT: release_value [[ARG]]
// CHECK-NEXT: tuple
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: } // end sil function 'unmanaged_rr_caller'
sil @unmanaged_rr_caller : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
%1 = function_ref @unmanaged_rr_callee : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%9999 = tuple()
return %9999 : $()
}
sil [transparent] [ossa] @term_ossa_callee : $@convention(thin) (@owned Builtin.NativeObject, @owned FakeOptional<Klass>) -> () {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $FakeOptional<Klass>):
checked_cast_br %0 : $Builtin.NativeObject to $Klass, bb1, bb2
bb1(%1a : @owned $Klass):
destroy_value %1a : $Klass
br bb3
bb2(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb3:
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some: bb4, default bb5
bb4(%3 : @owned $Klass):
destroy_value %3 : $Klass
br bb6
bb5(%4 : @owned $FakeOptional<Klass>):
destroy_value %4 : $FakeOptional<Klass>
br bb6
bb6:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @term_non_ossa_caller : $@convention(thin) (@owned Builtin.NativeObject, @owned FakeOptional<Klass>) -> () {
// CHECK: bb0([[ARG0:%.*]] : $Builtin.NativeObject, [[ARG1:%.*]] : $FakeOptional<Klass>):
// CHECK: checked_cast_br [[ARG0]] : $Builtin.NativeObject to $Klass, [[YES:bb[0-9]+]], [[NO:bb[0-9]+]]
//
// CHECK: [[YES]]([[SUCC:%.*]] :
// CHECK: release_value [[SUCC]]
// CHECK: br [[CONT:bb[0-9]+]]
//
// CHECK: [[NO]]:
// CHECK: release_value [[ARG0]]
// CHECK: br [[CONT]]
//
// CHECK: [[CONT]]:
// CHECK: switch_enum [[ARG1]] : $FakeOptional<Klass>, case #FakeOptional.some!enumelt.1: [[SOME:bb[0-9]+]], default [[DEFAULT:bb[0-9]+]]
//
// CHECK: [[SOME]]([[PAYLOAD:%.*]] :
// CHECK: release_value [[PAYLOAD]]
//
// CHECK: [[DEFAULT]]:
// CHECK: release_value [[ARG1]]
// CHECK: } // end sil function 'term_non_ossa_caller'
sil @term_non_ossa_caller : $@convention(thin) (@owned Builtin.NativeObject, @owned FakeOptional<Klass>) -> () {
bb0(%0 : $Builtin.NativeObject, %1 : $FakeOptional<Klass>):
%2 = function_ref @term_ossa_callee : $@convention(thin) (@owned Builtin.NativeObject, @owned FakeOptional<Klass>) -> ()
apply %2(%0, %1) : $@convention(thin) (@owned Builtin.NativeObject, @owned FakeOptional<Klass>) -> ()
%9999 = tuple()
return %9999 : $()
}
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
%2 = alloc_stack $Klass
store %0 to [init] %1 : $*Builtin.NativeObject
checked_cast_addr_br take_always Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
bb1:
destroy_addr %2 : $*Klass
br bb3
bb2:
br bb3
bb3:
dealloc_stack %2 : $*Klass
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: strong_retain [[ARG]]
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
// CHECK-NEXT: store [[ARG]] to [[SRC_ADDR]]
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [[SRC_ADDR]]
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
//
// ==> On success, we store the value into dest. The destroy is not from the
// ==> optimizer, but from the code.
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
// CHECK-NEXT: store [[CAST_VALUE]] to [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
//
// ==> take_always implies we destroy in failure
// CHECK: [[FAILURE_BB]]:
// CHECK-NEXT: strong_release [[RELOADED_ARG]]
// CHECK-NEXT: br [[CONT_BB]]
//
// CHECK: [[CONT_BB]]:
// CHECK: strong_release [[ARG]]
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_takealways_caller'
sil @term_nonossa_checked_cast_addr_br_takealways_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
%3 = function_ref @term_ossa_checked_cast_addr_br_takealways_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
strong_retain %0 : $Builtin.NativeObject
apply %3(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
strong_release %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
%2 = alloc_stack $Klass
store %0 to [init] %1 : $*Builtin.NativeObject
checked_cast_addr_br take_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
bb1:
destroy_addr %2 : $*Klass
br bb3
bb2:
destroy_addr %1 : $*Builtin.NativeObject
br bb3
bb3:
dealloc_stack %2 : $*Klass
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @term_nonossa_checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: strong_retain [[ARG]]
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
// CHECK-NEXT: store [[ARG]] to [[SRC_ADDR]]
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [[SRC_ADDR]]
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
//
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
// ==> On success, we store into dest and destroy dest.
// CHECK-NEXT: store [[CAST_VALUE]] to [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
//
// ==> Since we are doing a take on success and we failed... store the original
// ==> value back into the memory slot.
// CHECK: [[FAILURE_BB]]:
// CHECK-NEXT: store [[RELOADED_ARG]] to [[SRC_ADDR]]
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
// CHECK-NEXT: br [[CONT_BB]]
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_takeonsuccess_caller'
sil @term_nonossa_checked_cast_addr_br_takeonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
%2 = function_ref @term_ossa_checked_cast_addr_br_takeonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
strong_retain %0 : $Builtin.NativeObject
apply %2(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
strong_release %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
sil [transparent] [ossa] @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = alloc_stack $Builtin.NativeObject
%2 = alloc_stack $Klass
store %0 to [init] %1 : $*Builtin.NativeObject
checked_cast_addr_br copy_on_success Builtin.NativeObject in %1 : $*Builtin.NativeObject to Klass in %2 : $*Klass, bb1, bb2
bb1:
destroy_addr %2 : $*Klass
destroy_addr %1 : $*Builtin.NativeObject
br bb3
bb2:
destroy_addr %1 : $*Builtin.NativeObject
br bb3
bb3:
dealloc_stack %2 : $*Klass
dealloc_stack %1 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @term_nonossa_checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] :
// CHECK-NEXT: strong_retain [[ARG]]
// CHECK-NEXT: [[SRC_ADDR:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: [[DEST_ADDR:%.*]] = alloc_stack $Klass
// CHECK-NEXT: store [[ARG]] to [[SRC_ADDR]]
// CHECK-NEXT: [[RELOADED_ARG:%.*]] = load [[SRC_ADDR]]
// CHECK-NEXT: checked_cast_br [[RELOADED_ARG]] : $Builtin.NativeObject to $Klass, [[SUCCESS_BB:bb[0-9]+]], [[FAILURE_BB:bb[0-9]+]]
//
// CHECK: [[SUCCESS_BB]]([[CAST_VALUE:%.*]] :
// CHECK-NEXT: strong_retain [[CAST_VALUE]]
// CHECK-NEXT: store [[CAST_VALUE]] to [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[DEST_ADDR]]
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
// CHECK-NEXT: br [[CONT_BB:bb[0-9]+]]
//
// CHECK: [[FAILURE_BB]]:
// CHECK-NEXT: destroy_addr [[SRC_ADDR]]
// CHECK-NEXT: br [[CONT_BB]]
//
// CHECK: } // end sil function 'term_nonossa_checked_cast_addr_br_copyonsuccess_caller'
sil @term_nonossa_checked_cast_addr_br_copyonsuccess_caller : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
%1 = function_ref @term_ossa_checked_cast_addr_br_copyonsuccess_callee : $@convention(thin) (@owned Builtin.NativeObject) -> ()
strong_retain %0 : $Builtin.NativeObject
apply %1(%0) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
strong_release %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}