Files
swift-mirror/test/SILOptimizer/copy-to-borrow-optimization.sil

2263 lines
84 KiB
Plaintext

// 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<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
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<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
}
class C {}
class Base {
@_hasStorage var c: C
}
class Derived : Base {
}
class Container {
@_hasStorage var b: Base
}
struct OptionalAndClass {
var o: FakeOptional<C>
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<Klass>) -> ()
sil @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> ()
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<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
}
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<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: 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<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 [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<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_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<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:
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: 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<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 [dead_end] %2 : $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 [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<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 [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<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 [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<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_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<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>):
%0d = borrowed %0c : $FakeOptional<ClassLet> from (%0: $FakeOptional<ClassLet>)
switch_enum %0d : $FakeOptional<ClassLet>, 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<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 [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<ClassLet>)
bb3(%0c : @guaranteed $FakeOptional<ClassLet>):
%0d = borrowed %0c : $FakeOptional<ClassLet> from (%0: $FakeOptional<ClassLet>)
%f2 = function_ref @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> ()
apply %f2(%0d) : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> ()
end_borrow %0d : $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 : $()
}
// 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<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):
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<NativeObjectPair>
switch_enum %1 : $FakeOptional<NativeObjectPair>, 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<NativeObjectPair>
switch_enum %1 : $FakeOptional<NativeObjectPair>, 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<C>, 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<NonTrivialStruct>) -> @owned Optional<NonTrivialStruct> {
bb0(%0 : @owned $Optional<NonTrivialStruct>):
%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<C>) -> () {
bb0(%0 : $*Optional<C>):
%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<C>)) -> () {
bb0(%0 : $*(C, Optional<C>)):
%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<C>)) -> () {
bb0(%0 : $*(C, Optional<C>)):
%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<Int>) -> () {
bb0(%0 : @guaranteed $Array<Int>):
%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
}