// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts %s | %FileCheck %s // RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -enable-loop-arc=1 -arc-sequence-opts %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-LOOP %s // RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -arc-loop-opts %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-LOOP %s // REQUIRES: swift_in_compiler sil_stage canonical import Builtin import Swift // Utilities sil @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () sil @owned_user : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () 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() } public enum FakeOptional { case none case some(T) } class C { init() var w : FakeOptional } enum E { case A(C) case B } struct StructWithEnum { @_hasStorage var e: E { get } init(e: E) } sil @cls_use : $@convention(thin) (@owned Cls) -> () class Container { @_hasStorage var c : Cls init() } class RetainUser { } sil @rawpointer_use: $@convention(thin) (Builtin.RawPointer) -> () enum Either { case Left(LTy) case Right(RTy) } struct StaticString { /// Either a pointer to the start of UTF-8 data, or an integer representation /// of a single Unicode scalar. var _startPtrOrData: Builtin.RawPointer /// If `_startPtrOrData` is a pointer, contains the length of the UTF-8 data /// in bytes. var _byteSize: Builtin.Word /// Extra flags: /// /// - bit 0: set to 0 if `_startPtrOrData` is a pointer, or to 1 if it is a /// Unicode scalar. /// /// - bit 1: set to 1 if `_startPtrOrData` is a pointer and string data is /// ASCII. var _flags: Builtin.Int8 } public protocol Error { var _domain: Builtin.Int32 { get } var _code: Builtin.Int32 { get } } sil [serialized] @use : $@convention(thin) (Builtin.NativeObject) -> () sil [serialized] @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () sil [serialized] @owned_return : $@convention(thin) () -> (@owned <τ_0_0> { var τ_0_0 } ) sil [serialized] @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error ///////////////// // 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) (<τ_0_0> { var τ_0_0 } ) -> () // 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) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %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) (<τ_0_0> { var τ_0_0 } ) -> () // CHECK: bb0 // CHECK: strong_retain // CHECK-NEXT: integer_literal // CHECK-NEXT: integer_literal // 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) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } %2 = integer_literal $Builtin.Int32, 1 %3 = integer_literal $Builtin.Int32, 2 strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_release %0 : $<τ_0_0> { var τ_0_0 } %4 = tuple() return %4 : $() } // CHECK-LABEL: sil @delete_copyvalue_over_decrement_use_when_knownsafe : $@convention(thin) (S) -> () // CHECK: bb0 // CHECK: retain_value // CHECK-NEXT: integer_literal // CHECK-NEXT: integer_literal // 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) (<τ_0_0> { var τ_0_0 } ) -> () // 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) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): strong_retain %0 : $<τ_0_0> { var τ_0_0 } %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %4 = integer_literal $Builtin.Int64, 0 %5 = string_literal utf8 "123" strong_release %0 : $<τ_0_0> { var τ_0_0 } %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 bb // 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 <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_release %0 : $<τ_0_0> { var τ_0_0 } br bb1 bb1: strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %2 = tuple() return %2 : $() } // FIXME: Should be able to eliminate the r/r pair here. // CHECK-LABEL: @simple_alias_store_use_test : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { // SHOULD-NOT: strong_retain // SHOULD-NOT: strong_release sil @simple_alias_store_use_test : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = project_box %0 : $<τ_0_0> { var τ_0_0 } , 0 %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %3 = integer_literal $Builtin.Int32, 2 strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %2 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () store %3 to %1 : $*Builtin.Int32 strong_release %0 : $<τ_0_0> { var τ_0_0 } %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: project_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 $<τ_0_0> { var τ_0_0 } %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } , 0 %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %1 : $<τ_0_0> { var τ_0_0 } apply %2 (%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %3 = load %1a : $*Builtin.Int32 strong_release %1 : $<τ_0_0> { var τ_0_0 } %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: project_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 $<τ_0_0> { var τ_0_0 } %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } , 0 %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %1 : $<τ_0_0> { var τ_0_0 } strong_retain %1 : $<τ_0_0> { var τ_0_0 } apply %2 (%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %3 = load %1a : $*Builtin.Int32 strong_release %1 : $<τ_0_0> { var τ_0_0 } strong_release %1 : $<τ_0_0> { var τ_0_0 } %4 = tuple() return %4: $() } struct Int { var value : Builtin.Int64 } sil @guaranteed_call : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () { [%0: noescape **] bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = tuple () return %1 : $() } sil @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error any Error { [%0: noescape **] bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = tuple () return %1 : $() } // CHECK-LABEL: sil hidden [noinline] @$test_guaranteed_call : // CHECK: bb1{{.*}}: // CHECK-NOT: strong_retain // CHECK: apply // CHECK-NOT: strong_release // CHECK: bb2: // CHECK-LABEL: } // end sil function '$test_guaranteed_call' sil hidden [noinline] @$test_guaranteed_call : $@convention(thin) () -> () { bb0: %box = alloc_box $<τ_0_0> { var τ_0_0 } %proj = project_box %box : $<τ_0_0> { var τ_0_0 } , 0 %0 = integer_literal $Builtin.Int64, 1 %1 = integer_literal $Builtin.Int64, 100 %funcref = function_ref @guaranteed_call : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () %3 = struct $Int (%0 : $Builtin.Int64) %6 = integer_literal $Builtin.Int1, -1 br bb1(%0 : $Builtin.Int64) bb1(%8 : $Builtin.Int64): %9 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %0 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) %10 = tuple_extract %9 : $(Builtin.Int64, Builtin.Int1), 0 %11 = struct $Int (%10 : $Builtin.Int64) %12 = builtin "cmp_eq_Int64"(%10 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 strong_retain %box : $<τ_0_0> { var τ_0_0 } apply %funcref (%box) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () strong_release %box : $<τ_0_0> { var τ_0_0 } cond_br %12, bb3, bb2 bb2: br bb1(%10 : $Builtin.Int64) bb3: strong_release %box : $<τ_0_0> { var τ_0_0 } %17 = tuple () return %17 : $() } // CHECK-LABEL: sil @silargument_retain_iterated : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () // 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 <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %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) (<τ_0_0> { var τ_0_0 } ) -> () %3 = unchecked_ref_cast %0 : $Cls to $<τ_0_0> { var τ_0_0 } strong_retain %1 : $Cls apply %2(%3) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %2(%3) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %1 : $Cls %4 = tuple() return %4 : $() } // CHECK-LABEL: sil @escaping_pointer_can_have_refcount_decremented_indirectly : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () // CHECK: strong_retain // CHECK: strong_release sil @the_kraken : $@convention(thin) () -> () sil @escaping_pointer_can_have_refcount_decremented_indirectly : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @the_kraken : $@convention(thin) () -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1() : $@convention(thin) () -> () apply %1() : $@convention(thin) () -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %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 $<τ_0_0> { var τ_0_0 } strong_retain %3 : $<τ_0_0> { var τ_0_0 } apply %1() : $@convention(thin) () -> Builtin.RawPointer strong_release %3 : $<τ_0_0> { var τ_0_0 } strong_retain %3 : $<τ_0_0> { var τ_0_0 } apply %2(%0) : $@convention(thin) (Builtin.RawPointer) -> () strong_release %3 : $<τ_0_0> { var τ_0_0 } strong_release %3 : $<τ_0_0> { var τ_0_0 } %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 $<τ_0_0> { var τ_0_0 } %2 = alloc_stack $<τ_0_0> { var τ_0_0 } store %1 to %2 : $*<τ_0_0> { var τ_0_0 } %4 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %1 : $<τ_0_0> { var τ_0_0 } %6 = load %2 : $*<τ_0_0> { var τ_0_0 } %7 = apply %4(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %6 : $<τ_0_0> { var τ_0_0 } strong_release %1 : $<τ_0_0> { var τ_0_0 } dealloc_stack %2 : $*<τ_0_0> { var τ_0_0 } %11 = tuple () return %11 : $() } // CHECK-LABEL: sil @retain_can_be_used_by_other_pointer : $@convention(thin) (RetainUser, <τ_0_0> { var τ_0_0 } ) -> <τ_0_0> { var τ_0_0 } { // CHECK: strong_retain // CHECK: strong_retain // CHECK: strong_release sil @retain_can_be_used_by_other_pointer : $@convention(thin) (RetainUser, <τ_0_0> { var τ_0_0 } ) -> <τ_0_0> { var τ_0_0 } { bb0(%0 : $RetainUser, %1 : $<τ_0_0> { var τ_0_0 } ): %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $RetainUser apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %1 : $<τ_0_0> { var τ_0_0 } strong_release %0 : $RetainUser return %1 : $<τ_0_0> { var τ_0_0 } } // 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) () -> () { bb0: %0 = alloc_ref $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_indirectly_released_by_callee // CHECK: retain_value // CHECK: release_value sil @dont_remove_as_arg0_may_be_indirectly_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 : $() } // Remove a retain release "pair" for the local reference if a child object. // // The local 'Cls' reference is now effectively "moved" into the parent // 'Container' object, so the child will be destroyed with the parent. // The original SIL already has an over-release of the parent. // // TODO: This optimization is currently defeated because // - release_container marks anything '%2 = alloc_ref $Container' points to as escaping // - in this function, '%2 = alloc_ref $Container' points to '%1 = alloc_ref $Cls' // - therefore, the 'apply' may potentially release '%1 = alloc_ref $Cls' // // To hoist this 'release %1 : $Cls', AliasAnalysis alsos need to prove that // it isn't being hoisted above the last use. This information is not // properly communicated between AliasAnalysis and EscapeAnalysis. // // CHECK-LABEL: sil @remove_as_local_object_indirectly_escapes_to_callee // CHECK: retain_value // CHECK: release_value sil @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 : $() } // Remove a retain release "pair" for the local reference if a child object. // // The local 'Cls' reference is now effectively "moved" into the parent // 'Container' object, so the child will be destroyed with the parent. // // CHECK-LABEL: sil @local_object_indirectly_escapes_to_use_and_owned_arg // CHECK-NOT: retain_value // CHECK-NOT: release_value sil @local_object_indirectly_escapes_to_use_and_owned_arg : $@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 @use_container : $@convention(thin) (@guaranteed Container) -> () apply %f1 (%2) : $@convention(thin) (@guaranteed Container) -> () %f2 = function_ref @release_container : $@convention(thin) (Container) -> () apply %f2 (%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 @use_container : $@convention(thin) (@guaranteed Container) -> () { [%0: noescape **] [global: ] bb0(%0 : $Container): %1 = ref_element_addr %0 : $Container, #Container.c %2 = load %1 : $*Cls %r = tuple() return %r : $() } sil @release_container : $@convention(thin) (Container) -> () { [%0: noescape **] bb0(%0 : $Container): strong_release %0 : $Container %r = tuple() return %r : $() } sil @no_release_func : $@convention(thin) (Cls) -> () { [%0: noescape **] [global: ] 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 cannot 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) (<τ_0_0> { var τ_0_0 } ) -> () { // 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 bb // CHECK: bb4: // CHECK-NEXT: strong_release // CHECK-NEXT: tuple // CHECK-NEXT: return sil @double_hammock1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } cond_br undef, bb1, bb2 bb1: apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () br bb2 bb2: cond_br undef, bb3, bb4 bb3: apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () br bb4 bb4: strong_release %0 : $<τ_0_0> { var τ_0_0 } %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 bb // CHECK: bb2: // CHECK-NEXT: strong_release // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: strong_release // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: strong_retain // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: br bb // 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 bb // CHECK: bb2: // CHECK-NEXT: strong_retain // CHECK-NEXT: br bb // 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) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK: strong_retain // CHECK: strong_release sil @dont_move_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } cond_br undef, bb1, bb2 bb1: apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () br bb3 bb2: br bb3 bb3: strong_release %0 : $<τ_0_0> { var τ_0_0 } %2 = tuple() return %2 : $() } // CHECK-LABEL: sil @do_remove_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { // 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) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } strong_retain %0 : $<τ_0_0> { var τ_0_0 } cond_br undef, bb1, bb2 bb1: apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () br bb3 bb2: br bb3 bb3: strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_release %0 : $<τ_0_0> { var τ_0_0 } %2 = tuple() return %2 : $() } // CHECK-LABEL: sil @release_use_optimization : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () { // CHECK-NOT: strong_retain // CHECK: strong_release // CHECK-NOT: strong_release sil @release_use_optimization : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %2 = tuple() return %2 : $() } // CHECK-LABEL: sil @increment_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK: bb1: // CHECK-NEXT: strong_retain // CHECK-NEXT: strong_retain // CHECK-NEXT: br bb3 // CHECK: bb2: // CHECK-NEXT: strong_retain // CHECK-NEXT: apply // CHECK-NEXT: strong_retain // CHECK-NEXT: br bb3 // CHECK: bb3: // 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) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () cond_br undef, bb1, bb2 bb1: strong_retain %0 : $<τ_0_0> { var τ_0_0 } strong_retain %0 : $<τ_0_0> { var τ_0_0 } br bb3 bb2: strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } br bb3 bb3: apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %2 = tuple() return %2 : $() } // CHECK-LABEL: sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK: bb0( // CHECK-NEXT: function_ref // CHECK-NEXT: function_ref // CHECK-NEXT: strong_retain // CHECK-NEXT: apply // CHECK-NEXT: apply // CHECK-NEXT: cond_br // CHECK: bb1: // CHECK-NEXT: strong_release // CHECK-NEXT: strong_release // CHECK-NEXT: br bb3 // CHECK: strong_release sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () cond_br undef, bb1, bb2 bb1: strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_release %0 : $<τ_0_0> { var τ_0_0 } br bb3 bb2: strong_release %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () 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: strong_retain // CHECK: bb2: // CHECK: strong_retain // CHECK: bb3: // CHECK: strong_release 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 $<τ_0_0> { var τ_0_0 } strong_retain %2 : $<τ_0_0> { var τ_0_0 } br bb3 bb2: %3 = struct_extract %0 : $S, #S.x %4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $<τ_0_0> { var τ_0_0 } strong_retain %4 : $<τ_0_0> { var τ_0_0 } br bb3 bb3: %5 = struct_extract %0 : $S, #S.x %6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $<τ_0_0> { var τ_0_0 } %7 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %7(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %7(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %6 : $<τ_0_0> { var τ_0_0 } %11 = tuple() return %11 : $() } // CHECK-LABEL: sil @strip_off_layout_compatible_typed_geps : $@convention(thin) (S, FakeOptional) -> () { // 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) -> () { bb0(%0 : $S, %1 : $FakeOptional): %2 = struct_extract %0 : $S, #S.x strong_retain %2 : $Builtin.NativeObject release_value %0 : $S %3 = unchecked_enum_data %1 : $FakeOptional, #FakeOptional.some!enumelt strong_retain %3 : $Builtin.NativeObject release_value %1 : $FakeOptional %5 = tuple() return %5 : $() } // CHECK-LABEL: sil @strip_off_single_pred_args : $@convention(thin) (FakeOptional) -> () { // CHECK-NOT: retain_value // CHECK-NOT: strong_release sil @strip_off_single_pred_args : $@convention(thin) (FakeOptional) -> () { bb0(%0 : $FakeOptional): switch_enum %0 : $FakeOptional, case #FakeOptional.some!enumelt: bb1, case #FakeOptional.none!enumelt: bb2 bb1(%1 : $Builtin.NativeObject): retain_value %0 : $FakeOptional 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) -> () { // 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) -> () { bb0(%0 : $Either): retain_value %0 : $Either %1 = unchecked_enum_data %0 : $Either, #Either.Right!enumelt 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, #FakeOptional.some!enumelt, %0 : $Builtin.NativeObject strong_retain %0 : $Builtin.NativeObject release_value %1 : $FakeOptional %2 = tuple() return %2 : $() } // For now make sure we don't eliminate this. // CHECK-LABEL: sil @guaranteed_is_always_known_safe : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () { // CHECK: retain // CHECK: release sil @guaranteed_is_always_known_safe : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %2 = tuple() return %2 : $() } sil [_semantics "programtermination_point"] @fatalError : $@convention(thin) (StaticString, StaticString, StaticString) -> Never // 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, bb5 bb4: strong_release %0 : $Builtin.NativeObject %1 = tuple() return %1 : $() bb5: %39 = function_ref @fatalError : $@convention(thin) (StaticString, StaticString, StaticString) -> Never %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) (StaticString, StaticString, StaticString) -> Never unreachable } // Only check for the removal of RR in bb0 when loop arc is enabled. // // CHECK-LABEL: sil @propagate_postdominating_owned_release_info : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () { // CHECK: bb0( // CHECK-LOOP-NOT: retain // CHECK-LOOP-NOT: release // CHECK: bb1: // CHECK-NOT: retain // CHECK-NOT: release // CHECK: bb2: // CHECK: strong_release sil @propagate_postdominating_owned_release_info : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } br bb1 bb1: cond_br undef, bb1, bb2 bb2: strong_release %0 : $<τ_0_0> { var τ_0_0 } %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: strong_retain // CHECK: function_ref @guaranteed_use // CHECK: strong_release // CHECK: apply // CHECK: function_ref @guaranteed_use // CHECK: strong_retain // CHECK: function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () // CHECK: strong_release 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) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @branch_use1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): cond_br undef, bb1, bb2 bb1: strong_retain %0 : $<τ_0_0> { var τ_0_0 } %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () br bb3 bb2: strong_retain %0 : $<τ_0_0> { var τ_0_0 } br bb3 bb3: strong_release %0 : $<τ_0_0> { var τ_0_0 } %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) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK: strong_retain // CHECK: strong_retain // CHECK: strong_release sil @branch_use2 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): cond_br undef, bb1, bb2 bb1: strong_retain %0 : $<τ_0_0> { var τ_0_0 } %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () br bb3 bb2: strong_retain %0 : $<τ_0_0> { var τ_0_0 } br bb3 bb3: strong_release %0 : $<τ_0_0> { var τ_0_0 } %9999 = tuple() return %9999 : $() } // We can ignore this branch since bb3's use of %0 is dead. // // CHECK-LABEL: sil @branch_use3 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @branch_use3 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): cond_br undef, bb1, bb2 bb1: strong_retain %0 : $<τ_0_0> { var τ_0_0 } %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () br bb3(undef : $<τ_0_0> { var τ_0_0 } ) bb2: strong_retain %0 : $<τ_0_0> { var τ_0_0 } br bb3(%0 : $<τ_0_0> { var τ_0_0 } ) bb3(%2 : $<τ_0_0> { var τ_0_0 } ): strong_release %0 : $<τ_0_0> { var τ_0_0 } %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) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @cond_branch_use1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): strong_retain %0 : $<τ_0_0> { var τ_0_0 } %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %2 = integer_literal $Builtin.Int1, 0 cond_br %2, bb1, bb2 bb1: br bb3 bb2: br bb3 bb3: strong_release %0 : $<τ_0_0> { var τ_0_0 } %9999 = tuple() return %9999 : $() } // In this case, we can eliminate the retain, release pair since a cond_br does // not have any side-effects and is effectively a dead PHI. LLVM will clean up // the use if we do not. // // CHECK-LABEL: sil @cond_branch_use2 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @cond_branch_use2 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): strong_retain %0 : $<τ_0_0> { var τ_0_0 } %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %2 = integer_literal $Builtin.Int1, 0 cond_br %2, bb1(%0 : $<τ_0_0> { var τ_0_0 } ), bb2 bb1(%3 : $<τ_0_0> { var τ_0_0 } ): br bb3 bb2: br bb3 bb3: strong_release %0 : $<τ_0_0> { var τ_0_0 } %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil @cond_branch_use3 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @cond_branch_use3 : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): strong_retain %0 : $<τ_0_0> { var τ_0_0 } %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () %2 = integer_literal $Builtin.Int1, 0 cond_br %2, bb2(%0 : $<τ_0_0> { var τ_0_0 } ), bb1 bb2(%3 : $<τ_0_0> { var τ_0_0 } ): br bb3 bb1: br bb3 bb3: strong_release %0 : $<τ_0_0> { var τ_0_0 } %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 <τ_0_0> { var τ_0_0 } ) %1 = apply %0() : $@convention(thin) () -> (@owned <τ_0_0> { var τ_0_0 } ) %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %1 : $<τ_0_0> { var τ_0_0 } apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %1 : $<τ_0_0> { var τ_0_0 } strong_release %1 : $<τ_0_0> { var τ_0_0 } %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil @retains_that_are_not_removed_preserves_known_safety : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } , <τ_0_0> { var τ_0_0 } ) -> () { // 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 <τ_0_0> { var τ_0_0 } , <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } , %1 : $<τ_0_0> { var τ_0_0 } ): %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil @retains_that_are_removed_do_not_preserve_known_safety : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } , <τ_0_0> { var τ_0_0 } ) -> () { // 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 <τ_0_0> { var τ_0_0 } , <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } , %1 : $<τ_0_0> { var τ_0_0 } ): %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %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 $<τ_0_0> { var τ_0_0 } strong_retain %0 : $Cls %2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %1 : $<τ_0_0> { var τ_0_0 } strong_release %1 : $<τ_0_0> { var τ_0_0 } %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 $<τ_0_0> { var τ_0_0 } strong_retain %1 : $Cls %3 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %3(%2) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %3(%2) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %2 : $<τ_0_0> { var τ_0_0 } strong_release %2 : $<τ_0_0> { var τ_0_0 } %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil @must_use_test : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () { // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @must_use_test : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } ) -> () { bb0(%0 : $<τ_0_0> { var τ_0_0 } ): %1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_retain %0 : $<τ_0_0> { var τ_0_0 } apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } %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 $<τ_0_0> { var τ_0_0 } strong_retain %0 : $<τ_0_0> { var τ_0_0 } %3 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %3(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () apply %3(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_release %0 : $<τ_0_0> { var τ_0_0 } strong_release %0 : $<τ_0_0> { var τ_0_0 } %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"(%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) (<τ_0_0> { var τ_0_0 } ) -> () %1 = partial_apply %0() : $@convention(thin) (<τ_0_0> { var τ_0_0 } ) -> () strong_retain %1 : $@callee_owned (<τ_0_0> { var τ_0_0 } ) -> () %2 = convert_function %1 : $@callee_owned (<τ_0_0> { var τ_0_0 } ) -> () to $@callee_owned (<τ_0_0> { var τ_0_0 } ) -> () strong_release %2 : $@callee_owned (<τ_0_0> { var τ_0_0 } ) -> () %9999 = tuple() return %9999 : $() } // CHECK-LABEL: sil [serialized] @try_apply_test_1 : $@convention(thin) (Builtin.NativeObject) -> @error any Error { // CHECK: bb0 // CHECK: strong_retain // CHECK: bb1 // CHECK: strong_release // CHECK: bb2 // CHECK: strong_release sil [serialized] @try_apply_test_1 : $@convention(thin) (Builtin.NativeObject) -> @error any Error { bb0(%0 : $Builtin.NativeObject): strong_retain %0 : $Builtin.NativeObject %1 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error try_apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error, normal bb1, error bb2 bb1(%2 : $()): strong_release %0 : $Builtin.NativeObject return undef : $() bb2(%3 : $Error): strong_release %0 : $Builtin.NativeObject throw %3 : $Error } // CHECK-LABEL: sil [serialized] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error any Error { // CHECK: bb0( // CHECK: strong_retain // CHECK: try_apply // CHECK: bb1( // CHECK: strong_release // CHECK: bb2( // CHECK: strong_release sil [serialized] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error any Error { bb0(%0 : $Builtin.NativeObject): strong_retain %0 : $Builtin.NativeObject %1 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () %2 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error try_apply %2(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error, normal bb1, error bb2 bb1(%3 : $()): strong_release %0 : $Builtin.NativeObject return undef : $() bb2(%4 : $Error): strong_release %0 : $Builtin.NativeObject throw %4 : $Error } // CHECK-LABEL: sil hidden [noinline] @$try_apply_test_3 : // CHECK-NOT: strong_retain // CHECK-NOT: strong_release // CHECK-LABEL: } // end sil function '$try_apply_test_3' sil hidden [noinline] @$try_apply_test_3 : $@convention(thin) () -> @error any Error { bb0: %box = alloc_box $<τ_0_0> { var τ_0_0 } %proj = project_box %box : $<τ_0_0> { var τ_0_0 } , 0 %funcref = function_ref @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error any Error br bb1 bb1: strong_retain %box : $<τ_0_0> { var τ_0_0 } try_apply %funcref (%box) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } ) -> @error any Error, normal bbs, error bbe bbs(%s : $()): strong_release %box : $<τ_0_0> { var τ_0_0 } return undef : $() bbe(%e : $Error): strong_release %box : $<τ_0_0> { var τ_0_0 } throw %e : $Error } // In this control flow, ARC runs multiple iterations to get rid of and move the retain and releases. // In the first iteration, we will try to move id1/id3 towards each other. // we create new instructions and remove the old ones. However we had a bug to insert these newly created // instructions into the "interesting" instruction list. As a result, the in second iteration, // we end up ignoring the newly created id3. and will be able to move id2 across a potential release (id3). // // CHECK-LABEL: sil @interleaved_retain_release_with_multiple_arc_iteration // CHECK: strong_retain // CHECK: apply // CHECK: apply // CHECK: strong_retain // CHECK: strong_release sil @interleaved_retain_release_with_multiple_arc_iteration : $@convention(thin) (Builtin.NativeObject, @inout Builtin.NativeObject) -> () { bb0(%0 : $Builtin.NativeObject, %1 : $*Builtin.NativeObject): %6 = function_ref @use : $@convention(thin) (Builtin.NativeObject) -> () %2 = load %1 : $*Builtin.NativeObject strong_retain %2 : $Builtin.NativeObject // id 1 apply %6(%2) : $@convention(thin) (Builtin.NativeObject) -> () apply %6(%2) : $@convention(thin) (Builtin.NativeObject) -> () strong_retain %0 : $Builtin.NativeObject // id 2 %10 = tuple() strong_release %2 : $Builtin.NativeObject // id 3 strong_retain %0 : $Builtin.NativeObject // id 4 apply %6(%0) : $@convention(thin) (Builtin.NativeObject) -> () apply %6(%0) : $@convention(thin) (Builtin.NativeObject) -> () strong_release %0 : $Builtin.NativeObject // id 5 strong_release %0 : $Builtin.NativeObject // id 6 br bb2 // These are here to make sure we run 2nd iteration in arcopt. bb2: strong_retain %0 : $Builtin.NativeObject strong_retain %0 : $Builtin.NativeObject strong_release %0 : $Builtin.NativeObject strong_release %0 : $Builtin.NativeObject %5 = tuple() return %5 : $() } // CHECK-LABEL: sil @guaranteed_always_known_safe_bu : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { // CHECK: strong_retain // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @guaranteed_always_known_safe_bu : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { bb0(%0 : $Builtin.NativeObject): strong_retain %0 : $Builtin.NativeObject strong_retain %0 : $Builtin.NativeObject %1 = function_ref @use : $@convention(thin) (Builtin.NativeObject) -> () apply %1(%0) : $@convention(thin) (Builtin.NativeObject) -> () apply %1(%0) : $@convention(thin) (Builtin.NativeObject) -> () strong_release %0 : $Builtin.NativeObject return undef : $() } // CHECK-LABEL: sil @in_guaranteed_always_known_safe_bu : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () { // CHECK: strong_retain // CHECK-NOT: strong_retain // CHECK-NOT: strong_release sil @in_guaranteed_always_known_safe_bu : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () { bb0(%0 : $*Builtin.NativeObject): %1 = load %0 : $*Builtin.NativeObject strong_retain %1 : $Builtin.NativeObject strong_retain %1 : $Builtin.NativeObject %2 = function_ref @use : $@convention(thin) (Builtin.NativeObject) -> () apply %2(%1) : $@convention(thin) (Builtin.NativeObject) -> () apply %2(%1) : $@convention(thin) (Builtin.NativeObject) -> () strong_release %1 : $Builtin.NativeObject return undef : $() } // Make sure that we treat applications of callee_guaranteed functions as a // guaranteed use of the function object. // // CHECK-LABEL: sil @test_callee_guaranteed_is_treated_as_guaranteed : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () { // CHECK: strong_retain // CHECK: apply // CHECK: strong_release // CHECK: } // end sil function 'test_callee_guaranteed_is_treated_as_guaranteed' sil @test_callee_guaranteed_is_treated_as_guaranteed : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () { bb0(%0 : $@callee_guaranteed () -> ()): strong_retain %0 : $@callee_guaranteed () -> () apply %0() : $@callee_guaranteed () -> () strong_release %0 : $@callee_guaranteed () -> () %9999 = tuple() return %9999 : $() } // Make sure we can move a release across a releasenone functions. // // CHECK-LABEL: sil @testReleaseNoneAttribute // CHECK-NOT: strong_retain // CHECK: [[RELEASENONE:%.*]] = function_ref @releaseNone // CHECK-NOT: strong_retain // CHECK: apply [[RELEASENONE]] // CHECK-NOT: strong_retain // CHECK: [[MAYRELEASE:%.*]] = function_ref @mayRelease // CHECK-NOT: strong_retain // CHECK: apply [[MAYRELEASE]] // CHECK-NOT: strong_retain // CHECK: return // CHECK: } // end sil function 'testReleaseNoneAttribute' sil [releasenone] @releaseNone : $@convention(thin) () -> () sil @mayRelease : $@convention(thin) () -> () sil @testReleaseNoneAttribute : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () { bb0(%0 : $Builtin.NativeObject): %1 = function_ref @releaseNone : $@convention(thin) () -> () strong_retain %0 : $Builtin.NativeObject %2 = apply %1() : $@convention(thin) () -> () %3 = function_ref @mayRelease : $@convention(thin) () -> () %4 = apply %3() : $@convention(thin) () -> () strong_release %0 : $Builtin.NativeObject %10 = tuple() return %10 : $() } // Make sure that we eliminate the inner retain/release pair on the // partial_apply by treating it as an entrance. // CHECK-LABEL: sil @test_strong_entrance_partial_apply : $@convention(thin) () -> () { // CHECK: partial_apply // CHECK-NOT: strong_retain // CHECK: apply // CHECK: strong_release // CHECK-NOT: strong_release // CHECK: } // end sil function 'test_strong_entrance_partial_apply' sil @test_strong_entrance_partial_apply : $@convention(thin) () -> () { bb0: %0 = function_ref @mayRelease : $@convention(thin) () -> () %1 = partial_apply [callee_guaranteed] %0() : $@convention(thin) () -> () strong_retain %1 : $@callee_guaranteed () -> () apply %1() : $@callee_guaranteed () -> () strong_release %1 : $@callee_guaranteed () -> () strong_release %1 : $@callee_guaranteed () -> () %9999 = tuple() return %9999 : $() } //===----------------------------------------------------------------------===// // Test invoking EscapeAnalysis:mayReleaseContent on a builtin that takes // an address. This should simply not assert. // // Escape analysis crashes with // "an address is never a reference" error with -O -thread=sanitize //===----------------------------------------------------------------------===// // bufferMemory sil_global hidden @$s4test12bufferMemorySpys5UInt8VGvp : $UnsafeMutablePointer // x sil_global hidden @$s4test1xypvp : $Any sil [serialized] [always_inline] [readonly] [_semantics "string.makeUTF8"] @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // CHECK-LABEL: sil @testTsanInoutAccess : $@convention(thin) () -> () { // CHECK: alloc_global @$s4test12bufferMemorySpys5UInt8VGvp // CHECK: [[GLOBAL:%.*]] = global_addr @$s4test12bufferMemorySpys5UInt8VGvp : $*UnsafeMutablePointer // CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*UnsafeMutablePointer // CHECK: builtin "tsanInoutAccess"([[ACCESS]] : $*UnsafeMutablePointer) : $() // CHECK-LABEL: } // end sil function 'testTsanInoutAccess' sil @testTsanInoutAccess : $@convention(thin) () -> () { bb0: alloc_global @$s4test12bufferMemorySpys5UInt8VGvp %1 = global_addr @$s4test12bufferMemorySpys5UInt8VGvp : $*UnsafeMutablePointer %2 = integer_literal $Builtin.Int1, -1 alloc_global @$s4test1xypvp %4 = global_addr @$s4test1xypvp : $*Any %5 = string_literal utf8 "" %6 = integer_literal $Builtin.Word, 0 %7 = metatype $@thin String.Type // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:) %8 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String %9 = apply %8(%5, %6, %2, %7) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String %10 = init_existential_addr %4 : $*Any, $String store %9 to %10 : $*String %12 = begin_access [modify] [dynamic] %1 : $*UnsafeMutablePointer %13 = builtin "tsanInoutAccess"(%12 : $*UnsafeMutablePointer) : $() end_access %12 : $*UnsafeMutablePointer %15 = tuple () return %15 : $() } sil @closure : $@convention(thin) (@inout E, @guaranteed C) -> () sil @call_closure : $@convention(method) (@guaranteed @noescape @callee_guaranteed (@inout E) -> (), @inout StructWithEnum) -> @out S2 // CHECK-LABEL: sil @test_apply_with_out_arg : // CHECK: retain_value // CHECK: strong_release // CHECK: release_value // CHECK: } // end sil function 'test_apply_with_out_arg' sil @test_apply_with_out_arg : $@convention(method) (@guaranteed StructWithEnum) -> () { bb0(%0 : $StructWithEnum): %1 = alloc_stack $StructWithEnum store %0 to %1 : $*StructWithEnum %3 = struct_element_addr %1 : $*StructWithEnum, #StructWithEnum.e %4 = load %3 : $*E retain_value %4 : $E switch_enum %4 : $E, case #E.A!enumelt: bb1, default bb2 bb1(%7 : $C): %8 = alloc_stack $S2 %9 = function_ref @closure : $@convention(thin) (@inout E, @guaranteed C) -> () %10 = partial_apply [callee_guaranteed] [on_stack] %9(%7) : $@convention(thin) (@inout E, @guaranteed C) -> () %11 = function_ref @call_closure : $@convention(method) (@guaranteed @noescape @callee_guaranteed (@inout E) -> (), @inout StructWithEnum) -> @out S2 %12 = apply %11(%8, %10, %1) : $@convention(method) (@guaranteed @noescape @callee_guaranteed (@inout E) -> (), @inout StructWithEnum) -> @out S2 dealloc_stack %10 : $@noescape @callee_guaranteed (@inout E) -> () strong_release %7 : $C dealloc_stack %8 : $*S2 br bb3 bb2: release_value %4 : $E br bb3 bb3: dealloc_stack %1 : $*StructWithEnum %21 = tuple () return %21 : $() }