Files
swift-mirror/test/SILOptimizer/arcsequenceopts.sil
Andrew Trick f6624e355a Add EscapeAnalysis::findObjectKind to mitigate deinit side effects
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.
2021-02-19 12:35:11 -08:00

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 : $()
}