| // RUN: %target-sil-opt -module-name Swift -enable-sil-verify-all -semantic-arc-opts -sil-semantic-arc-peepholes-loadcopy-to-loadborrow -sil-semantic-arc-peepholes-redundant-borrowscope-elim %s | %FileCheck %s |
| |
| // NOTE: After we run load [copy] -> load_borrow, we run one additional round of |
| // borrow scope elimination since borrow scope elimination cleans up the IR a |
| // little bit. |
| |
| sil_stage canonical |
| |
| 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> |
| sil @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| /////////// |
| // Tests // |
| /////////// |
| |
| // 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] @dont_copy_let_properties_with_guaranteed_base : |
| // CHECK: ref_element_addr |
| // CHECK-NEXT: load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: return |
| // CHECK: } // end sil function 'dont_copy_let_properties_with_guaranteed_base' |
| sil [ossa] @dont_copy_let_properties_with_guaranteed_base : $@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 [copy] %p : $*Klass |
| %b = begin_borrow %v : $Klass |
| apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> () |
| end_borrow %b : $Klass |
| destroy_value %v : $Klass |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_guaranteed_base_and_forwarding_uses : |
| // CHECK: ref_element_addr |
| // CHECK-NEXT: load_borrow |
| // CHECK-NEXT: unchecked_ref_cast |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: return |
| // CHECK: } // end sil function 'dont_copy_let_properties_with_guaranteed_base_and_forwarding_uses' |
| sil [ossa] @dont_copy_let_properties_with_guaranteed_base_and_forwarding_uses : $@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 [copy] %p : $*Klass |
| %c = unchecked_ref_cast %v : $Klass to $Klass |
| %b = begin_borrow %c : $Klass |
| apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> () |
| end_borrow %b : $Klass |
| destroy_value %c : $Klass |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_guaranteed_upcast_base : |
| // CHECK: ref_element_addr |
| // CHECK-NEXT: load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: return |
| // CHECK: } // end sil function 'dont_copy_let_properties_with_guaranteed_upcast_base' |
| sil [ossa] @dont_copy_let_properties_with_guaranteed_upcast_base : $@convention(thin) (@guaranteed SubclassLet) -> () { |
| bb0(%x : @guaranteed $SubclassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %u = upcast %x : $SubclassLet to $ClassLet |
| %p = ref_element_addr %u : $ClassLet, #ClassLet.aLet |
| %v = load [copy] %p : $*Klass |
| %b = begin_borrow %v : $Klass |
| apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> () |
| end_borrow %b : $Klass |
| destroy_value %v : $Klass |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_global : |
| // CHECK: global_addr |
| // CHECK-NEXT: load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: return |
| // CHECK-NEXT: } // end sil function 'dont_copy_let_global' |
| sil [ossa] @dont_copy_let_global : $@convention(thin) () -> () { |
| bb0: |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %p = global_addr @a_let_global : $*Klass |
| %v = load [copy] %p : $*Klass |
| %b = begin_borrow %v : $Klass |
| apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> () |
| end_borrow %b : $Klass |
| destroy_value %v : $Klass |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_guaranteed_base_structural |
| // CHECK: ref_element_addr |
| // CHECK-NEXT: tuple_element_addr |
| // CHECK-NEXT: load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: return |
| sil [ossa] @dont_copy_let_properties_with_guaranteed_base_structural : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%x : @guaranteed $ClassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %p = ref_element_addr %x : $ClassLet, #ClassLet.aLetTuple |
| %q = tuple_element_addr %p : $*(Klass, Klass), 1 |
| %v = load [copy] %q : $*Klass |
| %b = begin_borrow %v : $Klass |
| apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> () |
| end_borrow %b : $Klass |
| destroy_value %v : $Klass |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @do_copy_var_properties_with_guaranteed_base |
| // CHECK: ref_element_addr |
| // CHECK-NEXT: load [copy] |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: destroy |
| // CHECK-NEXT: return |
| sil [ossa] @do_copy_var_properties_with_guaranteed_base : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%x : @guaranteed $ClassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %p = ref_element_addr %x : $ClassLet, #ClassLet.aVar |
| %v = load [copy] %p : $*Klass |
| apply %f(%v) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %v : $Klass |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @do_copy_var_global |
| // CHECK: global_addr |
| // CHECK-NEXT: load [copy] |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: destroy |
| // CHECK-NEXT: return |
| sil [ossa] @do_copy_var_global : $@convention(thin) () -> () { |
| bb0: |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %p = global_addr @a_var_global : $*Klass |
| %v = load [copy] %p : $*Klass |
| apply %f(%v) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %v : $Klass |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates |
| // CHECK: [[OUTER:%.*]] = begin_borrow |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: [[INNER:%.*]] = load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow [[INNER]] |
| // CHECK-NEXT: end_borrow [[OUTER]] |
| // CHECK-NEXT: destroy_value |
| sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates : $@convention(thin) (@owned ClassLet) -> () { |
| bb0(%x : @owned $ClassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %a = begin_borrow %x : $ClassLet |
| %p = ref_element_addr %a : $ClassLet, #ClassLet.aLet |
| %v = load [copy] %p : $*Klass |
| apply %f(%v) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %v : $Klass |
| |
| end_borrow %a : $ClassLet |
| destroy_value %x : $ClassLet |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase : |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase' |
| sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase : $@convention(thin) (@owned ClassLet) -> () { |
| bb0(%x : @owned $ClassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %a = begin_borrow %x : $ClassLet |
| %p = ref_element_addr %a : $ClassLet, #ClassLet.aLetTuple |
| %v = load [copy] %p : $*(Klass, Klass) |
| (%v1, %v2) = destructure_tuple %v : $(Klass, Klass) |
| apply %f(%v1) : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%v2) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %v1 : $Klass |
| destroy_value %v2 : $Klass |
| end_borrow %a : $ClassLet |
| destroy_value %x : $ClassLet |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2 : |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2' |
| sil [ossa] @dont_copy_let_properties_with_borrowed_base_that_dominates_projtestcase_2 : $@convention(thin) (@owned ClassLet) -> () { |
| bb0(%x : @owned $ClassLet): |
| %f = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| |
| %a = begin_borrow %x : $ClassLet |
| %p = ref_element_addr %a : $ClassLet, #ClassLet.aLet |
| %v = load [copy] %p : $*Klass |
| %v_cast = unchecked_ref_cast %v : $Klass to $Builtin.NativeObject |
| apply %f(%v_cast) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %v_cast : $Builtin.NativeObject |
| end_borrow %a : $ClassLet |
| destroy_value %x : $ClassLet |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @dont_copy_let_properties_with_multi_borrowed_base_that_dominates |
| // CHECK: [[OUTER:%.*]] = begin_borrow |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: [[INNER:%.*]] = load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow [[INNER]] |
| // CHECK-NEXT: end_borrow [[OUTER]] |
| // CHECK-NEXT: [[OUTER:%.*]] = begin_borrow |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: [[INNER:%.*]] = load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow [[INNER]] |
| // CHECK-NEXT: end_borrow [[OUTER]] |
| // CHECK-NEXT: destroy_value |
| sil [ossa] @dont_copy_let_properties_with_multi_borrowed_base_that_dominates : $@convention(thin) (@owned ClassLet) -> () { |
| bb0(%x : @owned $ClassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %a = begin_borrow %x : $ClassLet |
| %p = ref_element_addr %a : $ClassLet, #ClassLet.aLet |
| %v = load [copy] %p : $*Klass |
| apply %f(%v) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %v : $Klass |
| end_borrow %a : $ClassLet |
| |
| %b = begin_borrow %x : $ClassLet |
| %q = ref_element_addr %b : $ClassLet, #ClassLet.aLet |
| %w = load [copy] %q : $*Klass |
| %b2 = begin_borrow %w : $Klass |
| apply %f(%b2) : $@convention(thin) (@guaranteed Klass) -> () |
| end_borrow %b2 : $Klass |
| destroy_value %w : $Klass |
| end_borrow %b : $ClassLet |
| |
| destroy_value %x : $ClassLet |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @do_copy_let_properties_with_borrowed_base_that_does_not_dominate |
| // CHECK: begin_borrow |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: load [copy] |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: destroy_value |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: destroy_value |
| sil [ossa] @do_copy_let_properties_with_borrowed_base_that_does_not_dominate : $@convention(thin) (@owned ClassLet) -> () { |
| bb0(%x : @owned $ClassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %a = begin_borrow %x : $ClassLet |
| %p = ref_element_addr %a : $ClassLet, #ClassLet.aLet |
| %v = load [copy] %p : $*Klass |
| %b = begin_borrow %v : $Klass |
| apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> () |
| |
| // End the lifetime of the base object first... |
| end_borrow %a : $ClassLet |
| destroy_value %x : $ClassLet |
| |
| // ...then end the lifetime of the copy. |
| apply %f(%b) : $@convention(thin) (@guaranteed Klass) -> () |
| |
| end_borrow %b : $Klass |
| destroy_value %v : $Klass |
| |
| return undef : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates_2 : |
| // CHECK: [[OUTER:%.*]] = begin_borrow |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: [[INNER:%.*]] = load_borrow |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: end_borrow [[INNER]] |
| // CHECK-NEXT: end_borrow [[OUTER]] |
| // CHECK-NEXT: begin_borrow |
| // CHECK-NEXT: ref_element_addr |
| // CHECK-NEXT: load [copy] |
| // CHECK-NEXT: end_borrow |
| // CHECK-NEXT: destroy_value |
| // CHECK-NEXT: // function_ref |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: enum |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: destroy_value |
| // CHECK: } // end sil function 'do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates_2' |
| sil [ossa] @do_or_dont_copy_let_properties_with_multi_borrowed_base_when_it_dominates_2 : $@convention(thin) (@owned ClassLet) -> () { |
| bb0(%x : @owned $ClassLet): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| |
| %a = begin_borrow %x : $ClassLet |
| %p = ref_element_addr %a : $ClassLet, #ClassLet.aLet |
| %v = load [copy] %p : $*Klass |
| %c = begin_borrow %v : $Klass |
| apply %f(%c) : $@convention(thin) (@guaranteed Klass) -> () |
| end_borrow %c : $Klass |
| destroy_value %v : $Klass |
| end_borrow %a : $ClassLet |
| |
| %b = begin_borrow %x : $ClassLet |
| %q = ref_element_addr %b : $ClassLet, #ClassLet.aLet |
| %w = load [copy] %q : $*Klass |
| |
| // End the lifetime of the base object first... |
| end_borrow %b : $ClassLet |
| destroy_value %x : $ClassLet |
| |
| // ...then end the lifetime of the copy. |
| %f2 = function_ref @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () |
| %w2 = enum $FakeOptional<Klass>, #FakeOptional.some!enumelt, %w : $Klass |
| apply %f2(%w2) : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> () |
| |
| destroy_value %w2 : $FakeOptional<Klass> |
| |
| return undef : $() |
| } |
| |
| // Make sure that we put the end_borrow on the load_borrow, not LHS or RHS. |
| // |
| // CHECK-LABEL: sil [ossa] @destructure_load_copy_to_load_borrow : $@convention(thin) (@guaranteed ClassLet) -> () { |
| // CHECK: bb0([[ARG:%.*]] : |
| // CHECK: [[INTERIOR_POINTER:%.*]] = ref_element_addr [[ARG]] |
| // CHECK: [[BORROWED_VAL:%.*]] = load_borrow [[INTERIOR_POINTER]] |
| // CHECK: ([[LHS:%.*]], [[RHS:%.*]]) = destructure_tuple [[BORROWED_VAL]] |
| // CHECK: apply {{%.*}}([[LHS]]) |
| // CHECK: apply {{%.*}}([[RHS]]) |
| // CHECK: end_borrow [[BORROWED_VAL]] |
| // CHECK: } // end sil function 'destructure_load_copy_to_load_borrow' |
| sil [ossa] @destructure_load_copy_to_load_borrow : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aLetTuple |
| %2 = load [copy] %1 : $*(Klass, Klass) |
| (%3, %4) = destructure_tuple %2 : $(Klass, Klass) |
| %5 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| %6 = apply %5(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| %7 = apply %5(%4) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| destroy_value %4 : $Klass |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @single_init_allocstack : $@convention(thin) (@owned Klass) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'single_init_allocstack' |
| sil [ossa] @single_init_allocstack : $@convention(thin) (@owned Klass) -> () { |
| bb0(%0 : @owned $Klass): |
| %1 = alloc_stack $Klass |
| store %0 to [init] %1 : $*Klass |
| %2 = load [copy] %1 : $*Klass |
| |
| %3 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> () |
| |
| destroy_value %2 : $Klass |
| destroy_addr %1 : $*Klass |
| dealloc_stack %1 : $*Klass |
| |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @multiple_init_allocstack : $@convention(thin) (@owned Klass) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'multiple_init_allocstack' |
| sil [ossa] @multiple_init_allocstack : $@convention(thin) (@owned Klass) -> () { |
| bb0(%0 : @owned $Klass): |
| %0a = copy_value %0 : $Klass |
| %1 = alloc_stack $Klass |
| store %0 to [init] %1 : $*Klass |
| %2 = load [copy] %1 : $*Klass |
| |
| %3 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> () |
| |
| destroy_value %2 : $Klass |
| destroy_addr %1 : $*Klass |
| |
| store %0a to [init] %1 : $*Klass |
| destroy_addr %1 : $*Klass |
| dealloc_stack %1 : $*Klass |
| |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We could support this, but for now we are keeping things simple. If we do add |
| // support, this test will need to be updated. |
| // |
| // CHECK-LABEL: sil [ossa] @single_init_wrongblock : $@convention(thin) (@owned Klass) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'single_init_wrongblock' |
| sil [ossa] @single_init_wrongblock : $@convention(thin) (@owned Klass) -> () { |
| bb0(%0 : @owned $Klass): |
| %1 = alloc_stack $Klass |
| br bb1 |
| |
| bb1: |
| store %0 to [init] %1 : $*Klass |
| %2 = load [copy] %1 : $*Klass |
| |
| %3 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> () |
| |
| destroy_value %2 : $Klass |
| destroy_addr %1 : $*Klass |
| dealloc_stack %1 : $*Klass |
| |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We could support this, but for now we are keeping things simple. If we do add |
| // support, this test will need to be updated. |
| // |
| // CHECK-LABEL: sil [ossa] @single_init_loadtake : $@convention(thin) (@owned Klass) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'single_init_loadtake' |
| sil [ossa] @single_init_loadtake : $@convention(thin) (@owned Klass) -> () { |
| bb0(%0 : @owned $Klass): |
| %1 = alloc_stack $Klass |
| store %0 to [init] %1 : $*Klass |
| %2 = load [copy] %1 : $*Klass |
| |
| %3 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> () |
| |
| destroy_value %2 : $Klass |
| |
| %4 = load [take] %1 : $*Klass |
| destroy_value %4 : $Klass |
| dealloc_stack %1 : $*Klass |
| |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_1 : $@convention(thin) (@inout NativeObjectPair) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_1' |
| sil [ossa] @inout_argument_never_written_to_1 : $@convention(thin) (@inout NativeObjectPair) -> () { |
| bb0(%0 : $*NativeObjectPair): |
| %2 = load [copy] %0 : $*NativeObjectPair |
| (%3, %4) = destructure_struct %2 : $NativeObjectPair |
| |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%4) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| |
| destroy_value %3 : $Builtin.NativeObject |
| destroy_value %4 : $Builtin.NativeObject |
| |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_2 : $@convention(thin) (@inout NativeObjectPair) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_2' |
| sil [ossa] @inout_argument_never_written_to_2 : $@convention(thin) (@inout NativeObjectPair) -> () { |
| bb0(%0 : $*NativeObjectPair): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can handle this since the store is outside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_3 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'inout_argument_never_written_to_3' |
| sil [ossa] @inout_argument_never_written_to_3 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We cannot handle this since the store is inside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_4 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_4' |
| sil [ossa] @inout_argument_never_written_to_4 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We cannot handle this since the store is inside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_4a : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_4a' |
| sil [ossa] @inout_argument_never_written_to_4a : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can handle this since the store is outside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_5 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'inout_argument_never_written_to_5' |
| sil [ossa] @inout_argument_never_written_to_5 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can handle this since the store is outside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_6 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'inout_argument_never_written_to_6' |
| sil [ossa] @inout_argument_never_written_to_6 : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can handle this since the store is outside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_6a : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'inout_argument_never_written_to_6a' |
| sil [ossa] @inout_argument_never_written_to_6a : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| br bb0a |
| |
| bb0a: |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can handle this since the store is outside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_6b : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'inout_argument_never_written_to_6b' |
| sil [ossa] @inout_argument_never_written_to_6b : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| br bb0a |
| |
| bb0a: |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can handle this since the store is outside of our region. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_6c : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'inout_argument_never_written_to_6c' |
| sil [ossa] @inout_argument_never_written_to_6c : $@convention(thin) (@inout NativeObjectPair, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @owned $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %1a = copy_value %1 : $Builtin.NativeObject |
| store %1 to [assign] %2 : $*Builtin.NativeObject |
| br bb0a |
| |
| bb0a: |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| destroy_value %3 : $Builtin.NativeObject |
| store %1a to [assign] %2 : $*Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // This case, we can not optimize since the write scope is created around our entire load [copy]. |
| // |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_1 : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_begin_access_1' |
| sil [ossa] @inout_argument_never_written_to_begin_access_1 : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @guaranteed $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %2a = begin_access [modify] [static] %2 : $*Builtin.NativeObject |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| end_access %2a : $*Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_1a : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_begin_access_1a' |
| sil [ossa] @inout_argument_never_written_to_begin_access_1a : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @guaranteed $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %2a = begin_access [modify] [static] %2 : $*Builtin.NativeObject |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| end_access %2a : $*Builtin.NativeObject |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_1b : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_begin_access_1b' |
| sil [ossa] @inout_argument_never_written_to_begin_access_1b : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @guaranteed $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %2a = begin_access [modify] [static] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| end_access %2a : $*Builtin.NativeObject |
| destroy_value %3 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_1c : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_begin_access_1c' |
| sil [ossa] @inout_argument_never_written_to_begin_access_1c : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @guaranteed $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| %2a = begin_access [modify] [static] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| end_access %2a : $*Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_2a : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_begin_access_2a' |
| sil [ossa] @inout_argument_never_written_to_begin_access_2a : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @guaranteed $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %2a = begin_access [modify] [static] %2 : $*Builtin.NativeObject |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| end_access %2a : $*Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| destroy_value %3 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_2b : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_begin_access_2b' |
| sil [ossa] @inout_argument_never_written_to_begin_access_2b : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @guaranteed $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| br bb0a |
| |
| bb0a: |
| %2a = begin_access [modify] [static] %2 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| destroy_value %3 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| end_access %2a : $*Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_2c : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'inout_argument_never_written_to_begin_access_2c' |
| sil [ossa] @inout_argument_never_written_to_begin_access_2c : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { |
| bb0(%0 : $*NativeObjectPair, %1 : @guaranteed $Builtin.NativeObject): |
| %2 = struct_element_addr %0 : $*NativeObjectPair, #NativeObjectPair.obj1 |
| %2a = begin_access [modify] [static] %2 : $*Builtin.NativeObject |
| br bb0a |
| |
| bb0a: |
| %3 = load [copy] %2 : $*Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| destroy_value %3 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| destroy_value %3 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| end_access %2a : $*Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // 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 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_with_leaked_enum_case : $@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_leaked_enum_case' |
| sil [ossa] @switch_enum_test_loadcopy_with_leaked_enum_case : $@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): |
| unreachable |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| destroy_addr %0a : $*FakeOptional<Builtin.NativeObject> |
| dealloc_stack %0a : $*FakeOptional<Builtin.NativeObject> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_functionarg : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'convert_load_copy_to_load_borrow_despite_switch_enum_functionarg' |
| sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_functionarg : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> () { |
| bb0(%0 : @guaranteed $FakeOptional<ClassLet>): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| switch_enum %0 : $FakeOptional<ClassLet>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 |
| |
| bb1(%1 : @guaranteed $ClassLet): |
| %2 = ref_element_addr %1 : $ClassLet, #ClassLet.aLet |
| %3 = load [copy] %2 : $*Klass |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_beginborrow : $@convention(thin) (@owned FakeOptional<ClassLet>) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'convert_load_copy_to_load_borrow_despite_switch_enum_beginborrow' |
| sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_beginborrow : $@convention(thin) (@owned FakeOptional<ClassLet>) -> () { |
| bb0(%0 : @owned $FakeOptional<ClassLet>): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| %0a = begin_borrow %0 : $FakeOptional<ClassLet> |
| switch_enum %0a : $FakeOptional<ClassLet>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 |
| |
| bb1(%1 : @guaranteed $ClassLet): |
| %2 = ref_element_addr %1 : $ClassLet, #ClassLet.aLet |
| %3 = load [copy] %2 : $*Klass |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| end_borrow %0a : $FakeOptional<ClassLet> |
| destroy_value %0 : $FakeOptional<ClassLet> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_loadborrow : $@convention(thin) (@in_guaranteed FakeOptional<ClassLet>) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'convert_load_copy_to_load_borrow_despite_switch_enum_loadborrow' |
| sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_loadborrow : $@convention(thin) (@in_guaranteed FakeOptional<ClassLet>) -> () { |
| bb0(%0 : $*FakeOptional<ClassLet>): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| %0a = load_borrow %0 : $*FakeOptional<ClassLet> |
| switch_enum %0a : $FakeOptional<ClassLet>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 |
| |
| bb1(%1 : @guaranteed $ClassLet): |
| %2 = ref_element_addr %1 : $ClassLet, #ClassLet.aLet |
| %3 = load [copy] %2 : $*Klass |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| end_borrow %0a : $FakeOptional<ClassLet> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // TODO: We can support this in a little bit once the rest of SemanticARCOpts is |
| // guaranteed to be safe with guaranteed phis. |
| // |
| // CHECK-LABEL: sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_guaranteedphi_1 : $@convention(thin) (@owned FakeOptional<ClassLet>) -> () { |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'convert_load_copy_to_load_borrow_despite_switch_enum_guaranteedphi_1' |
| sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_guaranteedphi_1 : $@convention(thin) (@owned FakeOptional<ClassLet>) -> () { |
| bb0(%0 : @owned $FakeOptional<ClassLet>): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| cond_br undef, bb0a, bb0b |
| |
| bb0a: |
| %0a = begin_borrow %0 : $FakeOptional<ClassLet> |
| br bb0c(%0a : $FakeOptional<ClassLet>) |
| |
| bb0b: |
| %0b = begin_borrow %0 : $FakeOptional<ClassLet> |
| br bb0c(%0b : $FakeOptional<ClassLet>) |
| |
| bb0c(%0c : @guaranteed $FakeOptional<ClassLet>): |
| switch_enum %0c : $FakeOptional<ClassLet>, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 |
| |
| bb1(%1 : @guaranteed $ClassLet): |
| %2 = ref_element_addr %1 : $ClassLet, #ClassLet.aLet |
| %3 = load [copy] %2 : $*Klass |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| end_borrow %0c : $FakeOptional<ClassLet> |
| destroy_value %0 : $FakeOptional<ClassLet> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // Make sure that if begin_borrow has a consuming end scope use, we can still |
| // eliminate load [copy]. |
| // |
| // CHECK-LABEL: sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_guaranteedphi_2 : $@convention(thin) (@owned FakeOptional<ClassLet>) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'convert_load_copy_to_load_borrow_despite_switch_enum_guaranteedphi_2' |
| sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_guaranteedphi_2 : $@convention(thin) (@owned FakeOptional<ClassLet>) -> () { |
| bb0(%0 : @owned $FakeOptional<ClassLet>): |
| %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %0a = begin_borrow %0 : $FakeOptional<ClassLet> |
| br bb3(%0a : $FakeOptional<ClassLet>) |
| |
| bb2: |
| %0b = begin_borrow %0 : $FakeOptional<ClassLet> |
| %0b2 = unchecked_enum_data %0b : $FakeOptional<ClassLet>, #FakeOptional.some!enumelt |
| %2 = ref_element_addr %0b2 : $ClassLet, #ClassLet.aLet |
| %3 = load [copy] %2 : $*Klass |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| br bb3(%0b : $FakeOptional<ClassLet>) |
| |
| bb3(%0c : @guaranteed $FakeOptional<ClassLet>): |
| %f2 = function_ref @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> () |
| apply %f2(%0c) : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> () |
| end_borrow %0c : $FakeOptional<ClassLet> |
| destroy_value %0 : $FakeOptional<ClassLet> |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @loadcopy_to_loadborrow_from_read_access : $@convention(thin) (@guaranteed ClassLet) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'loadcopy_to_loadborrow_from_read_access' |
| sil [ossa] @loadcopy_to_loadborrow_from_read_access : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar |
| %2 = begin_access [read] [dynamic] %1 : $*Klass |
| %3 = load [copy] %2 : $*Klass |
| %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| end_access %2 : $*Klass |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @loadcopy_to_loadborrow_from_mut_access_without_writes : $@convention(thin) (@guaranteed ClassLet) -> () { |
| // CHECK-NOT: load [copy] |
| // CHECK: load_borrow |
| // CHECK-NOT: load [copy] |
| // CHECK: } // end sil function 'loadcopy_to_loadborrow_from_mut_access_without_writes' |
| sil [ossa] @loadcopy_to_loadborrow_from_mut_access_without_writes : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar |
| %2 = begin_access [modify] [dynamic] %1 : $*Klass |
| %3 = load [copy] %2 : $*Klass |
| %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| end_access %2 : $*Klass |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can with time handle this case by proving that the destroy_addr is after |
| // the destroy_value. |
| // |
| // CHECK-LABEL: sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes : $@convention(thin) (@guaranteed ClassLet) -> () { |
| // CHECK-NOT: load_borrow |
| // CHECK: load [copy] |
| // CHECK-NOT: load_borrow |
| // CHECK: } // end sil function 'loadcopy_to_loadborrow_from_mut_access_with_writes' |
| sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar |
| %2 = begin_access [modify] [dynamic] %1 : $*Klass |
| %3 = load [copy] %2 : $*Klass |
| %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| destroy_addr %2 : $*Klass |
| end_access %2 : $*Klass |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We will never be able to handle this unless we can hoist the copy before the |
| // destroy_addr. Once we have begin_borrows around all interior_pointers, we can |
| // handle this version. |
| // |
| // CHECK-LABEL: sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes_2 : $@convention(thin) (@guaranteed ClassLet) -> () { |
| // CHECK-NOT: load_borrow |
| // CHECK: load [copy] |
| // CHECK-NOT: load_borrow |
| // CHECK: } // end sil function 'loadcopy_to_loadborrow_from_mut_access_with_writes_2' |
| sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes_2 : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar |
| %2 = begin_access [modify] [dynamic] %1 : $*Klass |
| %3 = load [copy] %2 : $*Klass |
| %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_addr %2 : $*Klass |
| destroy_value %3 : $Klass |
| end_access %2 : $*Klass |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We will never be able to handle this since we can't hoist the destroy_value |
| // before the guaranteed_klass_user. |
| // |
| // CHECK-LABEL: sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes_3 : $@convention(thin) (@guaranteed ClassLet) -> () { |
| // CHECK-NOT: load_borrow |
| // CHECK: load [copy] |
| // CHECK-NOT: load_borrow |
| // CHECK: } // end sil function 'loadcopy_to_loadborrow_from_mut_access_with_writes_3' |
| sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes_3 : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar |
| %2 = begin_access [modify] [dynamic] %1 : $*Klass |
| %3 = load [copy] %2 : $*Klass |
| destroy_addr %2 : $*Klass |
| %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| end_access %2 : $*Klass |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We will never be able to handle this since the end_access is before the use |
| // of %3, so we can not form a long enough load_borrow. |
| // |
| // CHECK-LABEL: sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes_4 : $@convention(thin) (@guaranteed ClassLet) -> () { |
| // CHECK-NOT: load_borrow |
| // CHECK: load [copy] |
| // CHECK-NOT: load_borrow |
| // CHECK: } // end sil function 'loadcopy_to_loadborrow_from_mut_access_with_writes_4' |
| sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_writes_4 : $@convention(thin) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar |
| %2 = begin_access [modify] [dynamic] %1 : $*Klass |
| %3 = load [copy] %2 : $*Klass |
| end_access %2 : $*Klass |
| %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %3 : $Klass |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // Make sure that we do not promote the load [copy] to a load_borrow since it |
| // has a use outside of the access scope. |
| // |
| // CHECK-LABEL: sil [ossa] @deadEndBlockDoNotPromote : $@convention(method) (@guaranteed ClassLet) -> () { |
| // CHECK: load_borrow |
| // CHECK: load [copy] |
| // CHECK: } // end sil function 'deadEndBlockDoNotPromote' |
| sil [ossa] @deadEndBlockDoNotPromote : $@convention(method) (@guaranteed ClassLet) -> () { |
| bb0(%0 : @guaranteed $ClassLet): |
| %4 = ref_element_addr %0 : $ClassLet, #ClassLet.anotherLet |
| %5 = load [copy] %4 : $*ClassLet |
| %6 = begin_borrow %5 : $ClassLet |
| %7 = ref_element_addr %6 : $ClassLet, #ClassLet.anOptionalLet |
| %8 = begin_access [read] [dynamic] %7 : $*FakeOptional<Klass> |
| %9 = load [copy] %8 : $*FakeOptional<Klass> |
| end_access %8 : $*FakeOptional<Klass> |
| end_borrow %6 : $ClassLet |
| destroy_value %5 : $ClassLet |
| switch_enum %9 : $FakeOptional<Klass>, case #FakeOptional.none!enumelt: bb1, case #FakeOptional.some!enumelt: bb2 |
| |
| bb1: |
| %107 = tuple () |
| return %107 : $() |
| |
| bb2(%39 : @owned $Klass): |
| unreachable |
| } |
| |
| // CHECK-LABEL: sil [ossa] @destructure_with_differing_lifetimes_inout_1 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { |
| // CHECK-NOT: load_borrow |
| // CHECK: } // end sil function 'destructure_with_differing_lifetimes_inout_1' |
| sil [ossa] @destructure_with_differing_lifetimes_inout_1 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { |
| bb0(%0 : $*FakeOptionalNativeObjectPairPair): |
| %0a = struct_element_addr %0 : $*FakeOptionalNativeObjectPairPair, #FakeOptionalNativeObjectPairPair.pair1 |
| %1 = load [copy] %0a : $*FakeOptional<NativeObjectPair> |
| switch_enum %1 : $FakeOptional<NativeObjectPair>, case #FakeOptional.some!enumelt: bb1, default bb2 |
| |
| bb2(%2 : @owned $FakeOptional<NativeObjectPair>): |
| destroy_value %2 : $FakeOptional<NativeObjectPair> |
| br bbEnd |
| |
| bb1(%3 : @owned $NativeObjectPair): |
| (%3a, %3b) = destructure_struct %3 : $NativeObjectPair |
| cond_br undef, bb1a, bb1b |
| |
| bb1a: |
| destroy_value %3a : $Builtin.NativeObject |
| destroy_value %3b : $Builtin.NativeObject |
| br bbEnd |
| |
| bb1b: |
| destroy_value %3a : $Builtin.NativeObject |
| %f = function_ref @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () |
| apply %f(%0) : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () |
| destroy_value %3b : $Builtin.NativeObject |
| br bbEnd |
| |
| bbEnd: |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [ossa] @destructure_with_differing_lifetimes_inout_2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { |
| // CHECK-NOT: load_borrow |
| // CHECK: } // end sil function 'destructure_with_differing_lifetimes_inout_2' |
| sil [ossa] @destructure_with_differing_lifetimes_inout_2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () { |
| bb0(%0 : $*FakeOptionalNativeObjectPairPair): |
| %0a = struct_element_addr %0 : $*FakeOptionalNativeObjectPairPair, #FakeOptionalNativeObjectPairPair.pair1 |
| %1 = load [copy] %0a : $*FakeOptional<NativeObjectPair> |
| switch_enum %1 : $FakeOptional<NativeObjectPair>, case #FakeOptional.some!enumelt: bb1, default bb2 |
| |
| bb2(%2 : @owned $FakeOptional<NativeObjectPair>): |
| destroy_value %2 : $FakeOptional<NativeObjectPair> |
| br bbEnd |
| |
| bb1(%3 : @owned $NativeObjectPair): |
| (%3a, %3b) = destructure_struct %3 : $NativeObjectPair |
| cond_br undef, bb1a, bb1b |
| |
| bb1a: |
| destroy_value %3a : $Builtin.NativeObject |
| br bb1ab |
| |
| bb1ab: |
| destroy_value %3b : $Builtin.NativeObject |
| br bbEnd |
| |
| bb1b: |
| destroy_value %3a : $Builtin.NativeObject |
| %f = function_ref @inout_user2 : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () |
| apply %f(%0) : $@convention(thin) (@inout FakeOptionalNativeObjectPairPair) -> () |
| cond_br undef, bb1ba, bb1bb |
| |
| bb1ba: |
| br bb1baEnd |
| |
| bb1bb: |
| br bb1baEnd |
| |
| bb1baEnd: |
| destroy_value %3b : $Builtin.NativeObject |
| br bbEnd |
| |
| bbEnd: |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // Just make sure that we do not crash on this code and convert the 2nd load |
| // [copy] to a load_borrow. |
| // |
| // CHECK-LABEL: sil [ossa] @inproper_dead_end_block_crasher_test : $@convention(thin) (Builtin.RawPointer) -> () { |
| // CHECK: load_borrow |
| // CHECK: load_borrow |
| // CHECK: } // end sil function 'inproper_dead_end_block_crasher_test' |
| sil [ossa] @inproper_dead_end_block_crasher_test : $@convention(thin) (Builtin.RawPointer) -> () { |
| bb0(%0 : $Builtin.RawPointer): |
| %1 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*Klass |
| %2 = load_borrow %1 : $*Klass |
| %3 = ref_element_addr %2 : $Klass, #Klass.baseLet |
| %4 = load [copy] %3 : $*Klass |
| %f = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () |
| apply %f(%4) : $@convention(thin) (@guaranteed Klass) -> () |
| destroy_value %4 : $Klass |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| unreachable |
| |
| bb2: |
| unreachable |
| } |