| // 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 : $() |
| } |
| |