mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Type annotations for instruction operands are omitted, e.g. ``` %3 = struct $S(%1, %2) ``` Operand types are redundant anyway and were only used for sanity checking in the SIL parser. But: operand types _are_ printed if the definition of the operand value was not printed yet. This happens: * if the block with the definition appears after the block where the operand's instruction is located * if a block or instruction is printed in isolation, e.g. in a debugger The old behavior can be restored with `-Xllvm -sil-print-types`. This option is added to many existing test files which check for operand types in their check-lines.
2445 lines
85 KiB
Plaintext
2445 lines
85 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts %s | %FileCheck %s
|
|
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -enable-loop-arc=1 -arc-sequence-opts %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-LOOP %s
|
|
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all -arc-loop-opts %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-LOOP %s
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
// Utilities
|
|
|
|
sil @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <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>
|
|
}
|
|
|
|
enum E {
|
|
case A(C)
|
|
case B
|
|
}
|
|
|
|
struct StructWithEnum {
|
|
@_hasStorage var e: E { get }
|
|
init(e: E)
|
|
}
|
|
|
|
|
|
sil @cls_use : $@convention(thin) (@owned Cls) -> ()
|
|
|
|
class Container {
|
|
@_hasStorage var c : Cls
|
|
init()
|
|
}
|
|
|
|
class RetainUser { }
|
|
|
|
sil @rawpointer_use: $@convention(thin) (Builtin.RawPointer) -> ()
|
|
|
|
enum Either<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 any Error
|
|
|
|
/////////////////
|
|
// Basic Tests //
|
|
/////////////////
|
|
// CHECK-LABEL: sil @simple_retain_release_pair : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @simple_retain_release_pair : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @simple_copyvalue_destroyvalue_pair : $@convention(thin) (S) -> S
|
|
// CHECK: bb0({{%[0-9]+}} : $S)
|
|
// CHECK-NEXT: return
|
|
sil @simple_copyvalue_destroyvalue_pair : $@convention(thin) (S) -> S {
|
|
bb0(%0 : $S):
|
|
retain_value %0 : $S
|
|
release_value %0 : $S
|
|
retain_value %0 : $S
|
|
release_value %0 : $S
|
|
retain_value %0 : $S
|
|
release_value %0 : $S
|
|
return %0 : $S
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_retain_over_non_side_effect_instructions : $@convention(thin) (Builtin.NativeObject, Builtin.Int64) -> Builtin.Int1
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: builtin
|
|
// CHECK-NEXT: return
|
|
sil @delete_retain_over_non_side_effect_instructions : $@convention(thin) (Builtin.NativeObject, Builtin.Int64) -> (Builtin.Int1) {
|
|
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int64):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%3 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return %3 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_copyvalue_over_non_side_effect_instructions : $@convention(thin) (S, Builtin.Int64) -> Builtin.Int1
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: builtin
|
|
// CHECK-NEXT: return
|
|
sil @delete_copyvalue_over_non_side_effect_instructions : $@convention(thin) (S, Builtin.Int64) -> (Builtin.Int1) {
|
|
bb0(%0 : $S, %1 : $Builtin.Int64):
|
|
retain_value %0 : $S
|
|
%3 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1
|
|
release_value %0 : $S
|
|
return %3 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_retain_over_single_potential_decrement : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject) -> ()
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @delete_retain_over_single_potential_decrement : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
strong_release %1 : $Builtin.NativeObject
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_copyvalue_over_single_potential_decrement : $@convention(thin) (S, Builtin.NativeObject) -> ()
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @delete_copyvalue_over_single_potential_decrement : $@convention(thin) (S, Builtin.NativeObject) -> () {
|
|
bb0(%0 : $S, %1 : $Builtin.NativeObject):
|
|
retain_value %0 : $S
|
|
strong_release %1 : $Builtin.NativeObject
|
|
release_value %0 : $S
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_delete_retain_over_decrement_use : $@convention(thin) (<τ_0_0> { var τ_0_0 } <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: $()
|
|
}
|
|
|
|
struct Int {
|
|
var value : Builtin.Int64
|
|
}
|
|
|
|
sil @guaranteed_call : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Builtin.Int64>) -> () {
|
|
[%0: noescape **]
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>):
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
sil @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Builtin.Int64>) -> @error any Error {
|
|
[%0: noescape **]
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>):
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [noinline] @$test_guaranteed_call :
|
|
// CHECK: bb1{{.*}}:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: apply
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-LABEL: } // end sil function '$test_guaranteed_call'
|
|
sil hidden [noinline] @$test_guaranteed_call : $@convention(thin) () -> () {
|
|
bb0:
|
|
%box = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
%proj = project_box %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>, 0
|
|
%0 = integer_literal $Builtin.Int64, 1
|
|
%1 = integer_literal $Builtin.Int64, 100
|
|
%funcref = function_ref @guaranteed_call : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Builtin.Int64>) -> ()
|
|
%3 = struct $Int (%0 : $Builtin.Int64)
|
|
%6 = integer_literal $Builtin.Int1, -1
|
|
br bb1(%0 : $Builtin.Int64)
|
|
|
|
bb1(%8 : $Builtin.Int64):
|
|
%9 = builtin "sadd_with_overflow_Int64"(%8 : $Builtin.Int64, %0 : $Builtin.Int64, %6 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
|
|
%10 = tuple_extract %9 : $(Builtin.Int64, Builtin.Int1), 0
|
|
%11 = struct $Int (%10 : $Builtin.Int64)
|
|
%12 = builtin "cmp_eq_Int64"(%10 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1
|
|
strong_retain %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
apply %funcref (%box) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Builtin.Int64>) -> ()
|
|
strong_release %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
cond_br %12, bb3, bb2
|
|
|
|
bb2:
|
|
br bb1(%10 : $Builtin.Int64)
|
|
|
|
bb3:
|
|
strong_release %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
%17 = tuple ()
|
|
return %17 : $()
|
|
}
|
|
|
|
// 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) () -> () {
|
|
bb0:
|
|
%0 = alloc_ref $Cls
|
|
%1 = function_ref @no_release_func : $@convention(thin) (Cls) -> ()
|
|
strong_retain %0 : $Cls
|
|
apply %1 (%0) : $@convention(thin) (Cls) -> ()
|
|
apply %1 (%0) : $@convention(thin) (Cls) -> ()
|
|
strong_release %0 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_remove_as_arg0_may_be_indirectly_released_by_callee
|
|
// CHECK: retain_value
|
|
// CHECK: release_value
|
|
sil @dont_remove_as_arg0_may_be_indirectly_released_by_callee : $@convention(thin) (Cls, Cls) -> () {
|
|
bb0(%0 : $Cls, %1 : $Cls):
|
|
%2 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> ()
|
|
retain_value %0 : $Cls
|
|
apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> ()
|
|
release_value %0 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @remove_as_local_object_does_not_escape_to_callee
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @remove_as_local_object_does_not_escape_to_callee : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%1 = alloc_ref $Cls
|
|
retain_value %1 : $Cls
|
|
%f1 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> ()
|
|
release_value %1 : $Cls
|
|
%f2 = function_ref @no_release_func : $@convention(thin) (Cls) -> ()
|
|
apply %f2 (%1) : $@convention(thin) (Cls) -> ()
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// Remove a retain release "pair" for the local reference if a child object.
|
|
//
|
|
// The local 'Cls' reference is now effectively "moved" into the parent
|
|
// 'Container' object, so the child will be destroyed with the parent.
|
|
// The original SIL already has an over-release of the parent.
|
|
//
|
|
// TODO: This optimization is currently defeated because
|
|
// - release_container marks anything '%2 = alloc_ref $Container' points to as escaping
|
|
// - in this function, '%2 = alloc_ref $Container' points to '%1 = alloc_ref $Cls'
|
|
// - therefore, the 'apply' may potentially release '%1 = alloc_ref $Cls'
|
|
//
|
|
// To hoist this 'release %1 : $Cls', AliasAnalysis alsos need to prove that
|
|
// it isn't being hoisted above the last use. This information is not
|
|
// properly communicated between AliasAnalysis and EscapeAnalysis.
|
|
//
|
|
// CHECK-LABEL: sil @remove_as_local_object_indirectly_escapes_to_callee
|
|
// CHECK: retain_value
|
|
// CHECK: release_value
|
|
sil @remove_as_local_object_indirectly_escapes_to_callee : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%1 = alloc_ref $Cls
|
|
%2 = alloc_ref $Container
|
|
%3 = ref_element_addr %2 : $Container, #Container.c
|
|
store %1 to %3 : $*Cls
|
|
retain_value %1 : $Cls
|
|
%f1 = function_ref @release_container : $@convention(thin) (Container) -> ()
|
|
apply %f1 (%2) : $@convention(thin) (Container) -> ()
|
|
apply %f1 (%2) : $@convention(thin) (Container) -> ()
|
|
release_value %1 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// Remove a retain release "pair" for the local reference if a child object.
|
|
//
|
|
// The local 'Cls' reference is now effectively "moved" into the parent
|
|
// 'Container' object, so the child will be destroyed with the parent.
|
|
//
|
|
// CHECK-LABEL: sil @local_object_indirectly_escapes_to_use_and_owned_arg
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: release_value
|
|
sil @local_object_indirectly_escapes_to_use_and_owned_arg : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%1 = alloc_ref $Cls
|
|
%2 = alloc_ref $Container
|
|
%3 = ref_element_addr %2 : $Container, #Container.c
|
|
store %1 to %3 : $*Cls
|
|
retain_value %1 : $Cls
|
|
%f1 = function_ref @use_container : $@convention(thin) (@guaranteed Container) -> ()
|
|
apply %f1 (%2) : $@convention(thin) (@guaranteed Container) -> ()
|
|
%f2 = function_ref @release_container : $@convention(thin) (Container) -> ()
|
|
apply %f2 (%2) : $@convention(thin) (Container) -> ()
|
|
release_value %1 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @release_arg1 : $@convention(thin) (Cls, Cls) -> () {
|
|
bb0(%0 : $Cls, %1 : $Cls):
|
|
strong_release %1 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @use_container : $@convention(thin) (@guaranteed Container) -> () {
|
|
[%0: noescape **]
|
|
[global: ]
|
|
bb0(%0 : $Container):
|
|
%1 = ref_element_addr %0 : $Container, #Container.c
|
|
%2 = load %1 : $*Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @release_container : $@convention(thin) (Container) -> () {
|
|
[%0: noescape **]
|
|
bb0(%0 : $Container):
|
|
strong_release %0 : $Container
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @no_release_func : $@convention(thin) (Cls) -> () {
|
|
[%0: noescape **]
|
|
[global: ]
|
|
bb0(%0 : $Cls):
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
////////////////////
|
|
// Multi-BB tests //
|
|
////////////////////
|
|
|
|
//////////////
|
|
// Hammocks //
|
|
//////////////
|
|
|
|
// CHECK-LABEL: sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This hammock cannot be optimized.
|
|
// CHECK-LABEL: sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
/// This hammock can't be optimized.
|
|
// CHECK-LABEL: sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This should not be optimizable.
|
|
// CHECK-LABEL: sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_release
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
////////////////////
|
|
// Double Hammock //
|
|
////////////////////
|
|
|
|
// Make sure we do not do anything in the presence of double partial
|
|
// applies. This is due to issues related to the two branches of the two
|
|
// diamonds not being control dependent.
|
|
// CHECK-LABEL: sil @double_hammock1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <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
|
|
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: 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
|
|
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, %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 any Error {
|
|
// CHECK: bb0
|
|
// CHECK: strong_retain
|
|
// CHECK: bb1
|
|
// CHECK: strong_release
|
|
// CHECK: bb2
|
|
// CHECK: strong_release
|
|
sil [serialized] @try_apply_test_1 : $@convention(thin) (Builtin.NativeObject) -> @error any Error {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%1 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error
|
|
try_apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error, normal bb1, error bb2
|
|
|
|
bb1(%2 : $()):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return undef : $()
|
|
|
|
bb2(%3 : $Error):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
throw %3 : $Error
|
|
}
|
|
|
|
// CHECK-LABEL: sil [serialized] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error any Error {
|
|
// CHECK: bb0(
|
|
// CHECK: strong_retain
|
|
// CHECK: try_apply
|
|
// CHECK: bb1(
|
|
// CHECK: strong_release
|
|
// CHECK: bb2(
|
|
// CHECK: strong_release
|
|
sil [serialized] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error any Error {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%1 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
%2 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error
|
|
try_apply %2(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error any Error, normal bb1, error bb2
|
|
|
|
bb1(%3 : $()):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return undef : $()
|
|
|
|
bb2(%4 : $Error):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
throw %4 : $Error
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [noinline] @$try_apply_test_3 :
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK-LABEL: } // end sil function '$try_apply_test_3'
|
|
sil hidden [noinline] @$try_apply_test_3 : $@convention(thin) () -> @error any Error {
|
|
bb0:
|
|
%box = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
%proj = project_box %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>, 0
|
|
%funcref = function_ref @guaranteed_box_throwing_use : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Builtin.Int64>) -> @error any Error
|
|
br bb1
|
|
|
|
bb1:
|
|
strong_retain %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
try_apply %funcref (%box) : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Builtin.Int64>) -> @error any Error, normal bbs, error bbe
|
|
|
|
bbs(%s : $()):
|
|
strong_release %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
return undef : $()
|
|
|
|
bbe(%e : $Error):
|
|
strong_release %box : $<τ_0_0> { var τ_0_0 } <Builtin.Int64>
|
|
throw %e : $Error
|
|
}
|
|
|
|
// In this control flow, ARC runs multiple iterations to get rid of and move the retain and releases.
|
|
// In the first iteration, we will try to move id1/id3 towards each other.
|
|
// we create new instructions and remove the old ones. However we had a bug to insert these newly created
|
|
// instructions into the "interesting" instruction list. As a result, the in second iteration,
|
|
// we end up ignoring the newly created id3. and will be able to move id2 across a potential release (id3).
|
|
//
|
|
// CHECK-LABEL: sil @interleaved_retain_release_with_multiple_arc_iteration
|
|
// CHECK: strong_retain
|
|
// CHECK: apply
|
|
// CHECK: apply
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
sil @interleaved_retain_release_with_multiple_arc_iteration : $@convention(thin) (Builtin.NativeObject, @inout Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
|
|
%6 = function_ref @use : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
%2 = load %1 : $*Builtin.NativeObject
|
|
|
|
strong_retain %2 : $Builtin.NativeObject // id 1
|
|
apply %6(%2) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %6(%2) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
|
|
strong_retain %0 : $Builtin.NativeObject // id 2
|
|
|
|
%10 = tuple()
|
|
|
|
strong_release %2 : $Builtin.NativeObject // id 3
|
|
|
|
strong_retain %0 : $Builtin.NativeObject // id 4
|
|
apply %6(%0) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %6(%0) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
strong_release %0 : $Builtin.NativeObject // id 5
|
|
strong_release %0 : $Builtin.NativeObject // id 6
|
|
br bb2
|
|
|
|
// These are here to make sure we run 2nd iteration in arcopt.
|
|
bb2:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
strong_release %0 : $Builtin.NativeObject
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%5 = tuple()
|
|
return %5 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @guaranteed_always_known_safe_bu : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
|
|
// CHECK: strong_retain
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @guaranteed_always_known_safe_bu : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%1 = function_ref @use : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %1(%0) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %1(%0) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return undef : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @in_guaranteed_always_known_safe_bu : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () {
|
|
// CHECK: strong_retain
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @in_guaranteed_always_known_safe_bu : $@convention(thin) (@in_guaranteed Builtin.NativeObject) -> () {
|
|
bb0(%0 : $*Builtin.NativeObject):
|
|
%1 = load %0 : $*Builtin.NativeObject
|
|
strong_retain %1 : $Builtin.NativeObject
|
|
strong_retain %1 : $Builtin.NativeObject
|
|
%2 = function_ref @use : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %2(%1) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
apply %2(%1) : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
strong_release %1 : $Builtin.NativeObject
|
|
return undef : $()
|
|
}
|
|
|
|
// Make sure that we treat applications of callee_guaranteed functions as a
|
|
// guaranteed use of the function object.
|
|
//
|
|
// CHECK-LABEL: sil @test_callee_guaranteed_is_treated_as_guaranteed : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
|
|
// CHECK: strong_retain
|
|
// CHECK: apply
|
|
// CHECK: strong_release
|
|
// CHECK: } // end sil function 'test_callee_guaranteed_is_treated_as_guaranteed'
|
|
sil @test_callee_guaranteed_is_treated_as_guaranteed : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
|
|
bb0(%0 : $@callee_guaranteed () -> ()):
|
|
strong_retain %0 : $@callee_guaranteed () -> ()
|
|
apply %0() : $@callee_guaranteed () -> ()
|
|
strong_release %0 : $@callee_guaranteed () -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// Make sure we can move a release across a releasenone functions.
|
|
//
|
|
// CHECK-LABEL: sil @testReleaseNoneAttribute
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: [[RELEASENONE:%.*]] = function_ref @releaseNone
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: apply [[RELEASENONE]]
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: [[MAYRELEASE:%.*]] = function_ref @mayRelease
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: apply [[MAYRELEASE]]
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: return
|
|
// CHECK: } // end sil function 'testReleaseNoneAttribute'
|
|
sil [releasenone] @releaseNone : $@convention(thin) () -> ()
|
|
sil @mayRelease : $@convention(thin) () -> ()
|
|
|
|
sil @testReleaseNoneAttribute : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
%1 = function_ref @releaseNone : $@convention(thin) () -> ()
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%2 = apply %1() : $@convention(thin) () -> ()
|
|
%3 = function_ref @mayRelease : $@convention(thin) () -> ()
|
|
%4 = apply %3() : $@convention(thin) () -> ()
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%10 = tuple()
|
|
return %10 : $()
|
|
}
|
|
|
|
// Make sure that we eliminate the inner retain/release pair on the
|
|
// partial_apply by treating it as an entrance.
|
|
// CHECK-LABEL: sil @test_strong_entrance_partial_apply : $@convention(thin) () -> () {
|
|
// CHECK: partial_apply
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: apply
|
|
// CHECK: strong_release
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: } // end sil function 'test_strong_entrance_partial_apply'
|
|
sil @test_strong_entrance_partial_apply : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = function_ref @mayRelease : $@convention(thin) () -> ()
|
|
%1 = partial_apply [callee_guaranteed] %0() : $@convention(thin) () -> ()
|
|
strong_retain %1 : $@callee_guaranteed () -> ()
|
|
apply %1() : $@callee_guaranteed () -> ()
|
|
strong_release %1 : $@callee_guaranteed () -> ()
|
|
strong_release %1 : $@callee_guaranteed () -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Test invoking EscapeAnalysis:mayReleaseContent on a builtin that takes
|
|
// an address. This should simply not assert.
|
|
//
|
|
// <rdar://problem/60190962> Escape analysis crashes with
|
|
// "an address is never a reference" error with -O -thread=sanitize
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// bufferMemory
|
|
sil_global hidden @$s4test12bufferMemorySpys5UInt8VGvp : $UnsafeMutablePointer<UInt8>
|
|
|
|
// x
|
|
sil_global hidden @$s4test1xypvp : $Any
|
|
|
|
sil [serialized] [always_inline] [readonly] [_semantics "string.makeUTF8"] @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
|
|
// CHECK-LABEL: sil @testTsanInoutAccess : $@convention(thin) () -> () {
|
|
// CHECK: alloc_global @$s4test12bufferMemorySpys5UInt8VGvp
|
|
// CHECK: [[GLOBAL:%.*]] = global_addr @$s4test12bufferMemorySpys5UInt8VGvp : $*UnsafeMutablePointer<UInt8>
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[GLOBAL]] : $*UnsafeMutablePointer<UInt8>
|
|
// CHECK: builtin "tsanInoutAccess"([[ACCESS]] : $*UnsafeMutablePointer<UInt8>) : $()
|
|
// CHECK-LABEL: } // end sil function 'testTsanInoutAccess'
|
|
sil @testTsanInoutAccess : $@convention(thin) () -> () {
|
|
bb0:
|
|
alloc_global @$s4test12bufferMemorySpys5UInt8VGvp
|
|
%1 = global_addr @$s4test12bufferMemorySpys5UInt8VGvp : $*UnsafeMutablePointer<UInt8>
|
|
%2 = integer_literal $Builtin.Int1, -1
|
|
alloc_global @$s4test1xypvp
|
|
%4 = global_addr @$s4test1xypvp : $*Any
|
|
%5 = string_literal utf8 ""
|
|
%6 = integer_literal $Builtin.Word, 0
|
|
%7 = metatype $@thin String.Type
|
|
// function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
|
|
%8 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
%9 = apply %8(%5, %6, %2, %7) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
|
|
%10 = init_existential_addr %4 : $*Any, $String
|
|
store %9 to %10 : $*String
|
|
%12 = begin_access [modify] [dynamic] %1 : $*UnsafeMutablePointer<UInt8>
|
|
%13 = builtin "tsanInoutAccess"(%12 : $*UnsafeMutablePointer<UInt8>) : $()
|
|
end_access %12 : $*UnsafeMutablePointer<UInt8>
|
|
%15 = tuple ()
|
|
return %15 : $()
|
|
}
|
|
|
|
sil @closure : $@convention(thin) (@inout E, @guaranteed C) -> ()
|
|
sil @call_closure : $@convention(method) (@guaranteed @noescape @callee_guaranteed (@inout E) -> (), @inout StructWithEnum) -> @out S2
|
|
|
|
// CHECK-LABEL: sil @test_apply_with_out_arg :
|
|
// CHECK: retain_value
|
|
// CHECK: strong_release
|
|
// CHECK: release_value
|
|
// CHECK: } // end sil function 'test_apply_with_out_arg'
|
|
sil @test_apply_with_out_arg : $@convention(method) (@guaranteed StructWithEnum) -> () {
|
|
bb0(%0 : $StructWithEnum):
|
|
%1 = alloc_stack $StructWithEnum
|
|
store %0 to %1 : $*StructWithEnum
|
|
%3 = struct_element_addr %1 : $*StructWithEnum, #StructWithEnum.e
|
|
%4 = load %3 : $*E
|
|
retain_value %4 : $E
|
|
switch_enum %4 : $E, case #E.A!enumelt: bb1, default bb2
|
|
|
|
|
|
bb1(%7 : $C):
|
|
%8 = alloc_stack $S2
|
|
%9 = function_ref @closure : $@convention(thin) (@inout E, @guaranteed C) -> ()
|
|
%10 = partial_apply [callee_guaranteed] [on_stack] %9(%7) : $@convention(thin) (@inout E, @guaranteed C) -> ()
|
|
%11 = function_ref @call_closure : $@convention(method) (@guaranteed @noescape @callee_guaranteed (@inout E) -> (), @inout StructWithEnum) -> @out S2
|
|
%12 = apply %11(%8, %10, %1) : $@convention(method) (@guaranteed @noescape @callee_guaranteed (@inout E) -> (), @inout StructWithEnum) -> @out S2
|
|
dealloc_stack %10 : $@noescape @callee_guaranteed (@inout E) -> ()
|
|
strong_release %7 : $C
|
|
dealloc_stack %8 : $*S2
|
|
br bb3
|
|
|
|
bb2:
|
|
release_value %4 : $E
|
|
br bb3
|
|
|
|
bb3:
|
|
dealloc_stack %1 : $*StructWithEnum
|
|
%21 = tuple ()
|
|
return %21 : $()
|
|
}
|
|
|