| // RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts %s | FileCheck %s |
| // RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=1 -arc-sequence-opts %s | FileCheck %s |
| // RUN: %target-sil-opt -enable-sil-verify-all -arc-loop-opts %s | FileCheck %s |
| |
| sil_stage canonical |
| |
| import Swift |
| import Builtin |
| |
| // Utilities |
| |
| sil @user : $@convention(thin) (@box Builtin.Int32) -> () |
| |
| struct S { |
| var x : Builtin.NativeObject |
| } |
| sil @S_user : $@convention(thin) (S) -> () |
| |
| struct S2 { |
| var x : Builtin.Int32 |
| var y : Builtin.NativeObject |
| var z : Builtin.Int32 |
| } |
| |
| struct S3 { |
| var x : Builtin.Int32 |
| var y : Builtin.NativeObject |
| var y1 : Builtin.NativeObject |
| var z : Builtin.Int32 |
| } |
| |
| class Cls { |
| var random : Builtin.Int32 |
| |
| init() |
| } |
| |
| class C { |
| var w : Optional<Builtin.NativeObject> |
| } |
| |
| class Container { |
| @sil_stored var c : Cls |
| init() |
| } |
| |
| |
| class RetainUser { } |
| |
| sil @rawpointer_use: $@convention(thin) (Builtin.RawPointer) -> Bool |
| |
| enum FakeOptional<T> { |
| case None |
| case Some(T) |
| } |
| |
| enum Either<LTy, RTy> { |
| case Left(LTy) |
| case Right(RTy) |
| } |
| |
| sil [fragile] @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| |
| sil [fragile] @owned_return : $@convention(thin) () -> (@owned @box Builtin.Int32) |
| |
| sil [fragile] @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error ErrorType |
| |
| ///////////////// |
| // Basic Tests // |
| ///////////////// |
| |
| // CHECK-LABEL: sil @simple_retain_release_pair : $@convention(thin) (Builtin.NativeObject) -> () |
| // CHECK: bb0 |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @simple_retain_release_pair : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple () |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @simple_copyvalue_destroyvalue_pair : $@convention(thin) (S) -> S |
| // CHECK: bb0({{%[0-9]+}} : $S) |
| // CHECK-NEXT: return |
| sil @simple_copyvalue_destroyvalue_pair : $@convention(thin) (S) -> S { |
| bb0(%0 : $S): |
| retain_value %0 : $S |
| release_value %0 : $S |
| retain_value %0 : $S |
| release_value %0 : $S |
| retain_value %0 : $S |
| release_value %0 : $S |
| return %0 : $S |
| } |
| |
| // CHECK-LABEL: sil @delete_retain_over_non_side_effect_instructions : $@convention(thin) (Builtin.NativeObject, Builtin.Int64) -> Builtin.Int1 |
| // CHECK: bb0 |
| // CHECK-NEXT: builtin |
| // CHECK-NEXT: return |
| sil @delete_retain_over_non_side_effect_instructions : $@convention(thin) (Builtin.NativeObject, Builtin.Int64) -> (Builtin.Int1) { |
| bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int64): |
| strong_retain %0 : $Builtin.NativeObject |
| %3 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 |
| strong_release %0 : $Builtin.NativeObject |
| return %3 : $Builtin.Int1 |
| } |
| |
| // CHECK-LABEL: sil @delete_copyvalue_over_non_side_effect_instructions : $@convention(thin) (S, Builtin.Int64) -> Builtin.Int1 |
| // CHECK: bb0 |
| // CHECK-NEXT: builtin |
| // CHECK-NEXT: return |
| sil @delete_copyvalue_over_non_side_effect_instructions : $@convention(thin) (S, Builtin.Int64) -> (Builtin.Int1) { |
| bb0(%0 : $S, %1 : $Builtin.Int64): |
| retain_value %0 : $S |
| %3 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 |
| release_value %0 : $S |
| return %3 : $Builtin.Int1 |
| } |
| |
| // CHECK-LABEL: sil @delete_retain_over_single_potential_decrement : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject) -> () |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @delete_retain_over_single_potential_decrement : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| strong_release %1 : $Builtin.NativeObject |
| strong_release %0 : $Builtin.NativeObject |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @delete_copyvalue_over_single_potential_decrement : $@convention(thin) (S, Builtin.NativeObject) -> () |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @delete_copyvalue_over_single_potential_decrement : $@convention(thin) (S, Builtin.NativeObject) -> () { |
| bb0(%0 : $S, %1 : $Builtin.NativeObject): |
| retain_value %0 : $S |
| strong_release %1 : $Builtin.NativeObject |
| release_value %0 : $S |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @dont_delete_retain_over_decrement_use : $@convention(thin) (@box Builtin.Int32) -> () |
| // CHECK: bb0 |
| // CHECK: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @dont_delete_retain_over_decrement_use : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @dont_delete_copyvalue_over_decrement_use : $@convention(thin) (S) -> () |
| // CHECK: bb0 |
| // CHECK: retain_value |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: release_value |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @dont_delete_copyvalue_over_decrement_use : $@convention(thin) (S) -> () { |
| bb0(%0 : $S): |
| %1 = function_ref @S_user : $@convention(thin) (S) -> () |
| retain_value %0 : $S |
| apply %1 (%0) : $@convention(thin) (S) -> () |
| apply %1 (%0) : $@convention(thin) (S) -> () |
| release_value %0 : $S |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @move_delete_retain_over_decrement_use_when_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () |
| // CHECK: bb0 |
| // CHECK: integer_literal |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @move_delete_retain_over_decrement_use_when_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| %2 = integer_literal $Builtin.Int32, 1 |
| %3 = integer_literal $Builtin.Int32, 2 |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| strong_release %0 : $@box Builtin.Int32 |
| %4 = tuple() |
| return %4 : $() |
| } |
| |
| // CHECK-LABEL: sil @delete_copyvalue_over_decrement_use_when_knownsafe : $@convention(thin) (S) -> () |
| // CHECK: bb0 |
| // CHECK: integer_literal |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: retain_value |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: release_value |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @delete_copyvalue_over_decrement_use_when_knownsafe : $@convention(thin) (S) -> () { |
| bb0(%0 : $S): |
| %1 = function_ref @S_user : $@convention(thin) (S) -> () |
| retain_value %0 : $S |
| %2 = integer_literal $Builtin.Int32, 1 |
| %3 = integer_literal $Builtin.Int32, 2 |
| retain_value %0 : $S |
| apply %1 (%0) : $@convention(thin) (S) -> () |
| apply %1 (%0) : $@convention(thin) (S) -> () |
| release_value %0 : $S |
| release_value %0 : $S |
| %4 = tuple() |
| return %4 : $() |
| } |
| |
| // CHECK-LABEL: sil @literals_do_not_use_values_with_reference_semantics : $@convention(thin) (@box Builtin.Int32) -> () |
| // CHECK: bb0 |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: integer_literal |
| // CHECK-NEXT: string_literal |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @literals_do_not_use_values_with_reference_semantics : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| strong_retain %0 : $@box Builtin.Int32 |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| %4 = integer_literal $Builtin.Int64, 0 |
| %5 = string_literal utf8 "123" |
| strong_release %0 : $@box Builtin.Int32 |
| %6 = tuple() |
| return %6 : $() |
| } |
| |
| // CHECK-LABEL: sil @owned_arguments_are_known_safe_in_the_first_bb |
| // CHECK: bb0 |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: br |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @owned_arguments_are_known_safe_in_the_first_bb : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| strong_release %0 : $@box Builtin.Int32 |
| br bb1 |
| |
| bb1: |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // FIXME: Should be able to eliminate the r/r pair here. |
| |
| // CHECK-LABEL: @simple_alias_store_use_test : $@convention(thin) (@box Builtin.Int32) -> () { |
| // SHOULD-NOT: strong_retain |
| // SHOULD-NOT: strong_release |
| sil @simple_alias_store_use_test : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = project_box %0 : $@box Builtin.Int32 |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| %3 = integer_literal $Builtin.Int32, 2 |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %2 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| store %3 to %1 : $*Builtin.Int32 |
| strong_release %0 : $@box Builtin.Int32 |
| %4 = tuple() |
| return %4: $() |
| } |
| |
| // We can't remove the retain-release pair because the apply may be |
| // decrementing the refcount on our object. |
| // CHECK-LABEL: @simple_alias_load_use_test : $@convention(thin) (@inout Builtin.Int32) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: alloc_box |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: load |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @simple_alias_load_use_test : $@convention(thin) (@inout Builtin.Int32) -> () { |
| bb0(%0 : $*Builtin.Int32): |
| %1 = alloc_box $Builtin.Int32 |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %1#0 : $@box Builtin.Int32 |
| apply %2 (%1#0) : $@convention(thin) (@box Builtin.Int32) -> () |
| %3 = load %1#1 : $*Builtin.Int32 |
| strong_release %1#0 : $@box Builtin.Int32 |
| %4 = tuple() |
| return %4: $() |
| } |
| |
| // We *CAN* remove the pair if we have an iterated strong_release though. |
| // |
| // CHECK-LABEL: @simple_alias_load_use_test_two_release : $@convention(thin) (@inout Builtin.Int32) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: alloc_box |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: load |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @simple_alias_load_use_test_two_release : $@convention(thin) (@inout Builtin.Int32) -> () { |
| bb0(%0 : $*Builtin.Int32): |
| %1 = alloc_box $Builtin.Int32 |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %1#0 : $@box Builtin.Int32 |
| strong_retain %1#0 : $@box Builtin.Int32 |
| apply %2 (%1#0) : $@convention(thin) (@box Builtin.Int32) -> () |
| %3 = load %1#1 : $*Builtin.Int32 |
| strong_release %1#0 : $@box Builtin.Int32 |
| strong_release %1#0 : $@box Builtin.Int32 |
| %4 = tuple() |
| return %4: $() |
| } |
| |
| // CHECK-LABEL: sil @silargument_retain_iterated : $@convention(thin) (@owned @box Builtin.Int32) -> () |
| // CHECK: bb0 |
| // CHECK-NEXT: function_ref user |
| // CHECK-NEXT: function_ref @user |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| sil @silargument_retain_iterated : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| strong_release %0 : $@box Builtin.Int32 |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @value_that_does_not_alias_pointer_args_cannot_be_decremented : $@convention(thin) (Cls) -> () |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @value_that_does_not_alias_pointer_args_cannot_be_decremented : $@convention(thin) (Cls) -> () { |
| bb0(%0 : $Cls): |
| %1 = alloc_ref $Cls |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| %3 = unchecked_ref_cast %0 : $Cls to $@box Builtin.Int32 |
| strong_retain %1 : $Cls |
| apply %2(%3) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %2(%3) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %1 : $Cls |
| %4 = tuple() |
| return %4 : $() |
| } |
| |
| // CHECK-LABEL: sil @escaping_pointer_can_have_refcount_decremented_indirectly : $@convention(thin) (@box Builtin.Int32) -> () |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| |
| sil @the_kraken : $@convention(thin) () -> () |
| sil @escaping_pointer_can_have_refcount_decremented_indirectly : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @the_kraken : $@convention(thin) () -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1() : $@convention(thin) () -> () |
| apply %1() : $@convention(thin) () -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // Make sure that we clear state and don't do anything in the fact of |
| // autorelease push/pop. |
| sil @objc_autoreleasePoolPush : $@convention(thin) () -> Builtin.RawPointer |
| sil @objc_autoreleasePoolPop : $@convention(thin) (Builtin.RawPointer) -> () |
| |
| // CHECK-LABEL: sil @clear_state_in_fact_of_autorelease_pool_ops : $@convention(thin) (Builtin.RawPointer) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: function_ref objc_autoreleasePoolPush |
| // CHECK-NEXT: function_ref @objc_autoreleasePoolPush |
| // CHECK-NEXT: function_ref objc_autoreleasePoolPop |
| // CHECK-NEXT: function_ref @objc_autoreleasePoolPop |
| // CHECK-NEXT: alloc_box |
| // CHECK-NEXT: retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: release |
| // CHECK-NEXT: retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: release |
| // CHECK-NEXT: release |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @clear_state_in_fact_of_autorelease_pool_ops : $@convention(thin) (Builtin.RawPointer) -> () { |
| bb0(%0 : $Builtin.RawPointer): |
| %1 = function_ref @objc_autoreleasePoolPush : $@convention(thin) () -> Builtin.RawPointer |
| %2 = function_ref @objc_autoreleasePoolPop : $@convention(thin) (Builtin.RawPointer) -> () |
| %3 = alloc_box $Builtin.Int32 |
| strong_retain %3#0 : $@box Builtin.Int32 |
| apply %1() : $@convention(thin) () -> Builtin.RawPointer |
| strong_release %3#0 : $@box Builtin.Int32 |
| strong_retain %3#0 : $@box Builtin.Int32 |
| apply %2(%0) : $@convention(thin) (Builtin.RawPointer) -> () |
| strong_release %3#0 : $@box Builtin.Int32 |
| strong_release %3#0 : $@box Builtin.Int32 |
| %4 = tuple() |
| return %4 : $() |
| } |
| |
| |
| // CHECK-LABEL: sil @release_can_decrement_other_releases : $@convention(thin) () -> () { |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| // CHECK: strong_release |
| sil @release_can_decrement_other_releases : $@convention(thin) () -> () { |
| bb0: |
| %1 = alloc_box $Builtin.Int32 |
| %2 = alloc_stack $@box Builtin.Int32 |
| store %1#0 to %2#1 : $*@box Builtin.Int32 |
| %4 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %1#0 : $@box Builtin.Int32 |
| %6 = load %2#1 : $*@box Builtin.Int32 |
| %7 = apply %4(%6) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %6 : $@box Builtin.Int32 |
| strong_release %1#0 : $@box Builtin.Int32 |
| dealloc_stack %2#0 : $*@local_storage @box Builtin.Int32 |
| %11 = tuple () |
| return %11 : $() |
| } |
| |
| // CHECK-LABEL: sil @retain_can_be_used_by_other_pointer : $@convention(thin) (RetainUser, @box Builtin.Int32) -> @box Builtin.Int32 { |
| // CHECK: strong_retain |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @retain_can_be_used_by_other_pointer : $@convention(thin) (RetainUser, @box Builtin.Int32) -> @box Builtin.Int32 { |
| bb0(%0 : $RetainUser, %1 : $@box Builtin.Int32): |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $RetainUser |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %1 : $@box Builtin.Int32 |
| strong_release %0 : $RetainUser |
| return %1 : $@box Builtin.Int32 |
| } |
| |
| // CHECK-LABEL: sil @remove_retain_release_over_no_release_func |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @remove_retain_release_over_no_release_func : $@convention(thin) (Cls) -> () { |
| bb0(%0 : $Cls): |
| %1 = function_ref @no_release_func : $@convention(thin) (Cls) -> () |
| strong_retain %0 : $Cls |
| apply %1 (%0) : $@convention(thin) (Cls) -> () |
| apply %1 (%0) : $@convention(thin) (Cls) -> () |
| strong_release %0 : $Cls |
| %r = tuple() |
| return %r : $() |
| } |
| |
| // CHECK-LABEL: sil @dont_remove_as_arg0_may_be_incdirectly_released_by_callee |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @dont_remove_as_arg0_may_be_incdirectly_released_by_callee : $@convention(thin) (Cls, Cls) -> () { |
| bb0(%0 : $Cls, %1 : $Cls): |
| %2 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> () |
| retain_value %0 : $Cls |
| apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> () |
| apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> () |
| release_value %0 : $Cls |
| %r = tuple() |
| return %r : $() |
| } |
| |
| // CHECK-LABEL: sil @remove_as_local_object_does_not_escape_to_callee |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @remove_as_local_object_does_not_escape_to_callee : $@convention(thin) (Cls) -> () { |
| bb0(%0 : $Cls): |
| %1 = alloc_ref $Cls |
| retain_value %1 : $Cls |
| %f1 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> () |
| apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> () |
| apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> () |
| release_value %1 : $Cls |
| %f2 = function_ref @no_release_func : $@convention(thin) (Cls) -> () |
| apply %f2 (%1) : $@convention(thin) (Cls) -> () |
| %r = tuple() |
| return %r : $() |
| } |
| |
| // CHECK-LABEL: sil @dont_remove_as_local_object_indirectly_escapes_to_callee |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @dont_remove_as_local_object_indirectly_escapes_to_callee : $@convention(thin) (Cls) -> () { |
| bb0(%0 : $Cls): |
| %1 = alloc_ref $Cls |
| %2 = alloc_ref $Container |
| %3 = ref_element_addr %2 : $Container, #Container.c |
| store %1 to %3 : $*Cls |
| retain_value %1 : $Cls |
| %f1 = function_ref @release_container : $@convention(thin) (Container) -> () |
| apply %f1 (%2) : $@convention(thin) (Container) -> () |
| apply %f1 (%2) : $@convention(thin) (Container) -> () |
| release_value %1 : $Cls |
| %r = tuple() |
| return %r : $() |
| } |
| |
| sil @release_arg1 : $@convention(thin) (Cls, Cls) -> () { |
| bb0(%0 : $Cls, %1 : $Cls): |
| strong_release %1 : $Cls |
| %r = tuple() |
| return %r : $() |
| } |
| |
| sil @release_container : $@convention(thin) (Container) -> () { |
| bb0(%0 : $Container): |
| strong_release %0 : $Container |
| %r = tuple() |
| return %r : $() |
| } |
| |
| sil @no_release_func : $@convention(thin) (Cls) -> () { |
| bb0(%0 : $Cls): |
| %r = tuple() |
| return %r : $() |
| } |
| |
| //////////////////// |
| // Multi-BB tests // |
| //////////////////// |
| |
| ////////////// |
| // Hammocks // |
| ////////////// |
| |
| // CHECK-LABEL: sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb2 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // This hammock can not be optimized. |
| // CHECK-LABEL: sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_retain |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_release |
| sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb2 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| /// This hammock can't be optimized. |
| // CHECK-LABEL: sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_release |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_release |
| sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| br bb2 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // This should not be optimizable. |
| // CHECK-LABEL: sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_retain |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_release |
| sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb2 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NOT: strong_release |
| // CHECK-NOT: strong_retain |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_release |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_release |
| sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| br bb2 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| // CHECK: bb1: |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_release |
| sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb2 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_retain |
| // CHECK: bb2: |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb2 |
| |
| bb2: |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK-NOT: strong_release |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_release |
| // CHECK-NOT: strong_retain |
| // CHECK: bb2: |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| br bb2 |
| |
| bb2: |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| //////////////////// |
| // Double Hammock // |
| //////////////////// |
| |
| // Make sure we do not do anything in the presence of double partial |
| // applies. This is due to issues related to the two branches of the two |
| // diamonds not being control dependent. |
| // CHECK-LABEL: sil @double_hammock1 : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: function_ref user |
| // CHECK-NEXT: function_ref @user |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: bb2 |
| // CHECK: bb2: |
| // CHECK-NEXT: cond_br |
| // CHECK: bb3: |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: br |
| // CHECK: bb4: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @double_hammock1 : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb2 |
| |
| bb2: |
| cond_br undef, bb3, bb4 |
| |
| bb3: |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb4 |
| |
| bb4: |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| ////////////// |
| // Diamonds // |
| ////////////// |
| |
| // CHECK-LABEL: sil @diamond1 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @diamond1 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond2 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond2 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb3 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond3 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond3 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond4 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @diamond4 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond5 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond5 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond6 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond6 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb3 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond7 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond7 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| strong_release %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond8 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond8 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| /// CHECK-LABEL: sil @diamond9 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond9 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb3 |
| |
| bb2: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond10 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @diamond10 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| /// CHECK-LABEL: sil @diamond11 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond11 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @diamond12 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK: bb0 |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: br |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple () |
| // CHECK-NEXT: return |
| sil @diamond12 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb3 |
| |
| bb2: |
| strong_retain %0 : $Builtin.NativeObject |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK: sil @unreachable_bb : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @unreachable_bb : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| |
| bb2: |
| %3 = builtin "int_trap"() : $() |
| unreachable |
| } |
| |
| // CHECK: sil @dont_move_values_in_face_of_partial_merges : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @dont_move_values_in_face_of_partial_merges : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @do_remove_values_in_face_of_partial_merges : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: strong_retain |
| // CHECK-NOT: strong_retain |
| // CHECK-NEXT: cond_br |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_release |
| // CHECK-NOT: strong_release |
| sil @do_remove_values_in_face_of_partial_merges : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| strong_retain %0 : $@box Builtin.Int32 |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $@box Builtin.Int32 |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @release_use_optimization : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK: strong_release |
| // CHECK-NOT: strong_release |
| sil @release_use_optimization : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @increment_known_safe_merge_with_last_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: br bb3 |
| // CHECK: bb2: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: br bb3 |
| // CHECK: bb3: |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @increment_known_safe_merge_with_last_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $@box Builtin.Int32 |
| strong_retain %0 : $@box Builtin.Int32 |
| br bb3 |
| |
| bb2: |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| br bb3 |
| |
| bb3: |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: bb0( |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: function_ref |
| // CHECK-NEXT: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: apply |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: cond_br |
| // CHECK: bb1: |
| // CHECK-NEXT: strong_release |
| // CHECK-NEXT: br bb3 |
| // CHECK-NOT: strong_release |
| sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $@box Builtin.Int32 |
| strong_release %0 : $@box Builtin.Int32 |
| br bb3 |
| |
| bb2: |
| strong_release %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb3 |
| |
| bb3: |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // Just make sure we don't crash on this. |
| // CHECK-LABEL: sil @unreachable_pred : $@convention(thin) (Builtin.NativeObject) -> () { |
| sil @unreachable_pred : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| br bb2 |
| |
| bb1: |
| br bb2 |
| |
| bb2: |
| %1 = tuple() |
| return %1 : $() |
| } |
| |
| // CHECK-LABEL: sil @arg_merge : $@convention(thin) (@owned S) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @arg_merge : $@convention(thin) (@owned S) -> () { |
| bb0(%0 : $S): |
| %1 = struct_extract %0 : $S, #S.x |
| strong_retain %1 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %1 : $Builtin.NativeObject |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| |
| /// Make sure we strip off casts when inserting new retains, releases. Otherwise |
| /// we run into dominance problems if the bitcast is in a branch. |
| // CHECK-LABEL: sil @switch_merge_with_bit_cast_in_branches : $@convention(thin) (@owned S) -> () { |
| // CHECK: bb1: |
| // CHECK-NOT: strong_retain |
| // CHECK: bb2: |
| // CHECK-NOT: strong_retain |
| // CHECK: bb3: |
| // CHECK: retain_value |
| // CHECK: release_value |
| sil @switch_merge_with_bit_cast_in_branches : $@convention(thin) (@owned S) -> () { |
| bb0(%0 : $S): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %1 = struct_extract %0 : $S, #S.x |
| %2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $@box Builtin.Int32 |
| strong_retain %2 : $@box Builtin.Int32 |
| br bb3 |
| |
| bb2: |
| %3 = struct_extract %0 : $S, #S.x |
| %4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $@box Builtin.Int32 |
| strong_retain %4 : $@box Builtin.Int32 |
| br bb3 |
| |
| bb3: |
| %5 = struct_extract %0 : $S, #S.x |
| %6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $@box Builtin.Int32 |
| %7 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %7(%6) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %7(%6) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %6 : $@box Builtin.Int32 |
| %11 = tuple() |
| return %11 : $() |
| } |
| |
| // CHECK-LABEL: sil @strip_off_layout_compatible_typed_geps : $@convention(thin) (S, FakeOptional<Builtin.NativeObject>) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| // CHECK-NOT: retain_value |
| // CHECK-NOT: release_value |
| sil @strip_off_layout_compatible_typed_geps : $@convention(thin) (S, FakeOptional<Builtin.NativeObject>) -> () { |
| bb0(%0 : $S, %1 : $FakeOptional<Builtin.NativeObject>): |
| %2 = struct_extract %0 : $S, #S.x |
| strong_retain %2 : $Builtin.NativeObject |
| release_value %0 : $S |
| %3 = unchecked_enum_data %1 : $FakeOptional<Builtin.NativeObject>, #FakeOptional.Some!enumelt.1 |
| strong_retain %3 : $Builtin.NativeObject |
| release_value %1 : $FakeOptional<Builtin.NativeObject> |
| %5 = tuple() |
| return %5 : $() |
| } |
| |
| // CHECK-LABEL: sil @strip_off_single_pred_args : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () { |
| // CHECK-NOT: retain_value |
| // CHECK-NOT: strong_release |
| sil @strip_off_single_pred_args : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () { |
| bb0(%0 : $FakeOptional<Builtin.NativeObject>): |
| switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.Some!enumelt.1: bb1, case #FakeOptional.None!enumelt: bb2 |
| |
| bb1(%1 : $Builtin.NativeObject): |
| retain_value %0 : $FakeOptional<Builtin.NativeObject> |
| strong_release %1 : $Builtin.NativeObject |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @unreachable_bb_2 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @unreachable_bb_2 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| %4 = integer_literal $Builtin.Int1, -1 |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| |
| bb2: |
| cond_fail %4 : $Builtin.Int1 |
| unreachable |
| } |
| |
| // CHECK-LABEL: sil @unreachable_bb_3 : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @unreachable_bb_3 : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| |
| bb2: |
| %4 = integer_literal $Builtin.Int1, -1 |
| cond_fail %4 : $Builtin.Int1 |
| unreachable |
| } |
| |
| // CHECK-LABEL: sil @strip_off_multi_payload_unchecked_enum_data : $@convention(thin) (Either<C, S>) -> () { |
| // CHECK-NOT: retain_value |
| // CHECK-NOT: release_value |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @strip_off_multi_payload_unchecked_enum_data : $@convention(thin) (Either<C, S>) -> () { |
| bb0(%0 : $Either<C, S>): |
| retain_value %0 : $Either<C, S> |
| %1 = unchecked_enum_data %0 : $Either<C, S>, #Either.Right!enumelt.1 |
| release_value %1 : $S |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @strip_off_structs_only_non_trivial_field : $@convention(thin) (S2, S3) -> () { |
| // CHECK: bb0([[ARG0:%[0-9]+]] : $S2, [[ARG1:%[0-9]+]] : $S3): |
| // CHECK-NOT: retain_value |
| // CHECK-NOT: release_value |
| // CHECK: retain_value [[ARG1]] |
| // CHECK-NEXT: [[EXT:%[0-9]+]] = struct_extract [[ARG1]] |
| // CHECK-NEXT: release_value [[EXT]] |
| // CHECK-NOT: retain_value |
| // CHECK-NOT: release_value |
| sil @strip_off_structs_only_non_trivial_field : $@convention(thin) (S2, S3) -> () { |
| bb0(%0 : $S2, %1 : $S3): |
| retain_value %0 : $S2 |
| %2 = struct_extract %0 : $S2, #S2.y |
| release_value %2 : $Builtin.NativeObject |
| retain_value %1 : $S3 |
| %3 = struct_extract %1 : $S3, #S3.y |
| release_value %3 : $Builtin.NativeObject |
| %4 = tuple() |
| return %4 : $() |
| } |
| |
| // CHECK-LABEL: sil @strip_off_enum_from_payload : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: retain_value |
| // CHECK-NOT: release_value |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @strip_off_enum_from_payload : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| %1 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.Some!enumelt.1, %0 : $Builtin.NativeObject |
| strong_retain %0 : $Builtin.NativeObject |
| release_value %1 : $FakeOptional<Builtin.NativeObject> |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // For now make sure we don't eliminate this. |
| // CHECK-LABEL: sil @guaranteed_is_always_known_safe : $@convention(thin) (@guaranteed @box Builtin.Int32) -> () { |
| // CHECK: retain |
| // CHECK: release |
| sil @guaranteed_is_always_known_safe : $@convention(thin) (@guaranteed @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| sil @_TFs18_fatalErrorMessageFTVs12StaticStringS_S_Su_T_ : $@convention(thin) @noreturn (StaticString, StaticString, StaticString) -> () // user: %43 |
| |
| sil @random_prefix_TFs18_fatalErrorMessageFTVs12StaticStringS_S_Su_T_ : $@convention(thin) @noreturn (StaticString, StaticString, StaticString) -> () // user: %43 |
| |
| // CHECK-LABEL: sil @ignore_fatalErrorMsgBB : $@convention(thin) (Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @ignore_fatalErrorMsgBB : $@convention(thin) (Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb4, bb5 |
| |
| bb2: |
| strong_retain %0 : $Builtin.NativeObject |
| cond_br undef, bb3, bb4 |
| |
| bb3: |
| cond_br undef, bb4, bb6 |
| |
| bb4: |
| strong_release %0 : $Builtin.NativeObject |
| %1 = tuple() |
| return %1 : $() |
| |
| bb5: |
| %39 = function_ref @_TFs18_fatalErrorMessageFTVs12StaticStringS_S_Su_T_ : $@convention(thin) @noreturn (StaticString, StaticString, StaticString) -> () // user: %43 |
| %40 = string_literal utf8 "fatal error" |
| %41 = integer_literal $Builtin.Word, 11 |
| %42 = integer_literal $Builtin.Int8, 11 |
| %43 = struct $StaticString (%40 : $Builtin.RawPointer, %41 : $Builtin.Word, %42 : $Builtin.Int8) |
| %44 = apply %39(%43, %43, %43) : $@convention(thin) @noreturn (StaticString, StaticString, StaticString) -> () |
| unreachable |
| |
| bb6: |
| %45 = function_ref @random_prefix_TFs18_fatalErrorMessageFTVs12StaticStringS_S_Su_T_ : $@convention(thin) @noreturn (StaticString, StaticString, StaticString) -> () // user: %43 |
| %46 = string_literal utf8 "fatal error" |
| %47 = integer_literal $Builtin.Word, 11 |
| %48 = integer_literal $Builtin.Int8, 11 |
| %49 = struct $StaticString (%46 : $Builtin.RawPointer, %47 : $Builtin.Word, %48 : $Builtin.Int8) |
| %50 = apply %45(%49, %49, %49) : $@convention(thin) @noreturn (StaticString, StaticString, StaticString) -> () |
| unreachable |
| } |
| |
| // CHECK-LABEL: sil @propagate_postdominating_owned_release_info : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| // CHECK: bb0( |
| // CHECK-NOT: retain |
| // CHECK-NOT: release |
| // CHECK: bb1: |
| // CHECK-NOT: retain |
| // CHECK-NOT: release |
| // CHECK: bb2: |
| // CHECK: strong_release |
| sil @propagate_postdominating_owned_release_info : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| br bb1 |
| |
| bb1: |
| cond_br undef, bb1, bb2 |
| |
| bb2: |
| strong_release %0 : $@box Builtin.Int32 |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @guaranteed_is_a_mayuse_maydecrement : $@convention(thin) (@owned Builtin.NativeObject) -> () { |
| // CHECK: retain |
| // CHECK: release |
| sil @guaranteed_is_a_mayuse_maydecrement : $@convention(thin) (@owned Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| %1 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| strong_retain %0 : $Builtin.NativeObject |
| apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| strong_release %0 : $Builtin.NativeObject |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @guaranteed_is_a_mayuse_maydecrement_can_remove_if_known_safe : $@convention(thin) (@owned Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK: strong_retain |
| // CHECK-NEXT: apply |
| // CHECK: strong_release |
| // CHECK-NOT: strong_release |
| sil @guaranteed_is_a_mayuse_maydecrement_can_remove_if_known_safe : $@convention(thin) (@owned Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject): |
| %1 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| strong_retain %0 : $Builtin.NativeObject |
| strong_retain %0 : $Builtin.NativeObject |
| apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| strong_release %0 : $Builtin.NativeObject |
| strong_release %0 : $Builtin.NativeObject |
| %2 = tuple() |
| return %2 : $() |
| } |
| |
| // CHECK-LABEL: sil @guaranteed_check_if_we_already_have_insertion_pt_we_use_that_one : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { |
| // CHECK: function_ref @guaranteed_use |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| // CHECK: apply |
| // CHECK: function_ref @guaranteed_use |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| // CHECK: function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| sil @guaranteed_check_if_we_already_have_insertion_pt_we_use_that_one : $@convention(thin) (@owned Builtin.NativeObject, @owned Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| %2 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| strong_release %1 : $Builtin.NativeObject |
| %3 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| apply %2(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| %4 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| strong_retain %1 : $Builtin.NativeObject |
| %5 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () |
| strong_release %0 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // Make sure that we handle ARC branch uses correctly. |
| |
| // In the face of partial merges, we *can* remove retains, releases, but we can |
| // not move them. So remove these retains, releases. |
| // |
| // CHECK-LABEL: sil @branch_use1 : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @branch_use1 : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $@box Builtin.Int32 |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb3 |
| |
| bb2: |
| strong_retain %0 : $@box Builtin.Int32 |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We currently do not move this retain, release since we are very conservative with partial merges and code motion. |
| // |
| // CHECK-LABEL: sil @branch_use2 : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: strong_retain |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @branch_use2 : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $@box Builtin.Int32 |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb3 |
| |
| bb2: |
| strong_retain %0 : $@box Builtin.Int32 |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // We can not ignore this branch since bb3 uses %0. |
| // |
| // CHECK-LABEL: sil @branch_use3 : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: strong_retain |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @branch_use3 : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| strong_retain %0 : $@box Builtin.Int32 |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| br bb3(undef : $@box Builtin.Int32) |
| |
| bb2: |
| strong_retain %0 : $@box Builtin.Int32 |
| br bb3(%0 : $@box Builtin.Int32) |
| |
| bb3(%2 : $@box Builtin.Int32): |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // Make sure that we properly ignore the cond_br and do not try to compare the |
| // pointer with the Builtin.Int1 arg. |
| // |
| // CHECK-LABEL: sil @cond_branch_use1 : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @cond_branch_use1 : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| strong_retain %0 : $@box Builtin.Int32 |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| %2 = integer_literal $Builtin.Int1, 0 |
| cond_br %2, bb1, bb2 |
| |
| bb1: |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // Make sure that we do not ignore the cond_br and do not try to compare the |
| // pointer with the Builtin.Int1 arg. |
| // |
| // CHECK-LABEL: sil @cond_branch_use2 : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @cond_branch_use2 : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| strong_retain %0 : $@box Builtin.Int32 |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| %2 = integer_literal $Builtin.Int1, 0 |
| cond_br %2, bb1(%0 : $@box Builtin.Int32), bb2 |
| |
| bb1(%3 : $@box Builtin.Int32): |
| br bb3 |
| |
| bb2: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @cond_branch_use3 : $@convention(thin) (@box Builtin.Int32) -> () { |
| // CHECK: strong_retain |
| // CHECK: strong_release |
| sil @cond_branch_use3 : $@convention(thin) (@box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| strong_retain %0 : $@box Builtin.Int32 |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| %2 = integer_literal $Builtin.Int1, 0 |
| cond_br %2, bb2(%0 : $@box Builtin.Int32), bb1 |
| |
| bb2(%3 : $@box Builtin.Int32): |
| br bb3 |
| |
| bb1: |
| br bb3 |
| |
| bb3: |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @owned_return_value_test : $@convention(thin) () -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK: strong_release |
| // CHECK-NOT: strong_release |
| sil @owned_return_value_test : $@convention(thin) () -> () { |
| bb0: |
| %0 = function_ref @owned_return : $@convention(thin) () -> (@owned @box Builtin.Int32) |
| %1 = apply %0() : $@convention(thin) () -> (@owned @box Builtin.Int32) |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %1 : $@box Builtin.Int32 |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %1 : $@box Builtin.Int32 |
| strong_release %1 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @retains_that_are_not_removed_preserves_known_safety : $@convention(thin) (@owned @box Builtin.Int32, @box Builtin.Int32) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK: apply |
| // CHECK: apply |
| // CHECK-NOT: strong_release |
| // CHECK: strong_retain |
| // CHECK: apply |
| // CHECK: apply |
| // CHECK: strong_release |
| sil @retains_that_are_not_removed_preserves_known_safety : $@convention(thin) (@owned @box Builtin.Int32, @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32, %1 : $@box Builtin.Int32): |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @retains_that_are_removed_do_not_preserve_known_safety : $@convention(thin) (@owned @box Builtin.Int32, @box Builtin.Int32) -> () { |
| // CHECK: strong_retain |
| // CHECK: apply |
| // CHECK: apply |
| // CHECK: strong_release |
| // CHECK-NOT: strong_retain |
| // CHECK: apply |
| // CHECK-NOT: strong_release |
| sil @retains_that_are_removed_do_not_preserve_known_safety : $@convention(thin) (@owned @box Builtin.Int32, @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32, %1 : $@box Builtin.Int32): |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @alloc_ref_returns_at_p1 : $@convention(thin) () -> () { |
| // CHECK: alloc_ref |
| // CHECK-NOT: strong_retain |
| // CHECK: apply |
| // CHECK: apply |
| // CHECK: strong_release |
| // CHECK-NOT: strong_release |
| sil @alloc_ref_returns_at_p1 : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_ref $Cls |
| %1 = unchecked_ref_cast %0 : $Cls to $@box Builtin.Int32 |
| strong_retain %0 : $Cls |
| %2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %1 : $@box Builtin.Int32 |
| strong_release %1 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @alloc_ref_dynamic_returns_at_p1 : $@convention(thin) () -> () { |
| // CHECK: alloc_ref_dynamic |
| // CHECK-NOT: strong_retain |
| // CHECK: apply |
| // CHECK: apply |
| // CHECK: strong_release |
| // CHECK-NOT: strong_release |
| sil @alloc_ref_dynamic_returns_at_p1 : $@convention(thin) () -> () { |
| bb0: |
| %0 = metatype $@thick Cls.Type |
| %1 = alloc_ref_dynamic %0 : $@thick Cls.Type, $Cls |
| %2 = unchecked_ref_cast %1 : $Cls to $@box Builtin.Int32 |
| strong_retain %1 : $Cls |
| %3 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %3(%2) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %3(%2) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %2 : $@box Builtin.Int32 |
| strong_release %2 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @must_use_test : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @must_use_test : $@convention(thin) (@owned @box Builtin.Int32) -> () { |
| bb0(%0 : $@box Builtin.Int32): |
| %1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| strong_retain %0 : $@box Builtin.Int32 |
| apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @alloc_box_returns_at_p1 : $@convention(thin) () -> () { |
| // CHECK: alloc_box |
| // CHECK-NOT: strong_retain |
| // CHECK: apply |
| // CHECK: apply |
| // CHECK: strong_release |
| // CHECK-NOT: strong_release |
| sil @alloc_box_returns_at_p1 : $@convention(thin) () -> () { |
| bb0: |
| %0 = alloc_box $Builtin.Int32 |
| strong_retain %0#0 : $@box Builtin.Int32 |
| %3 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %3(%0#0) : $@convention(thin) (@box Builtin.Int32) -> () |
| apply %3(%0#0) : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_release %0#0 : $@box Builtin.Int32 |
| strong_release %0#0 : $@box Builtin.Int32 |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @copyArrayDoesntDecrementRefCounts : $@convention(thin) (Builtin.RawPointer, Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @copyArrayDoesntDecrementRefCounts : $@convention(thin) (Builtin.RawPointer, Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.NativeObject): |
| %2 = metatype $@thick Builtin.Int32.Type |
| %3 = integer_literal $Builtin.Word, 1 |
| strong_retain %1 : $Builtin.NativeObject |
| %4 = builtin "copyArray"<Builtin.Int32>(%2 : $@thick Builtin.Int32.Type, %0 : $Builtin.RawPointer, %0 : $Builtin.RawPointer, %3 : $Builtin.Word) : $() |
| fix_lifetime %1 : $Builtin.NativeObject |
| strong_release %1 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @clibraryintrinsicsdonttouchrefcounts : $@convention(thin) (Builtin.RawPointer, Builtin.NativeObject) -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @clibraryintrinsicsdonttouchrefcounts : $@convention(thin) (Builtin.RawPointer, Builtin.NativeObject) -> () { |
| bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.NativeObject): |
| %3 = integer_literal $Builtin.Int64, 1 |
| %4 = integer_literal $Builtin.Int32, 1 |
| %5 = integer_literal $Builtin.Int1, 0 |
| strong_retain %1 : $Builtin.NativeObject |
| %6 = builtin "int_memcpy_RawPointer_RawPointer_Int64"(%0 : $Builtin.RawPointer, %0 : $Builtin.RawPointer, %3 : $Builtin.Int64, %4 : $Builtin.Int32, %5 : $Builtin.Int1) : $() |
| fix_lifetime %1 : $Builtin.NativeObject |
| strong_release %1 : $Builtin.NativeObject |
| strong_retain %1 : $Builtin.NativeObject |
| %7 = builtin "int_memset_RawPointer_RawPointer_Int64"(%0 : $Builtin.RawPointer, %0 : $Builtin.RawPointer, %3 : $Builtin.Int64, %4 : $Builtin.Int32, %5 : $Builtin.Int1) : $() |
| fix_lifetime %1 : $Builtin.NativeObject |
| strong_release %1 : $Builtin.NativeObject |
| strong_retain %1 : $Builtin.NativeObject |
| %8 = builtin "int_memmove_RawPointer_RawPointer_Int64"(%0 : $Builtin.RawPointer, %0 : $Builtin.RawPointer, %3 : $Builtin.Int64, %4 : $Builtin.Int32, %5 : $Builtin.Int1) : $() |
| fix_lifetime %1 : $Builtin.NativeObject |
| strong_release %1 : $Builtin.NativeObject |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil @convert_function_preserves_rc_identity : $@convention(thin) () -> () { |
| // CHECK-NOT: strong_retain |
| // CHECK-NOT: strong_release |
| sil @convert_function_preserves_rc_identity : $@convention(thin) () -> () { |
| bb0: |
| %0 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> () |
| %1 = partial_apply %0() : $@convention(thin) (@box Builtin.Int32) -> () |
| strong_retain %1 : $@callee_owned (@box Builtin.Int32) -> () |
| %2 = convert_function %1 : $@callee_owned (@box Builtin.Int32) -> () to $@callee_owned (@box Builtin.Int32) -> () |
| strong_release %2 : $@callee_owned (@box Builtin.Int32) -> () |
| %9999 = tuple() |
| return %9999 : $() |
| } |
| |
| // CHECK-LABEL: sil [fragile] @try_apply_test : $@convention(thin) (Builtin.NativeObject) -> @error ErrorType { |
| // CHECK: bb0 |
| // CHECK: strong_retain |
| // CHECK: bb1 |
| // CHECK: strong_release |
| // CHECK: bb2 |
| // CHECK: strong_release |
| sil [fragile] @try_apply_test : $@convention(thin) (Builtin.NativeObject) -> @error ErrorType { |
| bb0(%0 : $Builtin.NativeObject): |
| strong_retain %0 : $Builtin.NativeObject |
| %1 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error ErrorType |
| try_apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error ErrorType, normal bb1, error bb2 |
| |
| bb1(%2 : $()): |
| strong_release %0 : $Builtin.NativeObject |
| return undef : $() |
| |
| bb2(%3 : $ErrorType): |
| strong_release %0 : $Builtin.NativeObject |
| throw %3 : $ErrorType |
| } |
| |