blob: 1cc48079154a154b9da12dc1d919e0b9ac7de01d [file] [log] [blame]
// 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 -check-prefix=CHECK -check-prefix=CHECK-LOOP %s
// RUN: %target-sil-opt -enable-sil-verify-all -arc-loop-opts %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-LOOP %s
sil_stage canonical
import Builtin
import Swift
// Utilities
sil @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
sil @owned_user : $@convention(thin) (@owned _0_0> { var τ_0_0 } <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()
}
public enum FakeOptional<T> {
case none
case some(T)
}
class C {
init()
var w : FakeOptional<Builtin.NativeObject>
}
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<LTy, RTy> {
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 } <Builtin.Int32>)
sil [serialized] @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error 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 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
// 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 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%2 = integer_literal $Builtin.Int32, 1
%3 = integer_literal $Builtin.Int32, 2
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%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 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%4 = integer_literal $Builtin.Int64, 0
%5 = string_literal utf8 "123"
strong_release %0 : $_0_0> { var τ_0_0 } <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 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 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb1
bb1:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// SHOULD-NOT: strong_retain
// SHOULD-NOT: strong_release
sil @simple_alias_store_use_test : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = project_box %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>, 0
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%3 = integer_literal $Builtin.Int32, 2
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
store %3 to %1 : $*Builtin.Int32
strong_release %0 : $_0_0> { var τ_0_0 } <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: 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 } <Builtin.Int32>
%1a = project_box %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>, 0
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2 (%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%3 = load %1a : $*Builtin.Int32
strong_release %1 : $_0_0> { var τ_0_0 } <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: 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 } <Builtin.Int32>
%1a = project_box %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>, 0
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2 (%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%3 = load %1a : $*Builtin.Int32
strong_release %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%4 = tuple()
return %4: $()
}
// CHECK-LABEL: sil @silargument_retain_iterated : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <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 _0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%3 = unchecked_ref_cast %0 : $Cls to $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %1 : $Cls
apply %2(%3) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %2(%3) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
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 } <Builtin.Int32>) -> ()
// 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 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @the_kraken : $@convention(thin) () -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1() : $@convention(thin) () -> ()
apply %1() : $@convention(thin) () -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <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 $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %3 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1() : $@convention(thin) () -> Builtin.RawPointer
strong_release %3 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %3 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2(%0) : $@convention(thin) (Builtin.RawPointer) -> ()
strong_release %3 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %3 : $_0_0> { var τ_0_0 } <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 $_0_0> { var τ_0_0 } <Builtin.Int32>
%2 = alloc_stack $_0_0> { var τ_0_0 } <Builtin.Int32>
store %1 to %2 : $*<τ_0_0> { var τ_0_0 } <Builtin.Int32>
%4 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%6 = load %2 : $*<τ_0_0> { var τ_0_0 } <Builtin.Int32>
%7 = apply %4(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %6 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
dealloc_stack %2 : $*<τ_0_0> { var τ_0_0 } <Builtin.Int32>
%11 = tuple ()
return %11 : $()
}
// CHECK-LABEL: sil @retain_can_be_used_by_other_pointer : $@convention(thin) (RetainUser, <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> <τ_0_0> { var τ_0_0 } <Builtin.Int32> {
// 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 } <Builtin.Int32>) -> _0_0> { var τ_0_0 } <Builtin.Int32> {
bb0(%0 : $RetainUser, %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $RetainUser
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %0 : $RetainUser
return %1 : $_0_0> { var τ_0_0 } <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_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 : $()
}
// CHECK-LABEL: sil @dont_remove_as_local_object_indirectly_escapes_to_callee
// CHECK: retain_value
// CHECK: release_value
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 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 } <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 bb
// CHECK: bb4:
// CHECK-NEXT: strong_release
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @double_hammock1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
cond_br undef, bb1, bb2
bb1:
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
br bb2
bb2:
cond_br undef, bb3, bb4
bb3:
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
br bb4
bb4:
strong_release %0 : $_0_0> { var τ_0_0 } <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 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 } <Builtin.Int32>) -> () {
// CHECK: strong_retain
// CHECK: strong_release
sil @dont_move_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
cond_br undef, bb1, bb2
bb1:
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
br bb3
bb2:
br bb3
bb3:
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @do_remove_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
cond_br undef, bb1, bb2
bb1:
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
br bb3
bb2:
br bb3
bb3:
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @release_use_optimization : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// CHECK-NOT: strong_retain
// CHECK: strong_release
// CHECK-NOT: strong_release
sil @release_use_optimization : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @increment_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// 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 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3
bb2:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3
bb3:
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// 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 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
cond_br undef, bb1, bb2
bb1:
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3
bb2:
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <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: 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 } <Builtin.Int32>
strong_retain %2 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3
bb2:
%3 = struct_extract %0 : $S, #S.x
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %4 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3
bb3:
%5 = struct_extract %0 : $S, #S.x
%6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $_0_0> { var τ_0_0 } <Builtin.Int32>
%7 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %7(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %7(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %6 : $_0_0> { var τ_0_0 } <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 <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// CHECK: retain
// CHECK: release
sil @guaranteed_is_always_known_safe : $@convention(thin) (@guaranteed _0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%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 } <Builtin.Int32>) -> () {
// 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 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb1
bb1:
cond_br undef, bb1, bb2
bb2:
strong_release %0 : $_0_0> { var τ_0_0 } <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: 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 } <Builtin.Int32>) -> () {
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @branch_use1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
br bb3
bb2:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3
bb3:
strong_release %0 : $_0_0> { var τ_0_0 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// CHECK: strong_retain
// CHECK: strong_retain
// CHECK: strong_release
sil @branch_use2 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
br bb3
bb2:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3
bb3:
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%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 } <Builtin.Int32>) -> () {
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @branch_use3 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
br bb3(undef : $_0_0> { var τ_0_0 } <Builtin.Int32>)
bb2:
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
br bb3(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>)
bb3(%2 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
strong_release %0 : $_0_0> { var τ_0_0 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @cond_branch_use1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%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 } <Builtin.Int32>
%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 } <Builtin.Int32>) -> () {
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @cond_branch_use2 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%2 = integer_literal $Builtin.Int1, 0
cond_br %2, bb1(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>), bb2
bb1(%3 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
br bb3
bb2:
br bb3
bb3:
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @cond_branch_use3 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @cond_branch_use3 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%2 = integer_literal $Builtin.Int1, 0
cond_br %2, bb2(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>), bb1
bb2(%3 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
br bb3
bb1:
br bb3
bb3:
strong_release %0 : $_0_0> { var τ_0_0 } <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 _0_0> { var τ_0_0 } <Builtin.Int32>)
%1 = apply %0() : $@convention(thin) () -> (@owned _0_0> { var τ_0_0 } <Builtin.Int32>)
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @retains_that_are_not_removed_preserves_known_safety : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>, <τ_0_0> { var τ_0_0 } <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 _0_0> { var τ_0_0 } <Builtin.Int32>, _0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>, %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @retains_that_are_removed_do_not_preserve_known_safety : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>, <τ_0_0> { var τ_0_0 } <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 _0_0> { var τ_0_0 } <Builtin.Int32>, _0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>, %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %2(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <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 $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $Cls
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %2(%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %1 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %1 : $_0_0> { var τ_0_0 } <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 $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %1 : $Cls
%3 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %3(%2) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %3(%2) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %2 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %2 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @must_use_test : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
sil @must_use_test : $@convention(thin) (@owned _0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
bb0(%0 : $_0_0> { var τ_0_0 } <Builtin.Int32>):
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <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 $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_retain %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
%3 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %3(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
apply %3(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %0 : $_0_0> { var τ_0_0 } <Builtin.Int32>
strong_release %0 : $_0_0> { var τ_0_0 } <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) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%1 = partial_apply %0() : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_retain %1 : $@callee_owned (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%2 = convert_function %1 : $@callee_owned (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () to $@callee_owned (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
strong_release %2 : $@callee_owned (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil [serialized] @try_apply_test_1 : $@convention(thin) (Builtin.NativeObject) -> @error 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 Error {
bb0(%0 : $Builtin.NativeObject):
strong_retain %0 : $Builtin.NativeObject
%1 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error Error
try_apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error 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 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 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 Error
try_apply %2(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error 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
}
// 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 elimiante 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 : $()
}