| // RUN: %target-sil-opt -module-name Swift -enable-sil-verify-all -semantic-arc-opts %s | %FileCheck %s |
| |
| sil_stage canonical |
| |
| import Builtin |
| |
| ////////////////// |
| // Declarations // |
| ////////////////// |
| |
| sil @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| sil @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> () |
| |
| struct NativeObjectPair { |
| var obj1 : Builtin.NativeObject |
| var obj2 : Builtin.NativeObject |
| } |
| |
| class Klass {} |
| |
| struct MyInt { |
| var value: Builtin.Int32 |
| } |
| |
| struct AnotherStruct { |
| var i : Builtin.Int32 |
| var c : Klass |
| } |
| |
| struct StructMemberTest { |
| var c : Klass |
| var s : AnotherStruct |
| var t : (Builtin.Int32, AnotherStruct) |
| } |
| |
| enum FakeOptional<T> { |
| case none |
| case some(T) |
| } |
| |
| sil @fakeoptional_guaranteed_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () |
| |
| /////////// |
| // 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 : $() |
| } |
| |
| // Simple in_guaranteed argument load_copy. |
| // CHECK-LABEL: sil [ossa] @load_copy_from_in_guaranteed : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () { |
| // CHECK: bb0([[ARG:%.*]] : |
| // CHECK: load_borrow |
| // CHECK: load_borrow |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'load_copy_from_in_guaranteed' |
| sil [ossa] @load_copy_from_in_guaranteed : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*Builtin.NativeObject): |
| %g = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| // Simple same bb. |
| %1 = load [copy] %0 : $*Builtin.NativeObject |
| apply %g(%1) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %1 : $Builtin.NativeObject |
| |
| // Diamond. |
| %2 = load [copy] %0 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| apply %g(%2) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %2 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| destroy_value %2 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| // Consuming use blocks. |
| %3 = load [copy] %0 : $*Builtin.NativeObject |
| %4 = function_ref @owned_user : $@convention(thin) (@owned Builtin.NativeObject) -> () |
| apply %4(%3) : $@convention(thin) (@owned 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, AnotherStruct) |
| (%4, %5) = destructure_tuple %3 : $(Builtin.Int32, AnotherStruct) |
| %6 = begin_borrow %5 : $AnotherStruct |
| %7 = struct_extract %6 : $AnotherStruct, #AnotherStruct.i |
| end_borrow %6 : $AnotherStruct |
| destroy_value %5 : $AnotherStruct |
| return %7 : $Builtin.Int32 |
| } |
| |
| // Make sure that in a case where we have multiple non-trivial values passed to |
| // a forwarding instruction we do not optimize... but if we only have one (and |
| // multiple trivial arguments), we can. |
| // |
| // 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 |
| } |
| |
| // CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_no_default : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'switch_enum_test_loadcopy_no_default' |
| sil [ossa] @switch_enum_test_loadcopy_no_default : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () { |
| bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>): |
| %0a = alloc_stack $FakeOptional<Builtin.NativeObject> |
| store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject> |
| %1 = load [copy] %0a : $*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: |
| destroy_addr %0a : $*FakeOptional<Builtin.NativeObject> |
| dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_with_default : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'switch_enum_test_loadcopy_with_default' |
| sil [ossa] @switch_enum_test_loadcopy_with_default : $@convention(thin) (@owned FakeOptional<Builtin.NativeObject>) -> () { |
| bb0(%0 : @owned $FakeOptional<Builtin.NativeObject>): |
| %0a = alloc_stack $FakeOptional<Builtin.NativeObject> |
| store %0 to [init] %0a : $*FakeOptional<Builtin.NativeObject> |
| %1 = load [copy] %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>): |
| destroy_value %3 : $FakeOptional<Builtin.NativeObject> |
| br bb3 |
| |
| bb3: |
| destroy_addr %0a : $*FakeOptional<Builtin.NativeObject> |
| dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // ============================================================================ |
| // Test SemanticARC phi optimization. canEliminatePhi must recognize |
| // terminators with multiple operands. |
| |
| // CHECK-LABEL: sil [ossa] @testTypeDependentCheckCast : $@convention(thin) (@guaranteed Klass, @thick @dynamic_self Klass.Type) -> () { |
| // CHECK: bb0(%0 : @guaranteed $Klass, %1 : $@thick @dynamic_self Klass.Type): |
| // CHECK: checked_cast_br %0 : $Klass to @dynamic_self Klass, bb1, bb2 // type-defs: %1; id: %2 |
| // |
| // CHECK: bb1([[CAST:%.*]] : @guaranteed $Klass): |
| // CHECK: [[SOME:%.*]] = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, [[CAST]] : $Klass |
| // CHECK: [[BORROW:%.*]] = begin_borrow [[SOME]] : $FakeOptional<Klass> |
| // CHECK: br bb3([[BORROW]] : $FakeOptional<Klass>) |
| // |
| // CHECK: bb2([[FAIL:%.*]] : @guaranteed $Klass): |
| // CHECK-NEXT: [[NONE:%.*]] = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt |
| // CHECK-NEXT: br bb3([[NONE]] : $FakeOptional<Klass>) |
| // |
| // CHECK: bb3([[PHI:%.*]] : @guaranteed $FakeOptional<Klass>): |
| // CHECK: switch_enum [[PHI]] : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb5, case #FakeOptional.none!enumelt: bb4 |
| // |
| // CHECK: bb4: |
| // CHECK-NEXT: end_borrow [[PHI]] : $FakeOptional<Klass> |
| // CHECK-NEXT: br bb6 |
| // |
| // CHECK: bb5(%{{.*}} : @guaranteed $Klass): |
| // CHECK-NEXT: end_borrow [[PHI]] : $FakeOptional<Klass> |
| // CHECK-NEXT: br bb6 |
| // CHECK-LABEL: } // end sil function 'testTypeDependentCheckCast' |
| sil [ossa] @testTypeDependentCheckCast : $@convention(thin) (@guaranteed Klass, @thick @dynamic_self Klass.Type) -> () { |
| bb0(%0 : @guaranteed $Klass, %1 : $@thick @dynamic_self Klass.Type): |
| %2 = copy_value %0 : $Klass |
| checked_cast_br %2 : $Klass to @dynamic_self Klass, bb1, bb2 |
| |
| bb1(%4 : @owned $Klass): |
| %5 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %4 : $Klass |
| br bb3(%5 : $FakeOptional<Klass>) |
| |
| bb2(%7 : @owned $Klass): |
| destroy_value %7 : $Klass |
| %9 = enum $FakeOptional<Klass>, #FakeOptional.none!enumelt |
| br bb3(%9 : $FakeOptional<Klass>) |
| |
| bb3(%11 : @owned $FakeOptional<Klass>): |
| switch_enum %11 : $FakeOptional<Klass>, case #FakeOptional.some!enumelt: bb5, case #FakeOptional.none!enumelt: bb4 |
| |
| bb4: |
| br bb6 |
| |
| bb5(%14 : @owned $Klass): |
| destroy_value %14 : $Klass |
| br bb6 |
| |
| bb6: |
| %17 = tuple () |
| return %17 : $() |
| } |