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