mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Also, add a third [serializable] state for functions whose bodies we *can* serialize, but only do so if they're referenced from another serialized function. This will be used for bodies synthesized for imported definitions, such as init(rawValue:), etc, and various thunks, but for now this change is NFC.
2149 lines
74 KiB
Plaintext
2149 lines
74 KiB
Plaintext
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts %s | %FileCheck %s
|
|
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -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 -assume-parsing-unqualified-ownership-sil -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 {
|
|
@sil_stored 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 "arc.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 : $()
|
|
}
|