mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Deinitializer side effects severely handicap the connection-graph based EscapeAnalysis. Because it's not flow-sensitive, this approach falls apart whenever an object is released in the current function, which makes it seem to have escaped everywhere (it generally doesn't matter if it doesn't escape until the release point, but the analysis can't discern that). This can be slightly mitigated by realizing that releasing an object can only cause things it points to to escape if the object itself has references or pointers. Fix: Don't create a escaping content node when releasing an object that can't contain any references or pointers. The previous commit, "Fix EscapeAnalysis::mayReleaseContent" would defeat release-hoisting in important cases without doing anything else. Adding this extra precision to the connection graph avoids some regressions.
2384 lines
84 KiB
Plaintext
2384 lines
84 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts %s | %FileCheck %s
|
|
// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=1 -arc-sequence-opts %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-LOOP %s
|
|
// RUN: %target-sil-opt -enable-sil-verify-all -arc-loop-opts %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-LOOP %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
// Utilities
|
|
|
|
sil @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
|
|
sil @owned_user : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
|
|
struct S {
|
|
var x : Builtin.NativeObject
|
|
}
|
|
sil @S_user : $@convention(thin) (S) -> ()
|
|
|
|
struct S2 {
|
|
var x : Builtin.Int32
|
|
var y : Builtin.NativeObject
|
|
var z : Builtin.Int32
|
|
}
|
|
|
|
struct S3 {
|
|
var x : Builtin.Int32
|
|
var y : Builtin.NativeObject
|
|
var y1 : Builtin.NativeObject
|
|
var z : Builtin.Int32
|
|
}
|
|
|
|
class Cls {
|
|
var random : Builtin.Int32
|
|
|
|
init()
|
|
}
|
|
|
|
public enum FakeOptional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
class C {
|
|
init()
|
|
var w : FakeOptional<Builtin.NativeObject>
|
|
}
|
|
|
|
sil @cls_use : $@convention(thin) (@owned Cls) -> ()
|
|
|
|
class Container {
|
|
@_hasStorage var c : Cls
|
|
init()
|
|
}
|
|
|
|
class RetainUser { }
|
|
|
|
sil @rawpointer_use: $@convention(thin) (Builtin.RawPointer) -> ()
|
|
|
|
enum Either<LTy, RTy> {
|
|
case Left(LTy)
|
|
case Right(RTy)
|
|
}
|
|
|
|
struct StaticString {
|
|
/// Either a pointer to the start of UTF-8 data, or an integer representation
|
|
/// of a single Unicode scalar.
|
|
var _startPtrOrData: Builtin.RawPointer
|
|
|
|
/// If `_startPtrOrData` is a pointer, contains the length of the UTF-8 data
|
|
/// in bytes.
|
|
var _byteSize: Builtin.Word
|
|
|
|
/// Extra flags:
|
|
///
|
|
/// - bit 0: set to 0 if `_startPtrOrData` is a pointer, or to 1 if it is a
|
|
/// Unicode scalar.
|
|
///
|
|
/// - bit 1: set to 1 if `_startPtrOrData` is a pointer and string data is
|
|
/// ASCII.
|
|
var _flags: Builtin.Int8
|
|
}
|
|
|
|
public protocol Error {
|
|
var _domain: Builtin.Int32 { get }
|
|
var _code: Builtin.Int32 { get }
|
|
}
|
|
|
|
sil [serialized] @use : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
sil [serialized] @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
|
|
sil [serialized] @owned_return : $@convention(thin) () -> (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>)
|
|
|
|
sil [serialized] @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error Error
|
|
|
|
/////////////////
|
|
// Basic Tests //
|
|
/////////////////
|
|
// CHECK-LABEL: sil @simple_retain_release_pair : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @simple_retain_release_pair : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple ()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @simple_copyvalue_destroyvalue_pair : $@convention(thin) (S) -> S
|
|
// CHECK: bb0({{%[0-9]+}} : $S)
|
|
// CHECK-NEXT: return
|
|
sil @simple_copyvalue_destroyvalue_pair : $@convention(thin) (S) -> S {
|
|
bb0(%0 : $S):
|
|
retain_value %0 : $S
|
|
release_value %0 : $S
|
|
retain_value %0 : $S
|
|
release_value %0 : $S
|
|
retain_value %0 : $S
|
|
release_value %0 : $S
|
|
return %0 : $S
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_retain_over_non_side_effect_instructions : $@convention(thin) (Builtin.NativeObject, Builtin.Int64) -> Builtin.Int1
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: builtin
|
|
// CHECK-NEXT: return
|
|
sil @delete_retain_over_non_side_effect_instructions : $@convention(thin) (Builtin.NativeObject, Builtin.Int64) -> (Builtin.Int1) {
|
|
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.Int64):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%3 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return %3 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_copyvalue_over_non_side_effect_instructions : $@convention(thin) (S, Builtin.Int64) -> Builtin.Int1
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: builtin
|
|
// CHECK-NEXT: return
|
|
sil @delete_copyvalue_over_non_side_effect_instructions : $@convention(thin) (S, Builtin.Int64) -> (Builtin.Int1) {
|
|
bb0(%0 : $S, %1 : $Builtin.Int64):
|
|
retain_value %0 : $S
|
|
%3 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1
|
|
release_value %0 : $S
|
|
return %3 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_retain_over_single_potential_decrement : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject) -> ()
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @delete_retain_over_single_potential_decrement : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject, %1 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
strong_release %1 : $Builtin.NativeObject
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_copyvalue_over_single_potential_decrement : $@convention(thin) (S, Builtin.NativeObject) -> ()
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @delete_copyvalue_over_single_potential_decrement : $@convention(thin) (S, Builtin.NativeObject) -> () {
|
|
bb0(%0 : $S, %1 : $Builtin.NativeObject):
|
|
retain_value %0 : $S
|
|
strong_release %1 : $Builtin.NativeObject
|
|
release_value %0 : $S
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_delete_retain_over_decrement_use : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
// CHECK: bb0
|
|
// CHECK: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @dont_delete_retain_over_decrement_use : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_delete_copyvalue_over_decrement_use : $@convention(thin) (S) -> ()
|
|
// CHECK: bb0
|
|
// CHECK: retain_value
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: release_value
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @dont_delete_copyvalue_over_decrement_use : $@convention(thin) (S) -> () {
|
|
bb0(%0 : $S):
|
|
%1 = function_ref @S_user : $@convention(thin) (S) -> ()
|
|
retain_value %0 : $S
|
|
apply %1 (%0) : $@convention(thin) (S) -> ()
|
|
apply %1 (%0) : $@convention(thin) (S) -> ()
|
|
release_value %0 : $S
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @move_delete_retain_over_decrement_use_when_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
// CHECK: bb0
|
|
// CHECK: strong_retain
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @move_delete_retain_over_decrement_use_when_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%2 = integer_literal $Builtin.Int32, 1
|
|
%3 = integer_literal $Builtin.Int32, 2
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_copyvalue_over_decrement_use_when_knownsafe : $@convention(thin) (S) -> ()
|
|
// CHECK: bb0
|
|
// CHECK: retain_value
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: release_value
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @delete_copyvalue_over_decrement_use_when_knownsafe : $@convention(thin) (S) -> () {
|
|
bb0(%0 : $S):
|
|
%1 = function_ref @S_user : $@convention(thin) (S) -> ()
|
|
retain_value %0 : $S
|
|
%2 = integer_literal $Builtin.Int32, 1
|
|
%3 = integer_literal $Builtin.Int32, 2
|
|
retain_value %0 : $S
|
|
apply %1 (%0) : $@convention(thin) (S) -> ()
|
|
apply %1 (%0) : $@convention(thin) (S) -> ()
|
|
release_value %0 : $S
|
|
release_value %0 : $S
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @literals_do_not_use_values_with_reference_semantics : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: string_literal
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @literals_do_not_use_values_with_reference_semantics : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
%4 = integer_literal $Builtin.Int64, 0
|
|
%5 = string_literal utf8 "123"
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%6 = tuple()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @owned_arguments_are_known_safe_in_the_first_bb
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @owned_arguments_are_known_safe_in_the_first_bb : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
br bb1
|
|
|
|
bb1:
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// FIXME: Should be able to eliminate the r/r pair here.
|
|
|
|
// CHECK-LABEL: @simple_alias_store_use_test : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
// SHOULD-NOT: strong_retain
|
|
// SHOULD-NOT: strong_release
|
|
sil @simple_alias_store_use_test : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
|
|
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
%3 = integer_literal $Builtin.Int32, 2
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %2 (%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
store %3 to %1 : $*Builtin.Int32
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%4 = tuple()
|
|
return %4: $()
|
|
}
|
|
|
|
// We can't remove the retain-release pair because the apply may be
|
|
// decrementing the refcount on our object.
|
|
// CHECK-LABEL: @simple_alias_load_use_test : $@convention(thin) (@inout Builtin.Int32) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_box
|
|
// CHECK-NEXT: project_box
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @simple_alias_load_use_test : $@convention(thin) (@inout Builtin.Int32) -> () {
|
|
bb0(%0 : $*Builtin.Int32):
|
|
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
|
|
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %2 (%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
%3 = load %1a : $*Builtin.Int32
|
|
strong_release %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%4 = tuple()
|
|
return %4: $()
|
|
}
|
|
|
|
// We *CAN* remove the pair if we have an iterated strong_release though.
|
|
//
|
|
// CHECK-LABEL: @simple_alias_load_use_test_two_release : $@convention(thin) (@inout Builtin.Int32) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: alloc_box
|
|
// CHECK-NEXT: project_box
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: load
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @simple_alias_load_use_test_two_release : $@convention(thin) (@inout Builtin.Int32) -> () {
|
|
bb0(%0 : $*Builtin.Int32):
|
|
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
|
|
%2 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %2 (%1) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
%3 = load %1a : $*Builtin.Int32
|
|
strong_release %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_release %1 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%4 = tuple()
|
|
return %4: $()
|
|
}
|
|
|
|
struct Int {
|
|
var value : Builtin.Int64
|
|
}
|
|
|
|
sil @guaranteed_call : $@convention(thin) (@guaranteed <τ_0_0> { var τ_0_0 } <Builtin.Int64>) -> () {
|
|
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 Error {
|
|
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) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%1 = function_ref @no_release_func : $@convention(thin) (Cls) -> ()
|
|
strong_retain %0 : $Cls
|
|
apply %1 (%0) : $@convention(thin) (Cls) -> ()
|
|
apply %1 (%0) : $@convention(thin) (Cls) -> ()
|
|
strong_release %0 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_remove_as_arg0_may_be_indirectly_released_by_callee
|
|
// CHECK: retain_value
|
|
// CHECK: release_value
|
|
sil @dont_remove_as_arg0_may_be_indirectly_released_by_callee : $@convention(thin) (Cls, Cls) -> () {
|
|
bb0(%0 : $Cls, %1 : $Cls):
|
|
%2 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> ()
|
|
retain_value %0 : $Cls
|
|
apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> ()
|
|
release_value %0 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @remove_as_local_object_does_not_escape_to_callee
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @remove_as_local_object_does_not_escape_to_callee : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%1 = alloc_ref $Cls
|
|
retain_value %1 : $Cls
|
|
%f1 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> ()
|
|
release_value %1 : $Cls
|
|
%f2 = function_ref @no_release_func : $@convention(thin) (Cls) -> ()
|
|
apply %f2 (%1) : $@convention(thin) (Cls) -> ()
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// 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) -> () {
|
|
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) -> () {
|
|
bb0(%0 : $Container):
|
|
strong_release %0 : $Container
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @no_release_func : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
////////////////////
|
|
// Multi-BB tests //
|
|
////////////////////
|
|
|
|
//////////////
|
|
// Hammocks //
|
|
//////////////
|
|
|
|
// CHECK-LABEL: sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This hammock cannot be optimized.
|
|
// CHECK-LABEL: sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
/// This hammock can't be optimized.
|
|
// CHECK-LABEL: sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This should not be optimizable.
|
|
// CHECK-LABEL: sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_release
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
////////////////////
|
|
// Double Hammock //
|
|
////////////////////
|
|
|
|
// Make sure we do not do anything in the presence of double partial
|
|
// applies. This is due to issues related to the two branches of the two
|
|
// diamonds not being control dependent.
|
|
// CHECK-LABEL: sil @double_hammock1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: function_ref user
|
|
// CHECK-NEXT: function_ref @user
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: bb2
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb4:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @double_hammock1 : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
cond_br undef, bb3, bb4
|
|
|
|
bb3:
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
br bb4
|
|
|
|
bb4:
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
//////////////
|
|
// Diamonds //
|
|
//////////////
|
|
|
|
// CHECK-LABEL: sil @diamond1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @diamond1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @diamond4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
/// CHECK-LABEL: sil @diamond9 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond9 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond10 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @diamond10 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
/// CHECK-LABEL: sil @diamond11 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond11 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @diamond12 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: br bb
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple ()
|
|
// CHECK-NEXT: return
|
|
sil @diamond12 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK: sil @unreachable_bb : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @unreachable_bb : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
|
|
bb2:
|
|
%3 = builtin "int_trap"() : $()
|
|
unreachable
|
|
}
|
|
|
|
// CHECK: sil @dont_move_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
sil @dont_move_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @do_remove_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
// CHECK: strong_retain
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NOT: strong_release
|
|
sil @do_remove_values_in_face_of_partial_merges : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @release_use_optimization : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: strong_release
|
|
// CHECK-NOT: strong_release
|
|
sil @release_use_optimization : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @increment_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
sil @increment_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
br bb3
|
|
|
|
bb3:
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
// CHECK: bb0(
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: strong_release
|
|
sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> () {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%1 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_retain %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
apply %1(%0) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
br bb3
|
|
|
|
bb3:
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// Just make sure we don't crash on this.
|
|
// CHECK-LABEL: sil @unreachable_pred : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
sil @unreachable_pred : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb1:
|
|
br bb2
|
|
|
|
bb2:
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @arg_merge : $@convention(thin) (@owned S) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @arg_merge : $@convention(thin) (@owned S) -> () {
|
|
bb0(%0 : $S):
|
|
%1 = struct_extract %0 : $S, #S.x
|
|
strong_retain %1 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %1 : $Builtin.NativeObject
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
|
|
/// Make sure we strip off casts when inserting new retains, releases. Otherwise
|
|
/// we run into dominance problems if the bitcast is in a branch.
|
|
// CHECK-LABEL: sil @switch_merge_with_bit_cast_in_branches : $@convention(thin) (@owned S) -> () {
|
|
// CHECK: bb1:
|
|
// CHECK: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK: strong_retain
|
|
// CHECK: bb3:
|
|
// CHECK: strong_release
|
|
sil @switch_merge_with_bit_cast_in_branches : $@convention(thin) (@owned S) -> () {
|
|
bb0(%0 : $S):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%1 = struct_extract %0 : $S, #S.x
|
|
%2 = unchecked_ref_cast %1 : $Builtin.NativeObject to $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_retain %2 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
br bb3
|
|
|
|
bb2:
|
|
%3 = struct_extract %0 : $S, #S.x
|
|
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
strong_retain %4 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
br bb3
|
|
|
|
bb3:
|
|
%5 = struct_extract %0 : $S, #S.x
|
|
%6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%7 = function_ref @user : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %7(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
apply %7(%6) : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> ()
|
|
strong_release %6 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>
|
|
%11 = tuple()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @strip_off_layout_compatible_typed_geps : $@convention(thin) (S, FakeOptional<Builtin.NativeObject>) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: release_value
|
|
sil @strip_off_layout_compatible_typed_geps : $@convention(thin) (S, FakeOptional<Builtin.NativeObject>) -> () {
|
|
bb0(%0 : $S, %1 : $FakeOptional<Builtin.NativeObject>):
|
|
%2 = struct_extract %0 : $S, #S.x
|
|
strong_retain %2 : $Builtin.NativeObject
|
|
release_value %0 : $S
|
|
%3 = unchecked_enum_data %1 : $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt
|
|
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 Error {
|
|
// CHECK: bb0
|
|
// CHECK: strong_retain
|
|
// CHECK: bb1
|
|
// CHECK: strong_release
|
|
// CHECK: bb2
|
|
// CHECK: strong_release
|
|
sil [serialized] @try_apply_test_1 : $@convention(thin) (Builtin.NativeObject) -> @error Error {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%1 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error Error
|
|
try_apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error Error, normal bb1, error bb2
|
|
|
|
bb1(%2 : $()):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return undef : $()
|
|
|
|
bb2(%3 : $Error):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
throw %3 : $Error
|
|
}
|
|
|
|
// CHECK-LABEL: sil [serialized] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error Error {
|
|
// CHECK: bb0(
|
|
// CHECK: strong_retain
|
|
// CHECK: try_apply
|
|
// CHECK: bb1(
|
|
// CHECK: strong_release
|
|
// CHECK: bb2(
|
|
// CHECK: strong_release
|
|
sil [serialized] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error Error {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%1 = function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
%2 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error Error
|
|
try_apply %2(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error Error, normal bb1, error bb2
|
|
|
|
bb1(%3 : $()):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return undef : $()
|
|
|
|
bb2(%4 : $Error):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
throw %4 : $Error
|
|
}
|
|
|
|
// 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 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 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 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 elimiante the inner retain/release pair on the
|
|
// partial_apply by treating it as an entrance.
|
|
// CHECK-LABEL: sil @test_strong_entrance_partial_apply : $@convention(thin) () -> () {
|
|
// CHECK: partial_apply
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: apply
|
|
// CHECK: strong_release
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: } // end sil function 'test_strong_entrance_partial_apply'
|
|
sil @test_strong_entrance_partial_apply : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = function_ref @mayRelease : $@convention(thin) () -> ()
|
|
%1 = partial_apply [callee_guaranteed] %0() : $@convention(thin) () -> ()
|
|
strong_retain %1 : $@callee_guaranteed () -> ()
|
|
apply %1() : $@callee_guaranteed () -> ()
|
|
strong_release %1 : $@callee_guaranteed () -> ()
|
|
strong_release %1 : $@callee_guaranteed () -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// 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 : $()
|
|
}
|