blob: 7ad2424d2fcff6703ab1e3fcee56a83569abe80f [file] [log] [blame]
// RUN: %target-sil-opt -module-name Swift -enable-sil-verify-all -semantic-arc-opts %s | %FileCheck %s
sil_stage raw
import Builtin
//////////////////
// Declarations //
//////////////////
typealias AnyObject = Builtin.AnyObject
enum MyNever {}
enum FakeOptional<T> {
case none
case some(T)
}
sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
sil @get_owned_obj : $@convention(thin) () -> @owned Builtin.NativeObject
sil @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
sil @inout_user : $@convention(thin) (@inout FakeOptional<NativeObjectPair>) -> ()
sil @get_native_object : $@convention(thin) () -> @owned Builtin.NativeObject
struct NativeObjectPair {
var obj1 : Builtin.NativeObject
var obj2 : Builtin.NativeObject
}
sil @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
struct FakeOptionalNativeObjectPairPair {
var pair1 : FakeOptional<NativeObjectPair>
var pair2 : FakeOptional<NativeObjectPair>
}
sil @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> ()
sil @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
sil @consume_nativeobject_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
protocol MyFakeAnyObject : Klass {
func myFakeMethod()
}
final class Klass {
var base: Klass
let baseLet: Klass
}
extension Klass : MyFakeAnyObject {
func myFakeMethod()
}
sil @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> ()
sil @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
sil @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> ()
struct MyInt {
var value: Builtin.Int32
}
struct StructWithDataAndOwner {
var data : Builtin.Int32
var owner : Klass
}
struct StructMemberTest {
var c : Klass
var s : StructWithDataAndOwner
var t : (Builtin.Int32, StructWithDataAndOwner)
}
class ClassLet {
@_hasStorage let aLet: Klass
@_hasStorage var aVar: Klass
@_hasStorage let aLetTuple: (Klass, Klass)
@_hasStorage let anOptionalLet: FakeOptional<Klass>
@_hasStorage let anotherLet: ClassLet
}
class SubclassLet: ClassLet {}
sil_global [let] @a_let_global : $Klass
sil_global @a_var_global : $Klass
enum EnumWithIndirectCase {
case first
indirect case second(Builtin.NativeObject)
}
struct StructWithEnumWithIndirectCaseField {
var i: Builtin.Int23
var field : EnumWithIndirectCase
}
sil @get_fakeoptional_nativeobject : $@convention(thin) () -> @owned FakeOptional<Builtin.NativeObject>
///////////
// Tests //
///////////
// CHECK-LABEL: sil [ossa] @argument_only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
sil [ossa] @argument_only_destroy_user_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1 = copy_value %0 : $Builtin.NativeObject
destroy_value %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @argument_diamond_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Builtin.NativeObject):
// CHECK-NEXT: [[RESULT:%.*]] = copy_value [[ARG]]
// CHECK-NEXT: cond_br undef, [[LHSBB:bb[0-9]+]], [[RHSBB:bb[0-9]+]]
//
// CHECK: [[LHSBB]]:
// CHECK-NEXT: br [[EPILOGBB:bb[0-9]+]]
//
// CHECK: [[RHSBB]]:
// CHECK-NEXT: br [[EPILOGBB]]
//
// CHECK: [[EPILOGBB]]:
// CHECK-NEXT: return [[RESULT]]
sil [ossa] @argument_diamond_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1 = copy_value %0 : $Builtin.NativeObject
%2 = copy_value %1 : $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
destroy_value %1 : $Builtin.NativeObject
br bb3
bb2:
destroy_value %1 : $Builtin.NativeObject
br bb3
bb3:
return %2 : $Builtin.NativeObject
}
// CHECK-LABEL: sil [ossa] @argument_copy_borrow_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $Builtin.NativeObject
// CHECK-NOT: copy_value
// CHECK-NOT: begin_borrow
// CHECK: apply {{%.*}}([[ARG]])
// CHECK-NOT: end_borrow
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'argument_copy_borrow_test_case'
sil [ossa] @argument_copy_borrow_test_case : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1 = copy_value %0 : $Builtin.NativeObject
%2 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%3 = begin_borrow %1 : $Builtin.NativeObject
apply %2(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %3 : $Builtin.NativeObject
destroy_value %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @argument_copy_of_copy : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK-NEXT: } // end sil function 'argument_copy_of_copy'
sil [ossa] @argument_copy_of_copy : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1 = copy_value %0 : $Builtin.NativeObject
%2 = begin_borrow %1 : $Builtin.NativeObject
%3 = copy_value %2 : $Builtin.NativeObject
%4 = begin_borrow %3 : $Builtin.NativeObject
end_borrow %4 : $Builtin.NativeObject
destroy_value %3 : $Builtin.NativeObject
end_borrow %2 : $Builtin.NativeObject
destroy_value %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @copy_struct_extract_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $NativeObjectPair):
// CHECK-NOT: copy_value
// CHECK-NOT: begin_borrow
// CHECK: [[FIELD:%.*]] = struct_extract [[ARG]]
// CHECK: apply {{%.*}}([[FIELD]]) :
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: } // end sil function 'copy_struct_extract_guaranteed_use'
sil [ossa] @copy_struct_extract_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
bb0(%0 : @guaranteed $NativeObjectPair):
%1 = copy_value %0 : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %1 : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @struct_extract_copy_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $NativeObjectPair):
// CHECK: [[FIELD:%.*]] = struct_extract [[ARG]]
// CHECK: apply {{%.*}}([[FIELD]])
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'struct_extract_copy_guaranteed_use'
sil [ossa] @struct_extract_copy_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
bb0(%0 : @guaranteed $NativeObjectPair):
%1 = struct_extract %0 : $NativeObjectPair, #NativeObjectPair.obj1
%2 = copy_value %1 : $Builtin.NativeObject
%3 = begin_borrow %2 : $Builtin.NativeObject
%4 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %3 : $Builtin.NativeObject
destroy_value %2 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @process_forwarding_uses : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'process_forwarding_uses'
sil [ossa] @process_forwarding_uses : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
bb0(%0 : @guaranteed $NativeObjectPair):
%1 = copy_value %0 : $NativeObjectPair
(%2, %3) = destructure_struct %1 : $NativeObjectPair
%4 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
destroy_value %3 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @process_forwarding_uses_2 : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'process_forwarding_uses_2'
sil [ossa] @process_forwarding_uses_2 : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1 = copy_value %0 : $Builtin.NativeObject
%2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $Builtin.NativeObject
%4 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %4(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// Do not eliminate a copy from an unowned value. This will cause us to pass the
// unowned value as guaranteed... =><=.
//
// CHECK-LABEL: sil [ossa] @unowned_arg_copy : $@convention(thin) (Builtin.NativeObject) -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'unowned_arg_copy'
sil [ossa] @unowned_arg_copy : $@convention(thin) (Builtin.NativeObject) -> () {
bb0(%0 : @unowned $Builtin.NativeObject):
%1 = copy_value %0 : $Builtin.NativeObject
%2 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %2(%1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %1 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @dead_live_range_multiple_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
// CHECK: bb3:
// CHECK: destroy_value
// CHECK: } // end sil function 'dead_live_range_multiple_destroy_value'
sil [ossa] @dead_live_range_multiple_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject) :
%1 = copy_value %0 : $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
destroy_value %1 : $Builtin.NativeObject
br bb3
bb2:
destroy_value %1 : $Builtin.NativeObject
br bb3
bb3:
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @dead_live_range_multiple_destroy_value_consuming_user : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: copy_value
// CHECK: destroy_value
// CHECK: destroy_value
// CHECK: } // end sil function 'dead_live_range_multiple_destroy_value_consuming_user'
sil [ossa] @dead_live_range_multiple_destroy_value_consuming_user : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject) :
%1 = copy_value %0 : $Builtin.NativeObject
cond_br undef, bb1, bb2
bb1:
destroy_value %1 : $Builtin.NativeObject
br bb3
bb2:
%2 = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %2(%1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
br bb3
bb3:
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @destructure_test : $@convention(thin) (@guaranteed StructMemberTest) -> Builtin.Int32 {
// CHECK: bb0([[ARG:%.*]] : @guaranteed $StructMemberTest):
// CHECK: [[EXT:%.*]] = struct_extract [[ARG]]
// CHECK: ([[DEST_1:%.*]], [[DEST_2:%.*]]) = destructure_tuple [[EXT]]
// CHECK: [[RESULT:%.*]] = struct_extract [[DEST_2]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'destructure_test'
sil [ossa] @destructure_test : $@convention(thin) (@guaranteed StructMemberTest) -> Builtin.Int32 {
bb0(%0 : @guaranteed $StructMemberTest):
%2 = struct_extract %0 : $StructMemberTest, #StructMemberTest.t
%3 = copy_value %2 : $(Builtin.Int32, StructWithDataAndOwner)
(%4, %5) = destructure_tuple %3 : $(Builtin.Int32, StructWithDataAndOwner)
%6 = begin_borrow %5 : $StructWithDataAndOwner
%7 = struct_extract %6 : $StructWithDataAndOwner, #StructWithDataAndOwner.data
end_borrow %6 : $StructWithDataAndOwner
destroy_value %5 : $StructWithDataAndOwner
return %7 : $Builtin.Int32
}
// CHECK-LABEL: sil [ossa] @multiple_arg_forwarding_inst_test : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.Int32) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'multiple_arg_forwarding_inst_test'
sil [ossa] @multiple_arg_forwarding_inst_test : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject, Builtin.Int32) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObject, %1a : $Builtin.Int32):
%2 = copy_value %0 : $Builtin.NativeObject
%3 = copy_value %1 : $Builtin.NativeObject
%4 = tuple(%2 : $Builtin.NativeObject, %3 : $Builtin.NativeObject)
destroy_value %4 : $(Builtin.NativeObject, Builtin.NativeObject)
%5 = copy_value %0 : $Builtin.NativeObject
%6 = tuple(%5 : $Builtin.NativeObject, %1a : $Builtin.Int32)
destroy_value %6 : $(Builtin.NativeObject, Builtin.Int32)
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @switch_enum_test_no_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'switch_enum_test_no_default'
sil [ossa] @switch_enum_test_no_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Builtin.NativeObject>):
%1 = copy_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb1(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb2:
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @switch_enum_test_with_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'switch_enum_test_with_default'
sil [ossa] @switch_enum_test_with_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Builtin.NativeObject>):
%1 = copy_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, default bb2
bb1(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb2(%3 : @owned $FakeOptional<Builtin.NativeObject>):
destroy_value %3 : $FakeOptional<Builtin.NativeObject>
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @do_not_add_trivial_users_of_owned_values_to_isconsumed_worklist : $@convention(thin) (@guaranteed (Klass, MyInt)) -> Builtin.Int32 {
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'do_not_add_trivial_users_of_owned_values_to_isconsumed_worklist'
sil [ossa] @do_not_add_trivial_users_of_owned_values_to_isconsumed_worklist : $@convention(thin) (@guaranteed (Klass, MyInt)) -> Builtin.Int32 {
bb0(%0 : @guaranteed $(Klass, MyInt)):
%1 = copy_value %0 : $(Klass, MyInt)
(%2, %3) = destructure_tuple %1 : $(Klass, MyInt)
%4 = struct_extract %3 : $MyInt, #MyInt.value
destroy_value %2 : $Klass
return %4 : $Builtin.Int32
}
sil [ossa] @black_hole : $@convention(thin) (@guaranteed Klass) -> ()
// Make sure that we properly eliminate all ref count ops except for the destroy
// for the @owned argument. The recursion happens since we can not eliminate the
// begin_borrow without eliminating the struct_extract (which we do after we
// eliminate the destroy_value).
// CHECK-LABEL: sil [ossa] @worklist_test : $@convention(thin) (@owned NativeObjectPair) -> () {
// CHECK-NOT: struct_extract
// CHECK: } // end sil function 'worklist_test'
sil [ossa] @worklist_test : $@convention(thin) (@owned NativeObjectPair) -> () {
bb0(%0 : @owned $NativeObjectPair):
%1 = begin_borrow %0 : $NativeObjectPair
%2 = struct_extract %1 : $NativeObjectPair, #NativeObjectPair.obj1
%3 = copy_value %2 : $Builtin.NativeObject
br bb1
bb1:
destroy_value %3 : $Builtin.NativeObject
end_borrow %1 : $NativeObjectPair
destroy_value %0 : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @begin_borrow_simple : $@convention(thin) () -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'begin_borrow_simple'
sil [ossa] @begin_borrow_simple : $@convention(thin) () -> () {
bb0:
%0 = function_ref @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
%1 = apply %0() : $@convention(thin) () -> @owned NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = copy_value %3 : $Builtin.NativeObject
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %4 : $Builtin.NativeObject
end_borrow %2 : $NativeObjectPair
destroy_value %1 : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @begin_borrow_fail : $@convention(thin) () -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'begin_borrow_fail'
sil [ossa] @begin_borrow_fail : $@convention(thin) () -> () {
bb0:
%0 = function_ref @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
%1 = apply %0() : $@convention(thin) () -> @owned NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = copy_value %3 : $Builtin.NativeObject
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %4 : $Builtin.NativeObject
destroy_value %1 : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_borrow_simple : $@convention(thin) (@in NativeObjectPair) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'load_borrow_simple'
sil [ossa] @load_borrow_simple : $@convention(thin) (@in NativeObjectPair) -> () {
bb0(%0 : $*NativeObjectPair):
%2 = load_borrow %0 : $*NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = copy_value %3 : $Builtin.NativeObject
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %4 : $Builtin.NativeObject
end_borrow %2 : $NativeObjectPair
destroy_addr %0 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @load_borrow_fail : $@convention(thin) (@in NativeObjectPair) -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'load_borrow_fail'
sil [ossa] @load_borrow_fail : $@convention(thin) (@in NativeObjectPair) -> () {
bb0(%0 : $*NativeObjectPair):
%2 = load_borrow %0 : $*NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = copy_value %3 : $Builtin.NativeObject
%5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %4 : $Builtin.NativeObject
destroy_addr %0 : $*NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// Make sure we do not eliminate the copy_value below to ensure that all uses of
// %2 are before %2's end_borrow.
//
// We used to eliminate the copy_value and change %func to use %2.
//
// CHECK-LABEL: sil [ossa] @begin_borrow_used_by_postdominating_no_return_function : $@convention(thin) () -> MyNever {
// CHECK: copy_value
// CHECK: } // end sil function 'begin_borrow_used_by_postdominating_no_return_function'
sil [ossa] @begin_borrow_used_by_postdominating_no_return_function : $@convention(thin) () -> MyNever {
bb0:
%0 = function_ref @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
%1 = apply %0() : $@convention(thin) () -> @owned NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = copy_value %3 : $Builtin.NativeObject
end_borrow %2 : $NativeObjectPair
%func = function_ref @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
apply %func(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
unreachable
}
// Make sure we do not eliminate the copy_value below to ensure that all uses of
// %2 are before %2's end_borrow.
//
// We used to eliminate the copy_value and change %func to use %2.
//
// CHECK-LABEL: sil [ossa] @load_borrow_used_by_postdominating_no_return_function : $@convention(thin) () -> MyNever {
// CHECK: copy_value
// CHECK: } // end sil function 'load_borrow_used_by_postdominating_no_return_function'
sil [ossa] @load_borrow_used_by_postdominating_no_return_function : $@convention(thin) () -> MyNever {
bb0:
%0 = function_ref @get_nativeobject_pair : $@convention(thin) () -> @owned NativeObjectPair
%1 = apply %0() : $@convention(thin) () -> @owned NativeObjectPair
%stackSlot = alloc_stack $NativeObjectPair
store %1 to [init] %stackSlot : $*NativeObjectPair
%2 = load_borrow %stackSlot : $*NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = copy_value %3 : $Builtin.NativeObject
end_borrow %2 : $NativeObjectPair
%func = function_ref @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
apply %func(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
unreachable
}
// Make sure that since we have a guaranteed argument and do not need to reason
// about end_borrows, we handle this.
//
// CHECK-LABEL: sil [ossa] @guaranteed_arg_used_by_postdominating_no_return_function : $@convention(thin) (@guaranteed NativeObjectPair) -> MyNever {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'guaranteed_arg_used_by_postdominating_no_return_function'
sil [ossa] @guaranteed_arg_used_by_postdominating_no_return_function : $@convention(thin) (@guaranteed NativeObjectPair) -> MyNever {
bb0(%0 : @guaranteed $NativeObjectPair):
%3 = struct_extract %0 : $NativeObjectPair, #NativeObjectPair.obj1
%4 = copy_value %3 : $Builtin.NativeObject
%func = function_ref @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
apply %func(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
unreachable
}
// Make sure that since our borrow introducer is a begin_borrow, we do not
// eliminate the copy.
//
// CHECK-LABEL: sil [ossa] @borrowed_val_used_by_postdominating_no_return_function : $@convention(thin) (@owned NativeObjectPair) -> MyNever {
// CHECK: copy_value
// CHECK: } // end sil function 'borrowed_val_used_by_postdominating_no_return_function'
sil [ossa] @borrowed_val_used_by_postdominating_no_return_function : $@convention(thin) (@owned NativeObjectPair) -> MyNever {
bb0(%0 : @owned $NativeObjectPair):
%1 = begin_borrow %0 : $NativeObjectPair
%2 = struct_extract %1 : $NativeObjectPair, #NativeObjectPair.obj1
%3 = copy_value %2 : $Builtin.NativeObject
%func = function_ref @unreachable_guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
apply %func(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> MyNever
unreachable
}
// Just make sure that we do not crash on this. We should be able to eliminate
// everything here.
//
// CHECK-LABEL: sil [ossa] @copy_value_with_debug_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
// CHECK: bb0
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK-NEXT: } // end sil function 'copy_value_with_debug_user'
sil [ossa] @copy_value_with_debug_user : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
bb0(%0 : @guaranteed $NativeObjectPair):
%1 = struct_extract %0 : $NativeObjectPair, #NativeObjectPair.obj1
%2 = copy_value %1 : $Builtin.NativeObject
debug_value %2 : $Builtin.NativeObject, let, name "myField"
destroy_value %2 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// Just make sure we do not crash here.
//
// CHECK-LABEL: sil [ossa] @do_not_insert_end_borrow_given_deadend : $@convention(thin) (@guaranteed ClassLet) -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'do_not_insert_end_borrow_given_deadend'
sil [ossa] @do_not_insert_end_borrow_given_deadend : $@convention(thin) (@guaranteed ClassLet) -> () {
bb0(%x : @guaranteed $ClassLet):
%f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> ()
%p = ref_element_addr %x : $ClassLet, #ClassLet.aLet
%v = load_borrow %p : $*Klass
%c = copy_value %v : $Klass
end_borrow %v : $Klass
apply %f(%c) : $@convention(thin) (@guaranteed Klass) -> ()
cond_br undef, bb1, bb2
bb1:
destroy_value %c : $Klass
br bb3
bb2:
destroy_value %c : $Klass
br bb3
bb3:
unreachable
}
// CHECK-LABEL: sil [ossa] @switch_enum_test_copyvalue_no_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'switch_enum_test_copyvalue_no_default'
sil [ossa] @switch_enum_test_copyvalue_no_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Builtin.NativeObject>):
%1 = copy_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2
bb1(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb2:
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @switch_enum_test_copyvalue_with_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'switch_enum_test_copyvalue_with_default'
sil [ossa] @switch_enum_test_copyvalue_with_default : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Builtin.NativeObject>):
%1 = copy_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, default bb2
bb1(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb2(%3 : @owned $FakeOptional<Builtin.NativeObject>):
destroy_value %3 : $FakeOptional<Builtin.NativeObject>
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @switch_enum_test_copyvalue_with_default_and_extract : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'switch_enum_test_copyvalue_with_default_and_extract'
sil [ossa] @switch_enum_test_copyvalue_with_default_and_extract : $@convention(thin) (@guaranteed FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Builtin.NativeObject>):
%f = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%1 = copy_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, default bb2
bb1(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb2(%3 : @owned $FakeOptional<Builtin.NativeObject>):
%3a = unchecked_enum_data %3 : $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt
apply %f(%3a) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %3a : $Builtin.NativeObject
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// TODO: We currently are unable to get rid of the begin_borrow. We should be
// able to with appropriate analysis.
// CHECK-LABEL: sil [ossa] @switch_enum_test_copyvalue_with_borrow : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'switch_enum_test_copyvalue_with_borrow'
sil [ossa] @switch_enum_test_copyvalue_with_borrow : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>):
%f = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
%0a = begin_borrow %0 : $FakeOptional<Builtin.NativeObject>
%1 = copy_value %0a : $FakeOptional<Builtin.NativeObject>
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb1, default bb2
bb1(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb2(%3 : @owned $FakeOptional<Builtin.NativeObject>):
%3a = unchecked_enum_data %3 : $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt
apply %f(%3a) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %3a : $Builtin.NativeObject
br bb3
bb3:
end_borrow %0a : $FakeOptional<Builtin.NativeObject>
destroy_value %0 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// TODO: We can support this with time.
//
// CHECK-LABEL: sil [ossa] @do_eliminate_begin_borrow_consumed_by_guaranteed_phi : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: begin_borrow
// CHECK: } // end sil function 'do_eliminate_begin_borrow_consumed_by_guaranteed_phi'
sil [ossa] @do_eliminate_begin_borrow_consumed_by_guaranteed_phi : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
br bb1(%1 : $Builtin.NativeObject)
bb1(%2 : @guaranteed $Builtin.NativeObject):
end_borrow %2 : $Builtin.NativeObject
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// Make sure we can chew through this and get rid of all ARC traffic.
// CHECK-LABEL: sil [ossa] @init_existential_ref_forwarding_test : $@convention(thin) (@guaranteed Klass) -> () {
// CHECK-NOT: copy_value
// CHECK-NOT: begin_borrow
// CHECK: } // end sil function 'init_existential_ref_forwarding_test'
sil [ossa] @init_existential_ref_forwarding_test : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
%0a = copy_value %0 : $Klass
%1 = init_existential_ref %0a : $Klass : $Klass, $MyFakeAnyObject
%1a = begin_borrow %1 : $MyFakeAnyObject
%2 = open_existential_ref %1a : $MyFakeAnyObject to $@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject
%3 = witness_method $@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject, #MyFakeAnyObject.myFakeMethod, %2 : $@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject : $@convention(witness_method: MyFakeAnyObject) <Ï„_0_0 where Ï„_0_0 : MyFakeAnyObject> (@guaranteed Ï„_0_0) -> ()
apply %3<@opened("A2E21C52-6089-11E4-9866-3C0754723233") MyFakeAnyObject>(%2) : $@convention(witness_method: MyFakeAnyObject) <Ï„_0_0 where Ï„_0_0 : MyFakeAnyObject> (@guaranteed Ï„_0_0) -> ()
end_borrow %1a : $MyFakeAnyObject
destroy_value %1 : $MyFakeAnyObject
%9999 = tuple()
return %9999 : $()
}
///////////////////
// Phi Web Tests //
///////////////////
// CHECK-LABEL: sil [ossa] @copy_of_guaranteed_simple_case : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'copy_of_guaranteed_simple_case'
sil [ossa] @copy_of_guaranteed_simple_case : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
cond_br undef, bb1, bb2
bb1:
%0a = copy_value %0 : $Klass
br bb3(%0a : $Klass)
bb2:
%1a = copy_value %1 : $Klass
br bb3(%1a : $Klass)
bb3(%2 : @owned $Klass):
%f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> ()
apply %f(%2) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %2 : $Klass
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @copy_of_guaranteed_forwarding_use : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'copy_of_guaranteed_forwarding_use'
sil [ossa] @copy_of_guaranteed_forwarding_use : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
cond_br undef, bb1, bb2
bb1:
%0a = copy_value %0 : $Klass
%0b = unchecked_ref_cast %0a : $Klass to $Klass
br bb3(%0b : $Klass)
bb2:
%1a = copy_value %1 : $Klass
%1b = unchecked_ref_cast %1a : $Klass to $Klass
br bb3(%1b : $Klass)
bb3(%2 : @owned $Klass):
%f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> ()
apply %f(%2) : $@convention(thin) (@guaranteed Klass) -> ()
destroy_value %2 : $Klass
%9999 = tuple()
return %9999 : $()
}
// A combined test of a common pattern, casting in an optional diamond.
//
// CHECK-LABEL: sil [ossa] @optional_cast_diamond : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'optional_cast_diamond'
sil [ossa] @optional_cast_diamond : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
%1 = copy_value %0 : $FakeOptional<Klass>
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb2, case #FakeOptional.none!enumelt: bb1
bb1:
%2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%2 : $FakeOptional<Klass>)
bb2(%3 : @owned $Klass):
%4 = unchecked_ref_cast %3 : $Klass to $Klass
%5 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %4 : $Klass
br bb3(%5 : $FakeOptional<Klass>)
bb3(%6 : @owned $FakeOptional<Klass>):
%f = function_ref @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
apply %f(%6) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
destroy_value %6 : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}
// A larger chained example. We can not handle this today, but we should be able
// to.
//
// CHECK-LABEL: sil [ossa] @optional_cast_diamond_chained : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'optional_cast_diamond_chained'
sil [ossa] @optional_cast_diamond_chained : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () {
bb0(%0 : @guaranteed $FakeOptional<Klass>):
%f = function_ref @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
%1 = copy_value %0 : $FakeOptional<Klass>
switch_enum %1 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb2, case #FakeOptional.none!enumelt: bb1
bb1:
%2 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%2 : $FakeOptional<Klass>)
bb2(%3 : @owned $Klass):
%4 = unchecked_ref_cast %3 : $Klass to $Klass
%5 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %4 : $Klass
br bb3(%5 : $FakeOptional<Klass>)
bb3(%6 : @owned $FakeOptional<Klass>):
apply %f(%6) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
switch_enum %6 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb5, case #FakeOptional.none!enumelt: bb4
bb4:
%2a = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb6(%2a : $FakeOptional<Klass>)
bb5(%3a : @owned $Klass):
%4a = unchecked_ref_cast %3a : $Klass to $Klass
%5a = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %4a : $Klass
br bb6(%5a : $FakeOptional<Klass>)
bb6(%6a : @owned $FakeOptional<Klass>):
apply %f(%6a) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
destroy_value %6a : $FakeOptional<Klass>
%9999 = tuple()
return %9999 : $()
}
// Make sure we do not crash here. We need to be able to think about multiple
// phi node at the same time.
//
// CHECK-LABEL: sil [ossa] @multiple_phi_node_uses_of_one_copy : $@convention(thin) (@guaranteed Klass) -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'multiple_phi_node_uses_of_one_copy'
sil [ossa] @multiple_phi_node_uses_of_one_copy : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
%1 = copy_value %0 : $Klass
cond_br undef, bb1, bb2
bb1:
br bb3(%1 : $Klass)
bb2:
br bb3(%1 : $Klass)
bb3(%2 : @owned $Klass):
destroy_value %2 : $Klass
%9999 = tuple()
return %9999 : $()
}
// Lets do a phi tree.
//
// CHECK-LABEL: sil [ossa] @copy_guaranteed_three_copy_simple : $@convention(thin) (@guaranteed Klass) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'copy_guaranteed_three_copy_simple'
sil [ossa] @copy_guaranteed_three_copy_simple : $@convention(thin) (@guaranteed Klass) -> () {
bb0(%0 : @guaranteed $Klass):
cond_br undef, bb1, bb2
bb1:
cond_br undef, bb3, bb4
bb2:
%1 = copy_value %0 : $Klass
br bb5(%1 : $Klass)
bb3:
%2 = copy_value %0 : $Klass
br bb5(%2 : $Klass)
bb4:
%3 = copy_value %0 : $Klass
br bb5(%3 : $Klass)
bb5(%end : @owned $Klass):
destroy_value %end : $Klass
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_simple : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> () {
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'cast_with_optional_result_and_default_simple'
sil [ossa] @cast_with_optional_result_and_default_simple : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> () {
bb0(%0 : @guaranteed $StructWithDataAndOwner):
%1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner
%2 = copy_value %1 : $Klass
checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2
bb1(%3 : @owned $Builtin.NativeObject):
%4 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %3 : $Builtin.NativeObject
br bb3(%4 : $FakeOptional<Builtin.NativeObject>)
bb2(%5 : @owned $Klass):
destroy_value %5 : $Klass
%6 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
br bb3(%6 : $FakeOptional<Builtin.NativeObject>)
bb3(%7 : @owned $FakeOptional<Builtin.NativeObject>):
destroy_value %7 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
// CHECK-NOT: destroy_value
// CHECK: copy_value
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'cast_with_optional_result_and_default_simple_unremoved_store'
sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
bb0(%result : $*FakeOptional<Builtin.NativeObject>, %0 : @guaranteed $StructWithDataAndOwner):
%1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner
%2 = copy_value %1 : $Klass
checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2
bb1(%3 : @owned $Builtin.NativeObject):
%4 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %3 : $Builtin.NativeObject
br bb3(%4 : $FakeOptional<Builtin.NativeObject>)
bb2(%5 : @owned $Klass):
destroy_value %5 : $Klass
%6 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
br bb3(%6 : $FakeOptional<Builtin.NativeObject>)
bb3(%7 : @owned $FakeOptional<Builtin.NativeObject>):
%8 = copy_value %7 : $FakeOptional<Builtin.NativeObject>
store %8 to [init] %result : $*FakeOptional<Builtin.NativeObject>
destroy_value %7 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// The pass visits the blocks in order, so we know that the failure to do the
// copy_value in block 1 will occur before any copy removal in later
// blocks. Lets take advantage of that to make sure that if we fail to copy
// multiple times, we ignore the duplicate copy_value in the phi list.
//
// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store_multiple_mods : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
// CHECK: copy_value
// CHECK-NOT: copy_value
// CHECK-NOT: destroy_value
// CHECK: } // end sil function 'cast_with_optional_result_and_default_simple_unremoved_store_multiple_mods'
sil [ossa] @cast_with_optional_result_and_default_simple_unremoved_store_multiple_mods : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
bb0(%result : $*FakeOptional<Builtin.NativeObject>, %0 : @guaranteed $StructWithDataAndOwner):
%1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner
%2 = copy_value %1 : $Klass
checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2
bb1(%3 : @owned $Builtin.NativeObject):
%4 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %3 : $Builtin.NativeObject
br bb3(%4 : $FakeOptional<Builtin.NativeObject>)
bb2(%5 : @owned $Klass):
destroy_value %5 : $Klass
%6 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
br bb3(%6 : $FakeOptional<Builtin.NativeObject>)
bb3(%7 : @owned $FakeOptional<Builtin.NativeObject>):
%8 = copy_value %7 : $FakeOptional<Builtin.NativeObject>
%9 = copy_value %8 : $FakeOptional<Builtin.NativeObject>
destroy_value %9 : $FakeOptional<Builtin.NativeObject>
store %8 to [init] %result : $*FakeOptional<Builtin.NativeObject>
destroy_value %7 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// We can not eliminate the copy_value here since we store it into the out
// parameter.
//
// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
// CHECK: bb0(
// CHECK: copy_value
// CHECK: checked_cast_br
// CHECK: } // end sil function 'cast_with_optional_result_and_default_and_switchenum_after'
sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after : $@convention(thin) (@guaranteed StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
bb0(%result : $*FakeOptional<Builtin.NativeObject>, %0 : @guaranteed $StructWithDataAndOwner):
%1 = struct_extract %0 : $StructWithDataAndOwner, #StructWithDataAndOwner.owner
%2 = copy_value %1 : $Klass
checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2
bb1(%3 : @owned $Builtin.NativeObject):
%4 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %3 : $Builtin.NativeObject
br bb3(%4 : $FakeOptional<Builtin.NativeObject>)
bb2(%5 : @owned $Klass):
destroy_value %5 : $Klass
%6 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
br bb3(%6 : $FakeOptional<Builtin.NativeObject>)
bb3(%7 : @owned $FakeOptional<Builtin.NativeObject>):
switch_enum %7 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb5, case #FakeOptional.none!enumelt: bb4
bb4:
%8 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
store %8 to [init] %result : $*FakeOptional<Builtin.NativeObject>
br bb6
bb5(%9 : @owned $Builtin.NativeObject):
%10 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %9 : $Builtin.NativeObject
store %10 to [init] %result : $*FakeOptional<Builtin.NativeObject>
br bb6
bb6:
%9999 = tuple()
return %9999 : $()
}
// Once we support converting struct_extract to a destructure here (since only
// one non-trivial leaf field), we should be able to optimize this case.
//
// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
// CHECK: bb0(
// CHECK: copy_value
// CHECK: checked_cast_br
// CHECK: } // end sil function 'cast_with_optional_result_and_default_and_switchenum_after_owned_arg'
sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
bb0(%result : $*FakeOptional<Builtin.NativeObject>, %0 : @owned $StructWithDataAndOwner):
%0a = begin_borrow %0 : $StructWithDataAndOwner
%1 = struct_extract %0a : $StructWithDataAndOwner, #StructWithDataAndOwner.owner
%2 = copy_value %1 : $Klass
checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2
bb1(%3 : @owned $Builtin.NativeObject):
%4 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %3 : $Builtin.NativeObject
br bb3(%4 : $FakeOptional<Builtin.NativeObject>)
bb2(%5 : @owned $Klass):
destroy_value %5 : $Klass
%6 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
br bb3(%6 : $FakeOptional<Builtin.NativeObject>)
bb3(%7 : @owned $FakeOptional<Builtin.NativeObject>):
switch_enum %7 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb5, case #FakeOptional.none!enumelt: bb4
bb4:
%8 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
store %8 to [init] %result : $*FakeOptional<Builtin.NativeObject>
br bb6
bb5(%9 : @owned $Builtin.NativeObject):
%10 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %9 : $Builtin.NativeObject
store %10 to [init] %result : $*FakeOptional<Builtin.NativeObject>
br bb6
bb6:
end_borrow %0a : $StructWithDataAndOwner
destroy_value %0 : $StructWithDataAndOwner
%9999 = tuple()
return %9999 : $()
}
// We can not eliminate this copy_value since the scope for %0a ends before the
// begin_borrow.
// CHECK-LABEL: sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg_1 : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
// CHECK: bb0(
// CHECK: copy_value
// CHECK: checked_cast_br
// CHECK: } // end sil function 'cast_with_optional_result_and_default_and_switchenum_after_owned_arg_1'
sil [ossa] @cast_with_optional_result_and_default_and_switchenum_after_owned_arg_1 : $@convention(thin) (@owned StructWithDataAndOwner) -> @out FakeOptional<Builtin.NativeObject> {
bb0(%result : $*FakeOptional<Builtin.NativeObject>, %0 : @owned $StructWithDataAndOwner):
%0a = begin_borrow %0 : $StructWithDataAndOwner
%1 = struct_extract %0a : $StructWithDataAndOwner, #StructWithDataAndOwner.owner
%2 = copy_value %1 : $Klass
checked_cast_br %2 : $Klass to Builtin.NativeObject, bb1, bb2
bb1(%3 : @owned $Builtin.NativeObject):
%4 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %3 : $Builtin.NativeObject
br bb3(%4 : $FakeOptional<Builtin.NativeObject>)
bb2(%5 : @owned $Klass):
destroy_value %5 : $Klass
%6 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
br bb3(%6 : $FakeOptional<Builtin.NativeObject>)
bb3(%7 : @owned $FakeOptional<Builtin.NativeObject>):
switch_enum %7 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt: bb5, case #FakeOptional.none!enumelt: bb4
bb4:
end_borrow %0a : $StructWithDataAndOwner
destroy_value %0 : $StructWithDataAndOwner
%8 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
store %8 to [init] %result : $*FakeOptional<Builtin.NativeObject>
br bb6
bb5(%9 : @owned $Builtin.NativeObject):
end_borrow %0a : $StructWithDataAndOwner
%9a = begin_borrow %9 : $Builtin.NativeObject
%9b = copy_value %9a : $Builtin.NativeObject
%10 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt, %9b : $Builtin.NativeObject
store %10 to [init] %result : $*FakeOptional<Builtin.NativeObject>
end_borrow %9a : $Builtin.NativeObject
destroy_value %9 : $Builtin.NativeObject
destroy_value %0 : $StructWithDataAndOwner
br bb6
bb6:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @struct_with_multiple_nontrivial_operands : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'struct_with_multiple_nontrivial_operands'
sil [ossa] @struct_with_multiple_nontrivial_operands : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObject):
%0a = copy_value %0 : $Builtin.NativeObject
%1a = copy_value %1 : $Builtin.NativeObject
%2 = struct $NativeObjectPair(%0a : $Builtin.NativeObject, %1a : $Builtin.NativeObject)
destroy_value %2 : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @tuple_with_multiple_nontrivial_operands : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'tuple_with_multiple_nontrivial_operands'
sil [ossa] @tuple_with_multiple_nontrivial_operands : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObject):
%0a = copy_value %0 : $Builtin.NativeObject
%1a = copy_value %1 : $Builtin.NativeObject
%2 = tuple (%0a : $Builtin.NativeObject, %1a : $Builtin.NativeObject)
destroy_value %2 : $(Builtin.NativeObject, Builtin.NativeObject)
%9999 = tuple()
return %9999 : $()
}
// Make sure that we properly handle this case with out parameters and don't
// crash due to the SILArgument in bb3.
//
// CHECK-LABEL: sil [ossa] @iterated_transforming_terminator : $@convention(method) (@guaranteed Builtin.NativeObject) -> @out FakeOptional<Klass> {
// CHECK-NOT: copy_value
// CHECK-NOT: @owned
// CHECK: } // end sil function 'iterated_transforming_terminator'
sil [ossa] @iterated_transforming_terminator : $@convention(method) (@guaranteed Builtin.NativeObject) -> @out FakeOptional<Klass> {
bb0(%0 : $*FakeOptional<Klass>, %1 : @guaranteed $Builtin.NativeObject):
%3 = init_enum_data_addr %0 : $*FakeOptional<Klass>, #FakeOptional.some!enumelt
%4 = copy_value %1 : $Builtin.NativeObject
checked_cast_br %4 : $Builtin.NativeObject to Klass, bb1, bb2
bb1(%7 : @owned $Klass):
%8 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %7 : $Klass
br bb3(%8 : $FakeOptional<Klass>)
bb2(%10 : @owned $Builtin.NativeObject):
destroy_value %10 : $Builtin.NativeObject
%12 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb3(%12 : $FakeOptional<Klass>)
bb3(%14 : @owned $FakeOptional<Klass>):
switch_enum %14 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb4, case #FakeOptional.none!enumelt: bb6
bb4(%16 : @owned $Klass):
%17 = begin_borrow %16 : $Klass
%18 = ref_element_addr %17 : $Klass, #Klass.base
copy_addr %18 to [initialization] %3 : $*Klass
end_borrow %17 : $Klass
destroy_value %16 : $Klass
inject_enum_addr %0 : $*FakeOptional<Klass>, #FakeOptional.some!enumelt
br bb5
bb5:
%24 = tuple ()
return %24 : $()
bb6:
inject_enum_addr %0 : $*FakeOptional<Klass>, #FakeOptional.none!enumelt
br bb5
}
// CHECK-LABEL: sil [ossa] @enum_with_indirect_case_projectbox_copyvalue_deadend : $@convention(thin) (@guaranteed StructWithEnumWithIndirectCaseField) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'enum_with_indirect_case_projectbox_copyvalue_deadend'
sil [ossa] @enum_with_indirect_case_projectbox_copyvalue_deadend : $@convention(thin) (@guaranteed StructWithEnumWithIndirectCaseField) -> () {
bb0(%0 : @guaranteed $StructWithEnumWithIndirectCaseField):
%1 = struct_extract %0 : $StructWithEnumWithIndirectCaseField, #StructWithEnumWithIndirectCaseField.field
%1a = copy_value %1 : $EnumWithIndirectCase
switch_enum %1a : $EnumWithIndirectCase, case #EnumWithIndirectCase.first!enumelt: bb1, case #EnumWithIndirectCase.second!enumelt: bb2
bb1:
%9999 = tuple()
return %9999 : $()
// NOTE: Eventually this will need to be changed when project_box has to be
// guarded by begin_borrow.
bb2(%2 : @owned ${ var Builtin.NativeObject }):
%3 = project_box %2 : ${ var Builtin.NativeObject }, 0
%4 = load [copy] %3 : $*Builtin.NativeObject
%user = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %user(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
unreachable
}
// CHECK-LABEL: sil [ossa] @enum_with_indirect_case_projectbox_loadcopy_to_loadborrow_deadend : $@convention(thin) (@in_guaranteed EnumWithIndirectCase) -> () {
// CHECK: bb0
// CHECK-NEXT: load_borrow
// CHECK: } // end sil function 'enum_with_indirect_case_projectbox_loadcopy_to_loadborrow_deadend'
sil [ossa] @enum_with_indirect_case_projectbox_loadcopy_to_loadborrow_deadend : $@convention(thin) (@in_guaranteed EnumWithIndirectCase) -> () {
bb0(%0 : $*EnumWithIndirectCase):
%1 = load [copy] %0 : $*EnumWithIndirectCase
switch_enum %1 : $EnumWithIndirectCase, case #EnumWithIndirectCase.first!enumelt: bb1, case #EnumWithIndirectCase.second!enumelt: bb2
bb1:
%9999 = tuple()
return %9999 : $()
// NOTE: Eventually this will need to be changed when project_box has to be
// guarded by begin_borrow.
bb2(%2 : @owned ${ var Builtin.NativeObject }):
%3 = project_box %2 : ${ var Builtin.NativeObject }, 0
%4 = load [copy] %3 : $*Builtin.NativeObject
%user = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %user(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
unreachable
}
// CHECK-LABEL: sil [ossa] @enum_with_indirect_case_projectbox_loadcopy_to_loadborrow_deadend_2 : $@convention(thin) (@in_guaranteed EnumWithIndirectCase) -> () {
// CHECK: bb0
// CHECK-NEXT: load_borrow
// CHECK: } // end sil function 'enum_with_indirect_case_projectbox_loadcopy_to_loadborrow_deadend_2'
sil [ossa] @enum_with_indirect_case_projectbox_loadcopy_to_loadborrow_deadend_2 : $@convention(thin) (@in_guaranteed EnumWithIndirectCase) -> () {
bb0(%0 : $*EnumWithIndirectCase):
%1 = load [copy] %0 : $*EnumWithIndirectCase
switch_enum %1 : $EnumWithIndirectCase, case #EnumWithIndirectCase.first!enumelt: bb1, case #EnumWithIndirectCase.second!enumelt: bb2
bb1:
%9999 = tuple()
return %9999 : $()
// NOTE: Eventually this will need to be changed when project_box has to be
// guarded by begin_borrow.
bb2(%2 : @owned ${ var Builtin.NativeObject }):
%3 = project_box %2 : ${ var Builtin.NativeObject }, 0
%4 = load [copy] %3 : $*Builtin.NativeObject
%user = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %user(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
destroy_value %2 : ${ var Builtin.NativeObject }
unreachable
}
// CHECK-LABEL: sil [ossa] @simple_recursive_copy_case : $@convention(thin) () -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'simple_recursive_copy_case'
sil [ossa] @simple_recursive_copy_case : $@convention(thin) () -> () {
bb0:
%f = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
%pair = apply %f() : $@convention(thin) () -> @owned NativeObjectPair
%1 = copy_value %pair : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%gUserFun = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %gUserFun(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %1 : $NativeObjectPair
destroy_value %pair : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [ossa] @simple_recursive_copy_case_2 : $@convention(thin) () -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'simple_recursive_copy_case_2'
sil [ossa] @simple_recursive_copy_case_2 : $@convention(thin) () -> () {
bb0:
%f = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
%pair = apply %f() : $@convention(thin) () -> @owned NativeObjectPair
%1 = copy_value %pair : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
destroy_value %pair : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%gUserFun = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %gUserFun(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %1 : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}
// We fail in this case since the lifetime of %pair ends too early and our
// joined lifetime analysis is too simplistic to handle this case.
//
// CHECK-LABEL: sil [ossa] @simple_recursive_copy_case_3 : $@convention(thin) () -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'simple_recursive_copy_case_3'
sil [ossa] @simple_recursive_copy_case_3 : $@convention(thin) () -> () {
bb0:
%f = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
%pair = apply %f() : $@convention(thin) () -> @owned NativeObjectPair
%1 = copy_value %pair : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%gUserFun = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %gUserFun(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
%consumeFunc = function_ref @consume_nativeobject_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
apply %consumeFunc(%pair) : $@convention(thin) (@owned NativeObjectPair) -> ()
cond_br undef, bb1, bb2
bb1:
(%1a, %1b) = destructure_struct %1 : $NativeObjectPair
%ownedUser = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %ownedUser(%1a) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %ownedUser(%1b) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
br bb3
bb2:
destroy_value %1 : $NativeObjectPair
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// This case fails due to the destructure of our parent object even though the
// lifetimes line up. We don't support destructures here yet.
//
// TODO: Handle this!
//
// CHECK-LABEL: sil [ossa] @simple_recursive_copy_case_4 : $@convention(thin) () -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'simple_recursive_copy_case_4'
sil [ossa] @simple_recursive_copy_case_4 : $@convention(thin) () -> () {
bb0:
%f = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
%pair = apply %f() : $@convention(thin) () -> @owned NativeObjectPair
%1 = copy_value %pair : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%gUserFun = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %gUserFun(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
%consumeFunc = function_ref @consume_nativeobject_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
destroy_value %1 : $NativeObjectPair
(%pair1, %pair2) = destructure_struct %pair : $NativeObjectPair
%ownedUser = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %ownedUser(%pair1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %ownedUser(%pair2) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%9999 = tuple()
return %9999 : $()
}
// This case fails due to the destructure of our parent object even though the
// lifetimes line up. We don't support destructures here yet.
//
// TODO: Handle this!
//
// CHECK-LABEL: sil [ossa] @simple_recursive_copy_case_5 : $@convention(thin) () -> () {
// CHECK: copy_value
// CHECK: } // end sil function 'simple_recursive_copy_case_5'
sil [ossa] @simple_recursive_copy_case_5 : $@convention(thin) () -> () {
bb0:
%f = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
%pair = apply %f() : $@convention(thin) () -> @owned NativeObjectPair
%1 = copy_value %pair : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
%3 = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
%gUserFun = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %gUserFun(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
%consumeFunc = function_ref @consume_nativeobject_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
(%pair1, %pair2) = destructure_struct %pair : $NativeObjectPair
%ownedUser = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> ()
destroy_value %1 : $NativeObjectPair
apply %ownedUser(%pair1) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
apply %ownedUser(%pair2) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%9999 = tuple()
return %9999 : $()
}
// We can eliminate the ARC traffic here due to lifetime joining. There is a
// test in semantic-arc-opts-redundantcopyopts.sil that shows said pass does not
// optimize this pattern.
//
// CHECK-LABEL: sil [ossa] @simple_recursive_copy_case_destroying_use_out_of_lifetime : $@convention(thin) () -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'simple_recursive_copy_case_destroying_use_out_of_lifetime'
sil [ossa] @simple_recursive_copy_case_destroying_use_out_of_lifetime : $@convention(thin) () -> () {
bb0:
%f = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
%pair = apply %f() : $@convention(thin) () -> @owned NativeObjectPair
%pairBorrow = begin_borrow %pair : $NativeObjectPair
%3 = struct_extract %pairBorrow : $NativeObjectPair, #NativeObjectPair.obj1
%gUserFun = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %gUserFun(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %pairBorrow : $NativeObjectPair
cond_br undef, bb1, bb2
bb1:
%1 = copy_value %pair : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
destroy_value %pair : $NativeObjectPair
%3a = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
apply %gUserFun(%3a) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %1 : $NativeObjectPair
br bb3
bb2:
destroy_value %pair : $NativeObjectPair
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// We handle this with lifetime joining.
//
// CHECK-LABEL: sil [ossa] @simple_recursive_copy_case_destroying_use_out_of_lifetime_2 : $@convention(thin) () -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'simple_recursive_copy_case_destroying_use_out_of_lifetime_2'
sil [ossa] @simple_recursive_copy_case_destroying_use_out_of_lifetime_2 : $@convention(thin) () -> () {
bb0:
%f = function_ref @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair
%pair = apply %f() : $@convention(thin) () -> @owned NativeObjectPair
%pairBorrow = begin_borrow %pair : $NativeObjectPair
%3 = struct_extract %pairBorrow : $NativeObjectPair, #NativeObjectPair.obj1
%gUserFun = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
apply %gUserFun(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %pairBorrow : $NativeObjectPair
cond_br undef, bb1, bb2
bb1:
%1 = copy_value %pair : $NativeObjectPair
%2 = begin_borrow %1 : $NativeObjectPair
destroy_value %pair : $NativeObjectPair
%3a = struct_extract %2 : $NativeObjectPair, #NativeObjectPair.obj1
apply %gUserFun(%3a) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
end_borrow %2 : $NativeObjectPair
destroy_value %1 : $NativeObjectPair
br bb3
bb2:
%consumePair = function_ref @consume_nativeobject_pair : $@convention(thin) (@owned NativeObjectPair) -> ()
apply %consumePair(%pair) : $@convention(thin) (@owned NativeObjectPair) -> ()
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}