blob: 1682a91c2cf9236584072ee9feca971460cba54f [file] [log] [blame]
// RUN: %target-sil-opt -ownership-model-eliminator %s | %FileCheck %s
sil_stage raw
import Builtin
sil @use_native_object : $@convention(thin) (@owned Builtin.NativeObject) -> ()
sil @use_int32 : $@convention(thin) (Builtin.Int32) -> ()
enum Either<T, R> {
case left(T)
case some(R)
}
class C {}
// CHECK-LABEL: sil @load : $@convention(thin) (@in Builtin.NativeObject, @in Builtin.Int32) -> () {
// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : $*Builtin.Int32):
// CHECK: [[LOAD2:%[0-9]+]] = load [[ARG1]] : $*Builtin.NativeObject
// CHECK: strong_retain [[LOAD2]]
// CHECK: apply {{%[0-9]+}}([[LOAD2]])
// CHECK: [[LOAD3:%[0-9]+]] = load [[ARG1]] : $*Builtin.NativeObject
// CHECK: apply {{%[0-9]+}}([[LOAD3]])
// CHECK: [[LOAD4:%[0-9]+]] = load [[ARG2]] : $*Builtin.Int32
// CHECK: apply {{%[0-9]+}}([[LOAD4]])
sil [ossa] @load : $@convention(thin) (@in Builtin.NativeObject, @in Builtin.Int32) -> () {
bb0(%0 : $*Builtin.NativeObject, %1 : $*Builtin.Int32):
%use_native_object_func = function_ref @use_native_object : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%use_int32_func = function_ref @use_int32 : $@convention(thin) (Builtin.Int32) -> ()
%3 = load [copy] %0 : $*Builtin.NativeObject
apply %use_native_object_func(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%4 = load [take] %0 : $*Builtin.NativeObject
apply %use_native_object_func(%4) : $@convention(thin) (@owned Builtin.NativeObject) -> ()
%5 = load [trivial] %1 : $*Builtin.Int32
apply %use_int32_func(%5) : $@convention(thin) (Builtin.Int32) -> ()
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @store : $@convention(thin) (Builtin.NativeObject, @in Builtin.Int32, Builtin.Int32) -> @out Builtin.NativeObject {
// CHECK: bb0([[ARG1:%[0-9]+]] : $*Builtin.NativeObject, [[ARG2:%[0-9]+]] : $Builtin.NativeObject, [[ARG3:%[0-9]+]] : $*Builtin.Int32, [[ARG4:%[0-9]+]] : $Builtin.Int32):
// CHECK: strong_retain [[ARG2]]
// CHECK: strong_retain [[ARG2]]
// CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.NativeObject
// CHECK: [[OLDVAL:%[0-9]+]] = load [[ARG1]] : $*Builtin.NativeObject
// CHECK: store [[ARG2]] to [[ARG1]] : $*Builtin.NativeObject
// CHECK: strong_release [[OLDVAL]]
// CHECK: store [[ARG4]] to [[ARG3]] : $*Builtin.Int32
sil [ossa] @store : $@convention(thin) (Builtin.NativeObject, @in Builtin.Int32, Builtin.Int32) -> @out Builtin.NativeObject {
bb0(%0 : $*Builtin.NativeObject, %1 : @unowned $Builtin.NativeObject, %2 : $*Builtin.Int32, %3 : $Builtin.Int32):
%4 = copy_value %1 : $Builtin.NativeObject
%5 = copy_value %1 : $Builtin.NativeObject
store %4 to [init] %0 : $*Builtin.NativeObject
store %5 to [assign] %0 : $*Builtin.NativeObject
store %3 to [trivial] %2 : $*Builtin.Int32
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @borrow : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%[0-9]+]] : $*Builtin.NativeObject):
// CHECK: [[BORROWED_VALUE:%[0-9]+]] = load [[ARG]] : $*Builtin.NativeObject
// CHECK: unchecked_ref_cast [[BORROWED_VALUE]]
// CHECK-NOT: end_borrow
sil [ossa] @borrow : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject):
%1 = load_borrow %0 : $*Builtin.NativeObject
%2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $Builtin.NativeObject
end_borrow %1 : $Builtin.NativeObject
%3 = tuple()
return %3 : $()
}
sil @opaque_function : $@convention(thin) () -> ()
// CHECK-LABEL: sil @copy_value_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG1:%.*]] : $Builtin.NativeObject):
// CHECK: strong_retain [[ARG1]]
// CHECK: strong_release [[ARG1]]
// CHECK: return [[ARG1]]
sil [ossa] @copy_value_destroy_value : $@convention(thin) (@owned Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = function_ref @opaque_function : $@convention(thin) () -> ()
%2 = copy_value %0 : $Builtin.NativeObject
apply %1() : $@convention(thin) () -> ()
destroy_value %0 : $Builtin.NativeObject
return %2 : $Builtin.NativeObject
}
// CHECK-LABEL: sil @begin_borrow_store_borrow : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] : $Builtin.NativeObject):
// CHECK-NEXT: [[MEM:%.*]] = alloc_stack $Builtin.NativeObject
// CHECK-NEXT: store [[ARG]] to [[MEM]] : $*Builtin.NativeObject
// CHECK-NEXT: dealloc_stack [[MEM]] : $*Builtin.NativeObject
// CHECK-NEXT: strong_release [[ARG]]
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
// CHECK: } // end sil function 'begin_borrow_store_borrow'
sil [ossa] @begin_borrow_store_borrow : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
%1 = begin_borrow %0 : $Builtin.NativeObject
end_borrow %1 : $Builtin.NativeObject
%2 = alloc_stack $Builtin.NativeObject
%3 = begin_borrow %0 : $Builtin.NativeObject
store_borrow %3 to %2 : $*Builtin.NativeObject
end_borrow %3 : $Builtin.NativeObject
dealloc_stack %2 : $*Builtin.NativeObject
destroy_value %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// We no longer lower copy_unowned_value. So make sure that we actually don't.
//
// CHECK-LABEL: sil @copy_unowned_value_test : $@convention(thin) (@owned @sil_unowned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] : $@sil_unowned Builtin.NativeObject):
// CHECK-NEXT: [[STRONG:%.*]] = copy_unowned_value [[ARG]] : $@sil_unowned Builtin.NativeObject
// CHECK-NEXT: strong_release [[STRONG]] : $Builtin.NativeObject
// CHECK-NEXT: unowned_release [[ARG]] : $@sil_unowned Builtin.NativeObject
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return
sil [ossa] @copy_unowned_value_test : $@convention(thin) (@owned @sil_unowned Builtin.NativeObject) -> () {
bb0(%0 : @owned $@sil_unowned Builtin.NativeObject):
%1 = copy_unowned_value %0 : $@sil_unowned Builtin.NativeObject
destroy_value %1 : $Builtin.NativeObject
destroy_value %0 : $@sil_unowned Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @unmanaged_retain_release_test : $@convention(thin) (@owned Builtin.NativeObject, @owned C) -> () {
// CHECK: bb0([[ARG1:%.*]] : $Builtin.NativeObject, [[ARG2:%.*]] : $C):
// CHECK: strong_retain [[ARG1]] : $Builtin.NativeObject
// CHECK: autorelease_value [[ARG2]] : $C
// CHECK: strong_release [[ARG1]] : $Builtin.NativeObject
// CHECK: strong_release [[ARG1]] : $Builtin.NativeObject
// CHECK: } // end sil function 'unmanaged_retain_release_test'
sil [ossa] @unmanaged_retain_release_test : $@convention(thin) (@owned Builtin.NativeObject, @owned C) -> () {
bb0(%0 : @owned $Builtin.NativeObject, %1 : @owned $C):
unmanaged_retain_value %0 : $Builtin.NativeObject
unmanaged_autorelease_value %1 : $C
br bb1
bb1:
unmanaged_release_value %0 : $Builtin.NativeObject
destroy_value %0 : $Builtin.NativeObject
destroy_value %1 : $C
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @checked_cast_br_lowered : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0([[ARG:%.*]] : $Builtin.NativeObject):
// CHECK: checked_cast_br [[ARG]] : $Builtin.NativeObject to $C, [[SUCCBB:bb[0-9]+]], [[FAILBB:bb[0-9]+]]
//
// CHECK: [[SUCCBB]]([[CASTED_VALUE:%.*]] : $C):
// CHECK-NEXT: strong_release [[CASTED_VALUE]]
// CHECK-NEXT: br bb3
//
// CHECK: [[FAILBB]]:
// CHECK-NEXT: strong_release [[ARG]]
// CHECK-NEXT: br bb3
sil [ossa] @checked_cast_br_lowered : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
checked_cast_br %0 : $Builtin.NativeObject to $C, bb1, bb2
bb1(%1 : @owned $C):
destroy_value %1 : $C
br bb3
bb2(%2 : @owned $Builtin.NativeObject):
destroy_value %2 : $Builtin.NativeObject
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @end_lifetime_test : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK-NOT: end_lifetime {{%.*}} : $Builtin.NativeObject
sil [ossa] @end_lifetime_test : $@convention(thin) (@owned Builtin.NativeObject) -> () {
bb0(%0 : @owned $Builtin.NativeObject):
end_lifetime %0 : $Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @unchecked_ownership_conversion_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] : $Builtin.NativeObject):
// CHECK: return [[ARG]] : $Builtin.NativeObject
sil [ossa] @unchecked_ownership_conversion_test : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @owned Builtin.NativeObject {
bb0(%0 : @guaranteed $Builtin.NativeObject):
%1 = unchecked_ownership_conversion %0 : $Builtin.NativeObject, @guaranteed to @owned
return %1 : $Builtin.NativeObject
}
// CHECK-LABEL: sil @switch_enum_default_case : $@convention(thin) (@owned Either<Builtin.NativeObject, AnyObject>) -> () {
// CHECK: bb0([[ARG:%.*]] : $Either<Builtin.NativeObject, AnyObject>):
// CHECK: switch_enum [[ARG]] : $Either<Builtin.NativeObject, AnyObject>, case #Either.left!enumelt.1: [[SUCC_BB:bb[0-9]+]], default [[DEFAULT_BB:bb[0-9]+]]
//
// CHECK: [[SUCC_BB]]([[LHS:%.*]] : $Builtin.NativeObject
// CHECK: strong_release [[LHS]]
// CHECK: br [[EPILOG_BB:bb[0-9]+]]
//
// CHECK: [[DEFAULT_BB]]:
// CHECK: release_value [[ARG]]
// CHECK: br [[EPILOG_BB]]
//
// CHECK: [[EPILOG_BB]]:
// CHECK: return
// CHECK: } // end sil function 'switch_enum_default_case'
sil [ossa] @switch_enum_default_case : $@convention(thin) (@owned Either<Builtin.NativeObject, Builtin.AnyObject>) -> () {
bb0(%0 : @owned $Either<Builtin.NativeObject, Builtin.AnyObject>):
switch_enum %0 : $Either<Builtin.NativeObject, Builtin.AnyObject>, case #Either.left!enumelt.1: bb1, default bb2
bb1(%1 : @owned $Builtin.NativeObject):
destroy_value %1 : $Builtin.NativeObject
br bb3
bb2(%2 : @owned $Either<Builtin.NativeObject, Builtin.AnyObject>):
destroy_value %2 : $Either<Builtin.NativeObject, Builtin.AnyObject>
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
class TestArrayStorage {
@_hasStorage var count: Builtin.Int32
init()
}
struct TestArray {
var storage : TestArrayStorage
}
struct TestArray2 {
var storage : TestArrayStorage
var someValue : Builtin.Int32
var storage2 : TestArrayStorage
}
// CHECK-LABEL: sil @test_destructure_struct_tuple : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Builtin.Int32, TestArrayStorage) {
// CHECK: bb0([[TUPLE:%.*]] : $(Builtin.NativeObject, Builtin.Int32), [[STRUCT:%.*]] : $TestArray2):
// CHECK: [[TUP_ELT_0:%.*]] = tuple_extract [[TUPLE]] : $(Builtin.NativeObject, Builtin.Int32), 0
// CHECK: [[TUP_ELT_1:%.*]] = tuple_extract [[TUPLE]] : $(Builtin.NativeObject, Builtin.Int32), 1
// CHECK: [[STRUCT_FIELD_0:%.*]] = struct_extract [[STRUCT]] : $TestArray2, #TestArray2.storage
// CHECK: [[STRUCT_FIELD_1:%.*]] = struct_extract [[STRUCT]] : $TestArray2, #TestArray2.someValue
// CHECK: [[STRUCT_FIELD_2:%.*]] = struct_extract [[STRUCT]] : $TestArray2, #TestArray2.storage2
// CHECK: [[RESULT:%.*]] = tuple ([[TUP_ELT_0]] : {{.*}}, [[TUP_ELT_1]] : {{.*}}, [[STRUCT_FIELD_0]] : {{.*}}, [[STRUCT_FIELD_1]] : {{.*}}, [[STRUCT_FIELD_2]] : {{.*}})
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'test_destructure_struct_tuple'
sil [ossa] @test_destructure_struct_tuple : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Builtin.Int32, TestArrayStorage) {
bb0(%0 : @owned $(Builtin.NativeObject, Builtin.Int32), %1 : @owned $TestArray2):
(%2, %3) = destructure_tuple %0 : $(Builtin.NativeObject, Builtin.Int32)
(%4, %5, %6) = destructure_struct %1 : $TestArray2
%7 = tuple(%2 : $Builtin.NativeObject, %3 : $Builtin.Int32, %4 : $TestArrayStorage, %5 : $Builtin.Int32, %6 : $TestArrayStorage)
return %7 : $(Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Builtin.Int32, TestArrayStorage)
}
struct EmptyStruct {}
// We should completely eliminate the destructures here since the relevant
// aggregates are empty.
//
// CHECK-LABEL: sil @test_empty_destructure : $@convention(thin) () -> () {
// CHECK-NOT: destructure_struct
// CHECK-NOT: destructure_tuple
// CHECK: } // end sil function 'test_empty_destructure'
sil [ossa] @test_empty_destructure : $@convention(thin) () -> () {
bb0:
%0 = struct $EmptyStruct()
() = destructure_struct %0 : $EmptyStruct
%1 = tuple()
() = destructure_tuple %1 : $()
return %1 : $()
}
// CHECK-LABEL: sil [canonical] @test_destructure_struct_tuple_canonical : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Builtin.Int32, TestArrayStorage) {
// CHECK: bb0([[TUPLE:%.*]] : $(Builtin.NativeObject, Builtin.Int32), [[STRUCT:%.*]] : $TestArray2):
// CHECK: [[TUP_ELT_0:%.*]] = tuple_extract [[TUPLE]] : $(Builtin.NativeObject, Builtin.Int32), 0
// CHECK: [[TUP_ELT_1:%.*]] = tuple_extract [[TUPLE]] : $(Builtin.NativeObject, Builtin.Int32), 1
// CHECK: [[STRUCT_FIELD_0:%.*]] = struct_extract [[STRUCT]] : $TestArray2, #TestArray2.storage
// CHECK: [[STRUCT_FIELD_1:%.*]] = struct_extract [[STRUCT]] : $TestArray2, #TestArray2.someValue
// CHECK: [[STRUCT_FIELD_2:%.*]] = struct_extract [[STRUCT]] : $TestArray2, #TestArray2.storage2
// CHECK: [[RESULT:%.*]] = tuple ([[TUP_ELT_0]] : {{.*}}, [[TUP_ELT_1]] : {{.*}}, [[STRUCT_FIELD_0]] : {{.*}}, [[STRUCT_FIELD_1]] : {{.*}}, [[STRUCT_FIELD_2]] : {{.*}})
// CHECK: return [[RESULT]]
// CHECK: } // end sil function 'test_destructure_struct_tuple_canonical'
sil [canonical] [ossa] @test_destructure_struct_tuple_canonical : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Builtin.Int32, TestArrayStorage) {
bb0(%0 : @owned $(Builtin.NativeObject, Builtin.Int32), %1 : @owned $TestArray2):
(%2, %3) = destructure_tuple %0 : $(Builtin.NativeObject, Builtin.Int32)
(%4, %5, %6) = destructure_struct %1 : $TestArray2
%7 = tuple(%2 : $Builtin.NativeObject, %3 : $Builtin.Int32, %4 : $TestArrayStorage, %5 : $Builtin.Int32, %6 : $TestArrayStorage)
return %7 : $(Builtin.NativeObject, Builtin.Int32, TestArrayStorage, Builtin.Int32, TestArrayStorage)
}
// In the following test, the trivial parts do not have any actual uses... do
// not emit any value projections for them!
//
// CHECK-LABEL: sil [canonical] @test_destructure_with_only_some_uses : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, TestArrayStorage, TestArrayStorage) {
// CHECK: bb0([[ARG0:%.*]] : $(Builtin.NativeObject, Builtin.Int32), [[ARG1:%.*]] : $TestArray2):
// CHECK-NEXT: [[ARG0_0:%.*]] = tuple_extract [[ARG0]]
// CHECK-NEXT: [[STORAGE:%.*]] = struct_extract [[ARG1]] : $TestArray2, #TestArray2.storage
// CHECK-NEXT: [[STORAGE2:%.*]] = struct_extract [[ARG1]] : $TestArray2, #TestArray2.storage2
// CHECK-NEXT: [[RESULT:%.*]] = tuple ([[ARG0_0]] : ${{.*}}, [[STORAGE]] : ${{.*}}, [[STORAGE2]] : ${{.*}})
// CHECK-NEXT: return [[RESULT]]
// CHECK: } // end sil function 'test_destructure_with_only_some_uses'
sil [canonical] [ossa] @test_destructure_with_only_some_uses : $@convention(thin) (@owned (Builtin.NativeObject, Builtin.Int32), @owned TestArray2) -> @owned (Builtin.NativeObject, TestArrayStorage, TestArrayStorage) {
bb0(%0 : @owned $(Builtin.NativeObject, Builtin.Int32), %1 : @owned $TestArray2):
(%2, %3) = destructure_tuple %0 : $(Builtin.NativeObject, Builtin.Int32)
(%4, %5, %6) = destructure_struct %1 : $TestArray2
%7 = tuple (%2 : $Builtin.NativeObject, %4 : $TestArrayStorage, %6 : $TestArrayStorage)
return %7 : $(Builtin.NativeObject, TestArrayStorage, TestArrayStorage)
}
// CHECK-LABEL: sil [canonical] @test_simplify_instruction : $@convention(thin) (@owned Builtin.NativeObject, Builtin.Int32) -> @owned Builtin.NativeObject {
// CHECK: bb0([[ARG:%.*]] : $Builtin.NativeObject,
// CHECK-NEXT: return [[ARG]]
// CHECK: } // end sil function 'test_simplify_instruction'
sil [canonical] [ossa] @test_simplify_instruction : $@convention(thin) (@owned Builtin.NativeObject, Builtin.Int32) -> @owned Builtin.NativeObject {
bb0(%0 : @owned $Builtin.NativeObject, %1 : $Builtin.Int32):
%2 = tuple(%0 : $Builtin.NativeObject, %1 : $Builtin.Int32)
(%3, %4) = destructure_tuple %2 : $(Builtin.NativeObject, Builtin.Int32)
return %3 : $Builtin.NativeObject
}