| // RUN: %target-sil-opt -enable-sil-ownership -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: apply {{%[0-9]+}}([[LOAD2]]) |
| // CHECK: [[LOAD3:%[0-9]+]] = load [[ARG1]] : $*Builtin.NativeObject |
| // CHECK: strong_retain [[LOAD3]] |
| // CHECK: apply {{%[0-9]+}}([[LOAD3]]) |
| // CHECK: [[LOAD4:%[0-9]+]] = load [[ARG2]] : $*Builtin.Int32 |
| // CHECK: apply {{%[0-9]+}}([[LOAD4]]) |
| sil @load : $@convention(thin) (@in Builtin.NativeObject, @in Builtin.Int32) -> () { |
| bb0(%0 : @trivial $*Builtin.NativeObject, %1 : @trivial $*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 [take] %0 : $*Builtin.NativeObject |
| apply %use_native_object_func(%3) : $@convention(thin) (@owned Builtin.NativeObject) -> () |
| |
| %4 = load [copy] %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) (@in Builtin.NativeObject, Builtin.NativeObject, @in Builtin.Int32, Builtin.Int32) -> () |
| // 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 @store : $@convention(thin) (@in Builtin.NativeObject, Builtin.NativeObject, @in Builtin.Int32, Builtin.Int32) -> () { |
| bb0(%0 : @trivial $*Builtin.NativeObject, %1 : @unowned $Builtin.NativeObject, %2 : @trivial $*Builtin.Int32, %3 : @trivial $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 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 @borrow : $@convention(thin) (@in Builtin.NativeObject) -> () { |
| bb0(%0 : @trivial $*Builtin.NativeObject): |
| %1 = load_borrow %0 : $*Builtin.NativeObject |
| %2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $Builtin.NativeObject |
| end_borrow %1 from %0 : $Builtin.NativeObject, $*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 @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 @begin_borrow_store_borrow : $@convention(thin) (@owned Builtin.NativeObject) -> () { |
| bb0(%0 : @owned $Builtin.NativeObject): |
| %1 = begin_borrow %0 : $Builtin.NativeObject |
| end_borrow %1 from %0 : $Builtin.NativeObject, $Builtin.NativeObject |
| %2 = alloc_stack $Builtin.NativeObject |
| %3 = begin_borrow %0 : $Builtin.NativeObject |
| store_borrow %3 to %2 : $*Builtin.NativeObject |
| end_borrow %3 from %0 : $Builtin.NativeObject, $Builtin.NativeObject |
| dealloc_stack %2 : $*Builtin.NativeObject |
| destroy_value %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @copy_unowned_value_test : $@convention(thin) (@owned @sil_unowned Builtin.NativeObject) -> () { |
| // CHECK: bb0([[ARG:%.*]] : $@sil_unowned Builtin.NativeObject): |
| // CHECK-NEXT: strong_retain_unowned [[ARG]] : $@sil_unowned Builtin.NativeObject |
| // CHECK-NEXT: [[OWNED_ARG:%.*]] = unowned_to_ref [[ARG]] : $@sil_unowned Builtin.NativeObject to $Builtin.NativeObject |
| // CHECK-NEXT: strong_release [[OWNED_ARG]] : $Builtin.NativeObject |
| // CHECK-NEXT: unowned_release [[ARG]] : $@sil_unowned Builtin.NativeObject |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @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 @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 @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 @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 @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, Builtin.UnknownObject>) -> () { |
| // CHECK: bb0([[ARG:%.*]] : $Either<Builtin.NativeObject, Builtin.UnknownObject>): |
| // CHECK: switch_enum [[ARG]] : $Either<Builtin.NativeObject, Builtin.UnknownObject>, 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 @switch_enum_default_case : $@convention(thin) (@owned Either<Builtin.NativeObject, Builtin.UnknownObject>) -> () { |
| bb0(%0 : @owned $Either<Builtin.NativeObject, Builtin.UnknownObject>): |
| switch_enum %0 : $Either<Builtin.NativeObject, Builtin.UnknownObject>, 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.UnknownObject>): |
| destroy_value %2 : $Either<Builtin.NativeObject, Builtin.UnknownObject> |
| br bb3 |
| |
| bb3: |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| class TestArrayStorage { |
| @sil_stored 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 @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 @test_empty_destructure : $@convention(thin) () -> () { |
| bb0: |
| %0 = struct $EmptyStruct() |
| () = destructure_struct %0 : $EmptyStruct |
| %1 = tuple() |
| () = destructure_tuple %1 : $() |
| return %1 : $() |
| } |