// RUN: %target-sil-opt -copy-to-borrow-optimization %s | %FileCheck %s // REQUIRES: macosx sil_stage canonical import Builtin import Swift ////////////////// // Declarations // ////////////////// enum MyNever {} enum FakeOptional { 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) -> () sil @get_native_object : $@convention(thin) () -> @owned Builtin.NativeObject sil [ossa] @get_enum : $@convention(thin) () -> @owned EnumA struct NativeObjectPair { var obj1 : Builtin.NativeObject var obj2 : Builtin.NativeObject } sil @get_object_pair : $@convention(thin) () -> @owned NativeObjectPair struct FakeOptionalNativeObjectPairPair { var pair1 : FakeOptional var pair2 : FakeOptional } 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 } class C {} class Base { @_hasStorage var c: C } class Derived : Base { } class Container { @_hasStorage var b: Base } struct OptionalAndClass { var o: FakeOptional var c: C } enum MultiPayload { case a(Klass) case b(MyInt) } sil @getC : $@convention(thin) () -> (@owned C) extension Klass : MyFakeAnyObject { func myFakeMethod() } struct NonTrivialStruct { var val: Klass } sil @getKlass : $@convention(thin) () -> @owned Klass sil @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () sil @use_inguaranteed : $@convention(thin) (@in_guaranteed Klass) -> () sil @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional) -> () sil @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional) -> () sil @closure : $@convention(thin) (@inout_aliasable Klass) -> () sil @lendC : $@yield_once_2 @convention(thin) () -> @yields @guaranteed C sil @useC : $@convention(thin) (@guaranteed C) -> () { [global:] } 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 @_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 } struct TrivialStruct { } enum EnumA { case none case sometrivial(TrivialStruct) case somenontrivial(NonTrivialStruct) } struct StructWithEnum { var val: EnumA } sil @get_fakeoptional_nativeobject : $@convention(thin) () -> @owned FakeOptional 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: begin_borrow // CHECK-NEXT: apply // CHECK-NEXT: end_borrow // 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 [immutable] %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: begin_borrow // CHECK-NEXT: apply // CHECK-NEXT: end_borrow // 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 [immutable] %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: begin_borrow // CHECK-NEXT: apply // CHECK-NEXT: end_borrow // 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 [immutable] %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: begin_borrow // CHECK-NEXT: apply // CHECK-NEXT: end_borrow // 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: begin_borrow // CHECK-NEXT: apply // CHECK-NEXT: end_borrow // 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 [immutable] %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_properties_with_guaranteed_base_unreachable : // CHECK: ref_element_addr // CHECK-NEXT: load [copy] // CHECK-NEXT: apply // CHECK-NEXT: unreachable sil [ossa] @do_copy_var_properties_with_guaranteed_base_unreachable : $@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) -> () unreachable } // 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 [immutable] %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 [immutable] %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 [immutable] %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: [[INNER2:%.*]] = begin_borrow [[INNER]] // CHECK-NEXT: apply // CHECK-NEXT: end_borrow [[INNER2]] // 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 [immutable] %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 [immutable] %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: begin_borrow // CHECK-NEXT: apply // CHECK-NEXT: end_borrow // CHECK-NEXT: destroy_value // CHECK-NEXT: apply // CHECK-NEXT: end_borrow // 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 [immutable] %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: [[INNER2:%.*]] = begin_borrow [[INNER]] // CHECK-NEXT: apply // CHECK-NEXT: end_borrow [[INNER2]] // 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 [immutable] %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) -> () %w2 = enum $FakeOptional, #FakeOptional.some!enumelt, %w : $Klass apply %f2(%w2) : $@convention(thin) (@guaranteed FakeOptional) -> () destroy_value %w2 : $FakeOptional 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 [immutable] [[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 [immutable] %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_borrow // 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 : $() } // CHECK-LABEL: sil [ossa] @single_init_different_block : $@convention(thin) (@owned Klass) -> () { // CHECK: load_borrow // CHECK: } // end sil function 'single_init_different_block' sil [ossa] @single_init_different_block : $@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 : $() } // CHECK-LABEL: sil [ossa] @single_init_loadtake : $@convention(thin) (@owned Klass) -> () { // CHECK: load_borrow // CHECK: load [take] // 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 : $() } // CHECK-LABEL: sil [ossa] @inout_argument_never_written_to_begin_access_1 : $@convention(thin) (@inout NativeObjectPair, @guaranteed Builtin.NativeObject) -> () { // CHECK: load_borrow // 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] %2a : $*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_borrow // CHECK: bb2: // CHECK: apply // CHECK-NEXT: end_borrow // CHECK: bb3: // CHECK-NEXT: end_borrow // 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 bb1 bb1: %3 = load [copy] %2a : $*Builtin.NativeObject cond_br undef, bb2, bb3 bb2: %5 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () apply %5(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () destroy_value %3 : $Builtin.NativeObject br bb4 bb3: destroy_value %3 : $Builtin.NativeObject br bb4 bb4: end_access %2a : $*Builtin.NativeObject %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_no_default : $@convention(thin) (@owned FakeOptional) -> () { // 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) -> () { bb0(%0 : @owned $FakeOptional): %0a = alloc_stack $FakeOptional store %0 to [init] %0a : $*FakeOptional %1 = load [copy] %0a : $*FakeOptional switch_enum %1 : $FakeOptional, 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 dealloc_stack %0a : $*FakeOptional %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @switch_enum_multi_payload : // CHECK: %1 = load_borrow %0 // CHECK: bb1(%3 : @guaranteed $Klass): // CHECK-NEXT: end_borrow %1 // CHECK: bb2(%6 : $MyInt): // CHECK-NEXT: end_borrow %1 // CHECK: } // end sil function 'switch_enum_multi_payload' sil [ossa] @switch_enum_multi_payload : $@convention(thin) (@inout MultiPayload) -> () { bb0(%0 : $*MultiPayload): %1 = load [copy] %0 : $*MultiPayload switch_enum %1 : $MultiPayload, case #MultiPayload.a!enumelt: bb1, case #MultiPayload.b!enumelt: bb2 bb1(%3 : @owned $Klass): destroy_value %3 : $Klass br bb3 bb2(%6 : $MyInt): br bb3 bb3: %8 = tuple() return %8 : $() } // CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_with_default : $@convention(thin) (@owned FakeOptional) -> () { // 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) -> () { bb0(%0 : @owned $FakeOptional): %0a = alloc_stack $FakeOptional store %0 to [init] %0a : $*FakeOptional %1 = load [copy] %0a : $*FakeOptional switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, default bb2 bb1(%2 : @owned $Builtin.NativeObject): destroy_value %2 : $Builtin.NativeObject br bb3 bb2: br bb3 bb3: destroy_addr %0a : $*FakeOptional dealloc_stack %0a : $*FakeOptional %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @switch_enum_test_loadcopy_with_leaked_enum_case : $@convention(thin) (@owned FakeOptional) -> () { // CHECK: load_borrow // 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) -> () { bb0(%0 : @owned $FakeOptional): %0a = alloc_stack $FakeOptional store %0 to [init] %0a : $*FakeOptional %1 = load [copy] %0a : $*FakeOptional switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 bb1(%2 : @owned $Builtin.NativeObject): destroy_value [dead_end] %2 : $Builtin.NativeObject unreachable bb2: br bb3 bb3: destroy_addr %0a : $*FakeOptional dealloc_stack %0a : $*FakeOptional %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_functionarg : $@convention(thin) (@guaranteed FakeOptional) -> () { // 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) -> () { bb0(%0 : @guaranteed $FakeOptional): %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () switch_enum %0 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 bb1(%1 : @guaranteed $ClassLet): %2 = ref_element_addr [immutable] %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) -> () { // 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) -> () { bb0(%0 : @owned $FakeOptional): %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () %0a = begin_borrow %0 : $FakeOptional switch_enum %0a : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 bb1(%1 : @guaranteed $ClassLet): %2 = ref_element_addr [immutable] %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 destroy_value %0 : $FakeOptional %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @convert_load_copy_to_load_borrow_despite_switch_enum_loadborrow : $@convention(thin) (@in_guaranteed FakeOptional) -> () { // 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) -> () { bb0(%0 : $*FakeOptional): %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () %0a = load_borrow %0 : $*FakeOptional switch_enum %0a : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 bb1(%1 : @guaranteed $ClassLet): %2 = ref_element_addr [immutable] %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 %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) -> () { // CHECK: load_borrow // 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) -> () { bb0(%0 : @owned $FakeOptional): %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () cond_br undef, bb0a, bb0b bb0a: %0a = begin_borrow %0 : $FakeOptional br bb0c(%0a : $FakeOptional) bb0b: %0b = begin_borrow %0 : $FakeOptional br bb0c(%0b : $FakeOptional) bb0c(%0c : @guaranteed $FakeOptional): %0d = borrowed %0c : $FakeOptional from (%0: $FakeOptional) switch_enum %0d : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 bb1(%1 : @guaranteed $ClassLet): %2 = ref_element_addr [immutable] %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 %0d : $FakeOptional destroy_value %0 : $FakeOptional %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) -> () { // 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) -> () { bb0(%0 : @owned $FakeOptional): %f = function_ref @black_hole : $@convention(thin) (@guaranteed Klass) -> () cond_br undef, bb1, bb2 bb1: %0a = begin_borrow %0 : $FakeOptional br bb3(%0a : $FakeOptional) bb2: %0b = begin_borrow %0 : $FakeOptional %0b2 = unchecked_enum_data %0b : $FakeOptional, #FakeOptional.some!enumelt %2 = ref_element_addr [immutable] %0b2 : $ClassLet, #ClassLet.aLet %3 = load [copy] %2 : $*Klass apply %f(%3) : $@convention(thin) (@guaranteed Klass) -> () destroy_value %3 : $Klass br bb3(%0b : $FakeOptional) bb3(%0c : @guaranteed $FakeOptional): %0d = borrowed %0c : $FakeOptional from (%0: $FakeOptional) %f2 = function_ref @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional) -> () apply %f2(%0d) : $@convention(thin) (@guaranteed FakeOptional) -> () end_borrow %0d : $FakeOptional destroy_value %0 : $FakeOptional %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 : $() } // CHECK-LABEL: sil [ossa] @loadcopy_to_loadborrow_from_mut_access_with_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_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 %9 = load [copy] %8 : $*FakeOptional end_access %8 : $*FakeOptional end_borrow %6 : $ClassLet destroy_value %5 : $ClassLet switch_enum %9 : $FakeOptional, case #FakeOptional.none!enumelt: bb1, case #FakeOptional.some!enumelt: bb2 bb1: %107 = tuple () return %107 : $() bb2(%39 : @owned $Klass): destroy_value [dead_end] %39 : $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 switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, default bb2 bb2: 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 switch_enum %1 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, default bb2 bb2: 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 // // CHECK-LABEL: sil [ossa] @improper_dead_end_block_crasher_test : $@convention(thin) (Builtin.RawPointer) -> () { // CHECK: } // end sil function 'improper_dead_end_block_crasher_test' sil [ossa] @improper_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 } // Make sure that we ignore type dependent operands when walking through the use // list to determine if we are writing to a piece of memory. protocol HasClassProperty { var c: Klass { get set } } struct HasClassPropertyWrapper { var h: HasClassProperty var otherProperty: Builtin.NativeObject } sil @use_hasclassproperty : $@convention(method) <τ_0_0 where τ_0_0 : HasClassProperty> (@inout τ_0_0) -> (@owned Builtin.NativeObject, @error Error) // Make sure we don't crash on this code. We used to crash by not ignoring the // type dependent operand usage of %2. // // CHECK-LABEL: sil [ossa] @use_class_property_wrapper : $@convention(thin) (@inout HasClassPropertyWrapper) -> () { // CHECK: load_borrow // CHECK: } // end sil function 'use_class_property_wrapper' sil [ossa] @use_class_property_wrapper : $@convention(thin) (@inout HasClassPropertyWrapper) -> () { bb0(%0 : $*HasClassPropertyWrapper): %1 = struct_element_addr %0 : $*HasClassPropertyWrapper, #HasClassPropertyWrapper.h %2 = open_existential_addr mutable_access %1 : $*HasClassProperty to $*@opened("85AB1D00-DF62-11EB-A413-ACDE48001122", HasClassProperty) Self %3 = function_ref @use_hasclassproperty : $@convention(method) <τ_0_0 where τ_0_0 : HasClassProperty> (@inout τ_0_0) -> (@owned Builtin.NativeObject, @error Error) %4 = struct_element_addr %0 : $*HasClassPropertyWrapper, #HasClassPropertyWrapper.otherProperty %5 = load [copy] %4 : $*Builtin.NativeObject %f2 = function_ref @guaranteed_user : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () apply %f2(%5) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () try_apply %3<@opened("85AB1D00-DF62-11EB-A413-ACDE48001122", HasClassProperty) Self>(%2) : $@convention(method) <τ_0_0 where τ_0_0 : HasClassProperty> (@inout τ_0_0) -> (@owned Builtin.NativeObject, @error Error), normal bb1, error bb2 bb1(%str : @owned $Builtin.NativeObject): destroy_value %str : $Builtin.NativeObject destroy_value %5 : $Builtin.NativeObject br bb3 bb2(%error : @owned $Error): destroy_value %error : $Error destroy_value %5 : $Builtin.NativeObject br bb3 bb3: %9999 = tuple() return %9999 : $() } // Make sure we don't crash on this code. We used to crash for @out args on the access path to the load sil [ossa] @test_opt_out_arg : $@convention(thin)(@in NonTrivialStruct) -> (@out NonTrivialStruct) { bb0(%0 : $*NonTrivialStruct, %1 : $*NonTrivialStruct): copy_addr %1 to [init] %0 : $*NonTrivialStruct %ele = struct_element_addr %0 : $*NonTrivialStruct, #NonTrivialStruct.val %ld = load [copy] %ele : $*Klass destroy_value %ld : $Klass destroy_addr %1 : $*NonTrivialStruct %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @switch_enum_test : // CHECK: load [copy] // CHECK: } // end sil function 'switch_enum_test' sil [ossa] @switch_enum_test : $@convention(thin) (@inout StructWithEnum) -> () { bb0(%0 : $*StructWithEnum): %1 = struct_element_addr %0 : $*StructWithEnum, #StructWithEnum.val %2 = struct_element_addr %0 : $*StructWithEnum, #StructWithEnum.val %3 = load [copy] %2 : $*EnumA destroy_addr %1 : $*EnumA switch_enum %3 : $EnumA, case #EnumA.sometrivial!enumelt: bb1, case #EnumA.somenontrivial!enumelt:bb2, case #EnumA.none!enumelt: bb3 bb1(%6 : $TrivialStruct): %f = function_ref @get_enum : $@convention(thin) () -> @owned EnumA %r = apply %f() : $@convention(thin) () -> @owned EnumA %ele = struct_element_addr %0 : $*StructWithEnum, #StructWithEnum.val store %r to [init] %ele :$*EnumA %9999 = tuple() return %9999 : $() bb2(%7 : @owned $NonTrivialStruct): destroy_value [dead_end] %7 : $NonTrivialStruct unreachable bb3: unreachable } // CHECK-LABEL: sil [ossa] @promote_moved_from_load_copy : {{.*}} { // CHECK: [[ADDR:%[^,]+]] = alloc_stack $C // CHECK: [[GET_C:%[^,]+]] = function_ref @getC // CHECK: [[STORED:%[^,]+]] = apply [[GET_C]]() // CHECK: store [[STORED]] to [init] [[ADDR]] // CHECK: [[LOADED:%[^,]+]] = load_borrow [[ADDR]] // CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [lexical] [[LOADED]] // CHECK: end_borrow [[LIFETIME]] // CHECK: end_borrow [[LOADED]] // CHECK: destroy_addr [[ADDR]] // CHECK: dealloc_stack [[ADDR]] // CHECK-LABEL: } // end sil function 'promote_moved_from_load_copy' sil [ossa] @promote_moved_from_load_copy : $@convention(thin) () -> () { bb0: %addr = alloc_stack $C %getC = function_ref @getC : $@convention(thin) () -> (@owned C) %stored = apply %getC() : $@convention(thin) () -> (@owned C) store %stored to [init] %addr : $*C %loaded = load [copy] %addr : $*C debug_value %loaded : $C, let, name "x" %lifetime = move_value [lexical] %loaded : $C destroy_value %lifetime : $C destroy_addr %addr : $*C dealloc_stack %addr : $*C %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @dont_promote_moved_from_load_copy_with_destroy_addr_above_range : {{.*}} { // CHECK: load [copy] // CHECK-LABEL: } // end sil function 'dont_promote_moved_from_load_copy_with_destroy_addr_above_range' sil [ossa] @dont_promote_moved_from_load_copy_with_destroy_addr_above_range : $@convention(thin) () -> () { bb0: %addr = alloc_stack $C %getC = function_ref @getC : $@convention(thin) () -> (@owned C) %stored = apply %getC() : $@convention(thin) () -> (@owned C) store %stored to [init] %addr : $*C %loaded = load [copy] %addr : $*C destroy_addr %addr : $*C %lifetime = move_value [lexical] %loaded : $C destroy_value %lifetime : $C dealloc_stack %addr : $*C %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @load_take_between_load_copy_and_move_inout : {{.*}} { // CHECK: load [copy] // CHECK-LABEL: } // end sil function 'load_take_between_load_copy_and_move_inout' sil [ossa] @load_take_between_load_copy_and_move_inout : $@convention(thin) (@inout C) -> () { entry(%addr : $*C): %v1 = load [copy] %addr : $*C %v2 = load [take] %addr : $*C %m1 = move_value [lexical] %v1 : $C destroy_value %m1 : $C store %v2 to [init] %addr : $*C %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @load_take_between_load_copy_and_move_stack : {{.*}} { // CHECK: load [copy] // CHECK-LABEL: } // end sil function 'load_take_between_load_copy_and_move_stack' sil [ossa] @load_take_between_load_copy_and_move_stack : $@convention(thin) () -> () { entry: %addr = alloc_stack $C %getC = function_ref @getC : $@convention(thin) () -> (@owned C) %stored = apply %getC() : $@convention(thin) () -> (@owned C) store %stored to [init] %addr : $*C %v1 = load [copy] %addr : $*C %v2 = load [take] %addr : $*C %m1 = move_value [lexical] %v1 : $C destroy_value %m1 : $C store %v2 to [init] %addr : $*C destroy_addr %addr : $*C dealloc_stack %addr : $*C %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @store_borrow_unaliased : // CHECK: load_borrow // CHECK-LABEL: } // end sil function 'store_borrow_unaliased' sil [ossa] @store_borrow_unaliased : $@convention(thin) (@guaranteed C, @in_guaranteed C) -> () { bb0(%0 : @guaranteed $C, %1 : $*C): %2 = alloc_stack $C %3 = store_borrow %0 to %2 : $*C %4 = load [copy] %1 : $*C end_borrow %3 : $*C destroy_value %4 : $C dealloc_stack %2 : $*C %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @store_borrow_aliased : // CHECK: load [copy] // CHECK-LABEL: } // end sil function 'store_borrow_aliased' sil [ossa] @store_borrow_aliased : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : @guaranteed $C): %1 = alloc_stack $C %2 = store_borrow %0 to %1 : $*C %3 = load [copy] %2 : $*C end_borrow %2 : $*C destroy_value %3 : $C dealloc_stack %1 : $*C %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @load_extends_borrow_scope : // CHECK: load [copy] // CHECK-LABEL: } // end sil function 'load_extends_borrow_scope' sil [ossa] @load_extends_borrow_scope : $@convention(thin) (@owned Klass) -> @owned Klass { bb0(%0 : @owned $Klass): %1 = begin_borrow %0 : $Klass %2 = ref_element_addr %1 : $Klass, #Klass.base %3 = load [copy] %2 : $*Klass end_borrow %1 : $Klass destroy_value %3 : $Klass return %0 : $Klass } // CHECK-LABEL: sil [ossa] @write_in_unreachable_block : // CHECK: load [copy] // CHECK-LABEL: } // end sil function 'write_in_unreachable_block' sil [ossa] @write_in_unreachable_block : $@convention(thin) (@inout Klass) -> () { bb0(%0 : $*Klass): %1 = load [copy] %0 : $*Klass cond_br undef, bb1, bb2 bb1: %3 = begin_borrow %1 : $Klass %4 = ref_element_addr %3 : $Klass, #Klass.baseLet destroy_addr %0 : $*Klass %5 = load [copy] %4 : $*Klass end_borrow %3 : $Klass destroy_value [dead_end] %1 : $Klass destroy_value [dead_end] %5 : $Klass unreachable bb2: destroy_value %1 : $Klass br bb3 bb3: %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [ossa] @no_write_in_unreachable_block : // CHECK: load_borrow // CHECK-LABEL: } // end sil function 'no_write_in_unreachable_block' sil [ossa] @no_write_in_unreachable_block : $@convention(thin) (@inout Klass) -> () { bb0(%0 : $*Klass): %1 = load [copy] %0 : $*Klass cond_br undef, bb1, bb2 bb1: %3 = begin_borrow %1 : $Klass %4 = ref_element_addr %3 : $Klass, #Klass.baseLet %5 = load [copy] %4 : $*Klass unreachable bb2: destroy_value %1 : $Klass br bb3 bb3: %9999 = tuple() return %9999 : $() } // 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] @use_interior_pointer_in_deadend_block : // CHECK: load [copy] // CHECK: } // end sil function 'use_interior_pointer_in_deadend_block' sil [ossa] @use_interior_pointer_in_deadend_block : $@convention(thin) (@guaranteed ClassLet) -> () { bb0(%0 : @guaranteed $ClassLet): %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar %2 = load [copy] %1 : $*Klass %3 = begin_borrow %2 : $Klass %4 = ref_element_addr %3 : $Klass, #Klass.base cond_br undef, bb1, bb2 bb1: %f = function_ref @use_inguaranteed : $@convention(thin) (@in_guaranteed Klass) -> () apply %f(%4) : $@convention(thin) (@in_guaranteed Klass) -> () unreachable bb2: end_borrow %3 : $Klass destroy_value %2 : $Klass %r = tuple () return %r : $() } // CHECK-LABEL: sil [ossa] @use_interior_pointer_not_in_deadend_block : // CHECK: load_borrow // CHECK: } // end sil function 'use_interior_pointer_not_in_deadend_block' sil [ossa] @use_interior_pointer_not_in_deadend_block : $@convention(thin) (@guaranteed ClassLet) -> () { bb0(%0 : @guaranteed $ClassLet): %1 = ref_element_addr %0 : $ClassLet, #ClassLet.aVar %2 = load [copy] %1 : $*Klass %3 = begin_borrow %2 : $Klass %4 = ref_element_addr %3 : $Klass, #Klass.base cond_br undef, bb1, bb2 bb1: %f = function_ref @use_inguaranteed : $@convention(thin) (@in_guaranteed Klass) -> () apply %f(%1) : $@convention(thin) (@in_guaranteed Klass) -> () unreachable bb2: end_borrow %3 : $Klass destroy_value %2 : $Klass %r = tuple () return %r : $() } // CHECK-LABEL: sil [ossa] @multiple_destroys_and_switch_enum : // CHECK: bb0(%0 : $*OptionalAndClass): // CHECK-NEXT: %1 = load_borrow // CHECK-NOT: end_borrow // CHECK: bb3: // CHECK-NEXT: end_borrow %1 // CHECK: } // end sil function 'multiple_destroys_and_switch_enum' sil [ossa] @multiple_destroys_and_switch_enum : $@convention(thin) (@in_guaranteed OptionalAndClass) -> () { bb0(%0 : $*OptionalAndClass): %1 = load [copy] %0 : $*OptionalAndClass (%2, %3) = destructure_struct %1 : $OptionalAndClass switch_enum %2 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 bb1(%5 : @owned $C): destroy_value %5 : $C br bb3 bb2: br bb3 bb3: destroy_value %3 : $C %10 = tuple () return %10 : $() } // CHECK-LABEL: sil [ossa] @load_copy_with_borrow_users : // CHECK: %1 = load_borrow // CHECK: end_borrow %1 // CHECK-NEXT: tuple () // CHECK: } // end sil function 'load_copy_with_borrow_users' sil [ossa] @load_copy_with_borrow_users : $@convention(thin) (@inout Klass) -> () { bb0(%0 : $*Klass): %ld1 = load [copy] %0 : $*Klass %b = begin_borrow %ld1 : $Klass %c = copy_value %b : $Klass %stk = alloc_stack $Klass store %c to [init] %stk : $*Klass %f = function_ref @use_inguaranteed : $@convention(thin) (@in_guaranteed Klass) -> () apply %f(%stk) : $@convention(thin) (@in_guaranteed Klass) -> () %ld2 = load [take] %stk : $*Klass destroy_value %ld2 : $Klass dealloc_stack %stk : $*Klass end_borrow %b : $Klass destroy_value %ld1 : $Klass %t = tuple () return %t : $() } // CHECK-LABEL: sil [ossa] @pa_user : // CHECK: %1 = load_borrow // CHECK: %2 = begin_borrow %1 // CHECK: end_borrow %2 // CHECK-NEXT: end_borrow %1 // CHECK: } // end sil function 'pa_user' sil [ossa] @pa_user : $@convention(thin) (@inout Klass) -> () { bb0(%0 : $*Klass): %ld1 = load [copy] %0 : $*Klass %b = begin_borrow %ld1 : $Klass %c = copy_value %b : $Klass %stk = alloc_stack $Klass store %c to [init] %stk : $*Klass %f = function_ref @use_inguaranteed : $@convention(thin) (@in_guaranteed Klass) -> () apply %f(%stk) : $@convention(thin) (@in_guaranteed Klass) -> () %ld2 = load [take] %stk : $*Klass destroy_value %ld2 : $Klass dealloc_stack %stk : $*Klass end_borrow %b : $Klass destroy_value %ld1 : $Klass %closure = function_ref @closure : $@convention(thin) (@inout_aliasable Klass) -> () %pa = partial_apply [callee_guaranteed] [on_stack] %closure(%0) : $@convention(thin) (@inout_aliasable Klass) -> () destroy_value %pa : $@noescape @callee_guaranteed () -> () %t = tuple () return %t : $() } // CHECK-LABEL: sil [ossa] @not_refcount_preserving_cast : // CHECK: %1 = load [copy] %0 // CHECK: } // end sil function 'not_refcount_preserving_cast' sil [ossa] @not_refcount_preserving_cast : $@convention(thin) (@inout AnyObject) -> () { bb0(%0 : $*AnyObject): %1 = load [copy] %0 : $*AnyObject checked_cast_br AnyObject in %1 : $AnyObject to Klass, bb1, bb2 bb1(%3 : @owned $Klass): destroy_value %3 : $Klass br bb3 bb2(%6 : @owned $AnyObject): destroy_value %6 : $AnyObject br bb3 bb3: %r = tuple () return %r : $() } // CHECK-LABEL: sil [ossa] @dead_end_loop : // CHECK: %1 = load [copy] %0 // CHECK: } // end sil function 'dead_end_loop' sil [ossa] @dead_end_loop : $@convention(thin) (@inout Klass) -> () { bb0(%0 : $*Klass): %1 = load [copy] %0 : $*Klass cond_br undef, bb5, bb1 bb1: br bb2 bb2: %4 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () apply %4(%1) : $@convention(thin) (@guaranteed Klass) -> () %6 = function_ref @getKlass : $@convention(thin) () -> @owned Klass %7 = apply %6() : $@convention(thin) () -> @owned Klass store %7 to [assign] %0 : $*Klass cond_br undef, bb4, bb3 bb3: br bb2 bb4: unreachable bb5: destroy_value %1 : $Klass %r = tuple () return %r : $() } // CHECK-LABEL: sil [ossa] @blocked_by_end_borrow : // CHECK: %7 = load [copy] %6 // CHECK: } // end sil function 'blocked_by_end_borrow' sil [ossa] @blocked_by_end_borrow : $@convention(thin) (@guaranteed Container) -> () { bb0(%0 : @guaranteed $Container): %1 = function_ref @useC : $@convention(thin) (@guaranteed C) -> () %2 = ref_element_addr [immutable] %0 : $Container, #Container.b %3 = load_borrow %2 : $*Base %4 = unconditional_checked_cast %3 : $Base to Derived %5 = upcast %4 : $Derived to $Base %6 = ref_element_addr [immutable] %5 : $Base, #Base.c %7 = load [copy] %6 : $*C end_borrow %3 : $Base %9 = apply %1(%7) : $@convention(thin) (@guaranteed C) -> () destroy_value %7 : $C return %9 : $() } // CHECK-LABEL: sil [ossa] @remove_copy_of_guaranteed_arg : // CHECK: %1 = destructure_struct %0 // CHECK-NOT: destroy_value // CHECK: } // end sil function 'remove_copy_of_guaranteed_arg' sil [ossa] @remove_copy_of_guaranteed_arg : $@convention(thin) (@guaranteed NonTrivialStruct) -> @owned Klass { bb0(%0 : @guaranteed $NonTrivialStruct): %1 = copy_value %0 %2 = destructure_struct %1 %3 = begin_borrow %2 %4 = ref_element_addr %3, #Klass.base %5 = load [copy] %4 : $*Klass end_borrow %3 destroy_value %2 return %5 } // CHECK-LABEL: sil [ossa] @remove_copy_of_borrow : // CHECK: %3 = apply %2(%1) // CHECK-NOT: destroy_value // CHECK: } // end sil function 'remove_copy_of_borrow' sil [ossa] @remove_copy_of_borrow : $@convention(thin) (@owned Klass) -> @owned Klass { bb0(%0 : @owned $Klass): %1 = begin_borrow %0 %2 = copy_value %1 %3 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () %4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> () destroy_value %2 end_borrow %1 return %0 } // CHECK-LABEL: sil [ossa] @dont_remove_copy_of_borrow : // CHECK: %2 = copy_value %1 // CHECK: } // end sil function 'dont_remove_copy_of_borrow' sil [ossa] @dont_remove_copy_of_borrow : $@convention(thin) (@owned Klass) -> @owned Klass { bb0(%0 : @owned $Klass): %1 = begin_borrow %0 %2 = copy_value %1 %3 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () end_borrow %1 %4 = apply %3(%2) : $@convention(thin) (@guaranteed Klass) -> () destroy_value %2 return %0 } // CHECK-LABEL: sil [ossa] @remove_copy_of_forwarded_borrow : // CHECK: [[DS:%.*]] = destructure_struct // CHECK-NOT: copy_value // CHECK: apply {{%[0-9]+}}([[DS]]) // CHECK: } // end sil function 'remove_copy_of_forwarded_borrow' sil [ossa] @remove_copy_of_forwarded_borrow : $@convention(thin) (@owned Optional) -> @owned Optional { bb0(%0 : @owned $Optional): %1 = begin_borrow %0 switch_enum %1, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2 bb1(%3 : @guaranteed $NonTrivialStruct): %4 = destructure_struct %3 %5 = copy_value %4 %6 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () %7 = apply %6(%5) : $@convention(thin) (@guaranteed Klass) -> () destroy_value %5 br bb3 bb2: br bb3 bb3: end_borrow %1 return %0 } // CHECK-LABEL: sil [ossa] @user_in_dead_end_block : // CHECK: %2 = copy_value %1 // CHECK: } // end sil function 'user_in_dead_end_block' sil [ossa] @user_in_dead_end_block : $@convention(thin) (@owned Klass) -> @owned Klass { bb0(%0 : @owned $Klass): %1 = begin_borrow %0 %2 = copy_value %1 end_borrow %1 %4 = function_ref @guaranteed_klass_user : $@convention(thin) (@guaranteed Klass) -> () %5 = apply %4(%2) : $@convention(thin) (@guaranteed Klass) -> () unreachable } // CHECK-LABEL: sil [ossa] @end_borrows_in_liferange_exit_block : // CHECK: %1 = load_borrow %0 // CHECK: %2 = begin_borrow [lexical] %1 // CHECK: bb1({{.*}} : @guaranteed $C): // CHECK-NEXT: end_borrow %2 // CHECK-NEXT: end_borrow %1 // CHECK: bb2: // CHECK-NEXT: end_borrow %2 // CHECK-NEXT: end_borrow %1 // CHECK: } // end sil function 'end_borrows_in_liferange_exit_block' sil [ossa] @end_borrows_in_liferange_exit_block : $@convention(thin) (@in_guaranteed Optional) -> () { bb0(%0 : $*Optional): %1 = load [copy] %0 %2 = move_value [lexical] %1 switch_enum %2, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2 bb1(%4 : @owned $C): destroy_value %4 br bb3 bb2: br bb3 bb3: %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @lifetime_ending_enum_data : // CHECK: %1 = load_borrow %0 // CHECK-NEXT: %2 = unchecked_enum_data %1 // CHECK-NEXT: end_borrow %1 // CHECK: } // end sil function 'lifetime_ending_enum_data' sil [ossa] @lifetime_ending_enum_data : $@convention(method) (@in_guaranteed MultiPayload) -> MyInt { bb0(%0 : $*MultiPayload): %1 = load [copy] %0 %2 = unchecked_enum_data %1, #MultiPayload.b!enumelt return %2 } // CHECK-LABEL: sil [ossa] @duplicate_lifetime_end1 : // CHECK: load_borrow %0 // CHECK: } // end sil function 'duplicate_lifetime_end1' sil [ossa] @duplicate_lifetime_end1 : $@convention(thin) (@in_guaranteed (C, Optional)) -> () { bb0(%0 : $*(C, Optional)): %1 = load [copy] %0 (%2, %3) = destructure_tuple %1 switch_enum %3, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2 bb1(%4 : @owned $C): destroy_value %2 destroy_value %4 br bb3 bb2: debug_value %2 destroy_value %2 br bb3 bb3: %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @duplicate_lifetime_end2 : // CHECK: load_borrow %0 // CHECK: } // end sil function 'duplicate_lifetime_end2' sil [ossa] @duplicate_lifetime_end2 : $@convention(thin) (@in_guaranteed (C, Optional)) -> () { bb0(%0 : $*(C, Optional)): %1 = load [copy] %0 (%2, %3) = destructure_tuple %1 switch_enum %3, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2 bb1(%4 : @owned $C): destroy_value %2 destroy_value %4 br bb3 bb2: destroy_value %2 br bb3 bb3: %r = tuple () return %r } // CHECK-LABEL: sil [ossa] @keep_yield2ed_copy : {{.*}} { // CHECK: copy_value // CHECK: } // end sil function 'keep_yield2ed_copy' sil [ossa] @keep_yield2ed_copy : $@convention(thin) () -> () { %lendC = function_ref @lendC : $@yield_once_2 @convention(thin) () -> @yields @guaranteed C (%c, %token, %alloc) = begin_apply %lendC() : $@yield_once_2 @convention(thin) () -> @yields @guaranteed C %copy = copy_value %c : $C end_apply %token as $() dealloc_stack %alloc : $*Builtin.SILToken %useC = function_ref @useC : $@convention(thin) (@guaranteed C) -> () apply %useC(%copy) : $@convention(thin) (@guaranteed C) -> () destroy_value %copy : $C %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @borrowed_from_forward1 : {{.*}} { // CHECK-NOT: copy_value // CHECK-LABEL: } // end sil function 'borrowed_from_forward1' sil [ossa] @borrowed_from_forward1 : $@convention(thin) (@guaranteed C) -> () { bb0(%0 : @guaranteed $C): br bb1(%0) bb1(%1 : @guaranteed $C): %2 = borrowed %1 from (%0) %copy = copy_value %2 %useC = function_ref @useC : $@convention(thin) (@guaranteed C) -> () apply %useC(%copy) : $@convention(thin) (@guaranteed C) -> () destroy_value %copy %retval = tuple () return %retval : $() } // CHECK-LABEL: sil [ossa] @borrowed_from_forward2 : {{.*}} { // CHECK-NOT: copy_value // CHECK-LABEL: } // end sil function 'borrowed_from_forward2' sil [ossa] @borrowed_from_forward2 : $@convention(thin) (@guaranteed Array) -> () { bb0(%0 : @guaranteed $Array): %1 = struct_extract %0, #Array._buffer %2 = struct_extract %1, #_ArrayBuffer._storage %3 = struct_extract %2, #_BridgeStorage.rawValue %4 = unchecked_ref_cast %3 to $__ContiguousArrayStorageBase br bb1(%4) bb1(%6 : @guaranteed $__ContiguousArrayStorageBase): %7 = borrowed %6 from (%0) %8 = copy_value %7 %9 = begin_borrow %8 %10 = ref_element_addr [immutable] %9, #__ContiguousArrayStorageBase.countAndCapacity end_borrow %9 destroy_value %8 %13 = tuple () return %13 }