mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Compute, update and handle borrowed-from instruction in various utilities and passes. Also, used borrowed-from to simplify `gatherBorrowIntroducers` and `gatherEnclosingValues`. Replace those utilities by `Value.getBorrowIntroducers` and `Value.getEnclosingValues`, which return a lazily computed Sequence of borrowed/enclosing values.
1662 lines
70 KiB
Plaintext
1662 lines
70 KiB
Plaintext
// RUN: %target-sil-opt -module-name Swift -enable-sil-verify-all -update-borrowed-from -semantic-arc-opts %s | %FileCheck %s
|
|
|
|
sil_stage raw
|
|
|
|
import Builtin
|
|
|
|
//////////////////
|
|
// Declarations //
|
|
//////////////////
|
|
|
|
typealias AnyObject = Builtin.AnyObject
|
|
protocol Error {}
|
|
|
|
enum MyNever {}
|
|
enum FakeOptional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
enum MultiPayload {
|
|
case none
|
|
case some(Builtin.NativeObject)
|
|
case another(Builtin.NativeObject)
|
|
}
|
|
|
|
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:
|
|
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:
|
|
br bb3
|
|
|
|
bb3:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @switch_enum_test_copyvalue_with_default_and_extract : $@convention(thin) (@guaranteed MultiPayload) -> () {
|
|
// 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 MultiPayload) -> () {
|
|
bb0(%0 : @guaranteed $MultiPayload):
|
|
%f = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
%1 = copy_value %0 : $MultiPayload
|
|
switch_enum %1 : $MultiPayload, case #MultiPayload.some!enumelt: bb1, default bb2
|
|
|
|
bb1(%2 : @owned $Builtin.NativeObject):
|
|
destroy_value %2 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2(%3 : @owned $MultiPayload):
|
|
%3a = unchecked_enum_data %3 : $MultiPayload, #MultiPayload.another!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 MultiPayload) -> () {
|
|
// 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 MultiPayload) -> () {
|
|
bb0(%0 : @owned $MultiPayload):
|
|
%f = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
%0a = begin_borrow %0 : $MultiPayload
|
|
%1 = copy_value %0a : $MultiPayload
|
|
switch_enum %1 : $MultiPayload, case #MultiPayload.some!enumelt: bb1, default bb2
|
|
|
|
bb1(%2 : @owned $Builtin.NativeObject):
|
|
destroy_value %2 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2(%3 : @owned $MultiPayload):
|
|
%3a = unchecked_enum_data %3 : $MultiPayload, #MultiPayload.another!enumelt
|
|
apply %f(%3a) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
destroy_value %3a : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
end_borrow %0a : $MultiPayload
|
|
destroy_value %0 : $MultiPayload
|
|
%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) Self
|
|
%3 = witness_method $@opened("A2E21C52-6089-11E4-9866-3C0754723233", MyFakeAnyObject) Self, #MyFakeAnyObject.myFakeMethod, %2 : $@opened("A2E21C52-6089-11E4-9866-3C0754723233", MyFakeAnyObject) Self : $@convention(witness_method: MyFakeAnyObject) <τ_0_0 where τ_0_0 : MyFakeAnyObject> (@guaranteed τ_0_0) -> ()
|
|
apply %3<@opened("A2E21C52-6089-11E4-9866-3C0754723233", MyFakeAnyObject) Self>(%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 Klass in %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 Klass in %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 Klass in %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 Klass in %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 Klass in %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 Klass in %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 Builtin.NativeObject in %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 [init] %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 : $()
|
|
}
|
|
|
|
// Make sure we do not convert checked_cast_br from owned to guaranteed if we
|
|
// are casting from AnyObject. This is because we may need to unwrap boxed
|
|
// AnyObject + bridging.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @cast_anyobject_donot_opt : $@convention(thin) (@guaranteed AnyObject) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @guaranteed $AnyObject):
|
|
// CHECK: [[COPIED_ARG:%.*]] = copy_value [[ARG]]
|
|
// CHECK: checked_cast_br AnyObject in [[COPIED_ARG]] :
|
|
// CHECK: } // end sil function 'cast_anyobject_donot_opt'
|
|
sil [ossa] @cast_anyobject_donot_opt : $@convention(thin) (@guaranteed AnyObject) -> () {
|
|
bb0(%0 : @guaranteed $AnyObject):
|
|
%2 = copy_value %0 : $AnyObject
|
|
checked_cast_br AnyObject in %2 : $AnyObject 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 $AnyObject):
|
|
destroy_value %5 : $AnyObject
|
|
%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 : $()
|
|
}
|
|
|
|
// SemanticARCOptVisitor::performGuaranteedCopyValueOptimization should not optimize this case.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @testDeadInterleavedBorrow : $@convention(c) () -> () {
|
|
// CHECK: [[B:%.*]] = begin_borrow [lexical] %0 : $FakeOptional<AnyObject>
|
|
// CHECK: copy_value
|
|
// CHECK: switch_enum
|
|
// CHECK: bb{{.*}}([[COPY:%.*]] : @owned $AnyObject):
|
|
// CHECK: begin_borrow [lexical] [[COPY]] : $AnyObject
|
|
// CHECK: end_borrow [[B]] : $FakeOptional<AnyObject>
|
|
// CHECK: end_borrow
|
|
// CHECK: destroy_value [[COPY]] : $AnyObject
|
|
// CHECK-LABEL: } // end sil function 'testDeadInterleavedBorrow'
|
|
sil [ossa] @testDeadInterleavedBorrow : $@convention(c) () -> () {
|
|
bb0:
|
|
%opt = apply undef() : $@convention(thin) () -> (@owned FakeOptional<AnyObject>)
|
|
%opt_borrow = begin_borrow [lexical] %opt : $FakeOptional<AnyObject>
|
|
%opt_borrow_copy = copy_value %opt_borrow : $FakeOptional<AnyObject>
|
|
switch_enum %opt_borrow_copy : $FakeOptional<AnyObject>, case #FakeOptional.some!enumelt: some, case #FakeOptional.none!enumelt: none
|
|
|
|
some(%obj : @owned $AnyObject):
|
|
%_borrow = begin_borrow [lexical] %obj : $AnyObject
|
|
end_borrow %opt_borrow : $FakeOptional<AnyObject>
|
|
end_borrow %_borrow : $AnyObject
|
|
destroy_value %obj : $AnyObject
|
|
br die
|
|
|
|
die:
|
|
unreachable
|
|
|
|
none:
|
|
end_borrow %opt_borrow : $FakeOptional<AnyObject>
|
|
br exit
|
|
|
|
exit:
|
|
destroy_value %opt : $FakeOptional<AnyObject>
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// SemanticARCOptVisitor::performGuaranteedCopyValueOptimization should not optimize this case.
|
|
//
|
|
// CHECK-LABEL: sil [ossa] @testDeadAndAliveInterleavedBorrow : $@convention(c) () -> () {
|
|
// CHECK: [[B:%.*]] = begin_borrow [lexical] %0 : $FakeOptional<AnyObject>
|
|
// CHECK: copy_value
|
|
// CHECK: switch_enum
|
|
//
|
|
// CHECK: bb{{.*}}([[COPY:%.*]] : @owned $AnyObject):
|
|
// CHECK: [[BB:%.*]] = begin_borrow [lexical] [[COPY]] : $AnyObject
|
|
//
|
|
// CHECK: try_apply undef
|
|
//
|
|
// CHECK: [[RESULT:%.*]] = apply undef(%{{.*}}) : $@convention(method) (@guaranteed AnyObject) -> @owned FakeOptional<AnyObject>
|
|
// CHECK: switch_enum [[RESULT]] : $FakeOptional<AnyObject>, case #FakeOptional.some!enumelt: {{.*}}, case #FakeOptional.none!enumelt: [[NONEBB:bb[0-9]?]]
|
|
//
|
|
// CHECK: [[NONEBB]]:
|
|
// CHECK: end_borrow [[B]] : $FakeOptional<AnyObject>
|
|
// CHECK: end_borrow [[BB]] : $AnyObject
|
|
// CHECK: destroy_value [[COPY]] : $AnyObject
|
|
// CHECK: destroy_value %0 : $FakeOptional<AnyObject>
|
|
// CHECK-LABEL: } // end sil function 'testDeadAndAliveInterleavedBorrow'
|
|
sil [ossa] @testDeadAndAliveInterleavedBorrow : $@convention(c) () -> () {
|
|
bb0:
|
|
%opt = apply undef() : $@convention(thin) () -> (@owned FakeOptional<AnyObject>)
|
|
%opt_borrow = begin_borrow [lexical] %opt : $FakeOptional<AnyObject>
|
|
%opt_borrow_copy = copy_value %opt_borrow : $FakeOptional<AnyObject>
|
|
switch_enum %opt_borrow_copy : $FakeOptional<AnyObject>, case #FakeOptional.some!enumelt: some, case #FakeOptional.none!enumelt: none
|
|
|
|
some(%obj : @owned $AnyObject):
|
|
%obj_borrow = begin_borrow [lexical] %obj : $AnyObject
|
|
%obj_borrow_copy = copy_value %obj_borrow : $AnyObject
|
|
try_apply undef(%obj_borrow_copy) : $@convention(method) (@owned AnyObject) -> (@owned AnyObject, @error Error), normal good, error bad
|
|
|
|
good(%obj2 : @owned $AnyObject):
|
|
%obj3 = apply undef(%obj2) : $@convention(method) (@guaranteed AnyObject) -> @owned FakeOptional<AnyObject>
|
|
destroy_value %obj2 : $AnyObject
|
|
switch_enum %obj3 : $FakeOptional<AnyObject>, case #FakeOptional.some!enumelt: good_some, case #FakeOptional.none!enumelt: good_none
|
|
|
|
good_some(%obj4 : @owned $AnyObject):
|
|
destroy_value %obj4 : $AnyObject
|
|
end_borrow %obj_borrow : $AnyObject
|
|
destroy_value %obj : $AnyObject
|
|
br exit
|
|
|
|
good_none:
|
|
end_borrow %opt_borrow : $FakeOptional<AnyObject>
|
|
end_borrow %obj_borrow : $AnyObject
|
|
destroy_value %obj : $AnyObject
|
|
destroy_value %opt : $FakeOptional<AnyObject>
|
|
br die
|
|
|
|
bad(%error1 : @owned $Error):
|
|
br die
|
|
|
|
die:
|
|
unreachable
|
|
|
|
none:
|
|
br exit
|
|
|
|
exit:
|
|
end_borrow %opt_borrow : $FakeOptional<AnyObject>
|
|
destroy_value %opt : $FakeOptional<AnyObject>
|
|
%res = tuple ()
|
|
return %res : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_owned_to_guaranteed_phi :
|
|
// CHECK-NOT: copy_value
|
|
// CHECK-LABEL: } // end sil function 'test_owned_to_guaranteed_phi'
|
|
sil [ossa] @test_owned_to_guaranteed_phi : $@convention(thin) (@guaranteed Klass, @guaranteed Klass) -> () {
|
|
bb0(%0 : @guaranteed $Klass, %1 : @guaranteed $Klass):
|
|
%some = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %0 : $Klass
|
|
%copysome = copy_value %some : $FakeOptional<Klass>
|
|
switch_enum %copysome : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb2, case #FakeOptional.none!enumelt: bb3
|
|
|
|
bb2(%2 : @owned $Klass):
|
|
br bb4(%2 : $Klass)
|
|
|
|
bb3:
|
|
%3 = copy_value %1 : $Klass
|
|
br bb4(%3 : $Klass)
|
|
|
|
bb4(%4 : @owned $Klass):
|
|
%b = begin_borrow %4 : $Klass
|
|
%f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> ()
|
|
apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> ()
|
|
end_borrow %b : $Klass
|
|
destroy_value %4 : $Klass
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|