mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Iterative data flow retain sinking and release hoisting. This allows us to sink retains and hoist releases across harmless loops. which is an improvement on the SILCodeMotion retain sinking and release hoisting. It also separates the duty of moving retain and release with the duty of eliminating them in ASO. This should eventually replace RR code motion in SILcodemotion and insertion point in ARCsequence opts (ASO). This is the performance difference i get with retain sinking and release hoisting. After disabling retain release code motion in ASO and SILCodeMotion. we can start to take those code out once this lands. I see that we go from 24.5% of time spent in SILOptimizations w.r.t. the whole stdlib compilation to 25.1%. Improvement is better (i.e. retain sinking and hoisting releases result in performance gain). <details open> <summary>Regression (7)</summary> TEST | OLD_MIN | NEW_MIN | DELTA (%) | SPEEDUP --- | --- | --- | --- | --- SetIsSubsetOf | 441 | 510 | +15.7% | **0.86x** SetIntersect | 1041 | 1197 | +15.0% | **0.87x** BenchLangCallingCFunction | 184 | 211 | +14.7% | **0.87x** Sim2DArray | 326 | 372 | +14.1% | **0.88x** SetIsSubsetOf_OfObjects | 498 | 567 | +13.9% | **0.88x** GeekbenchGEMM | 945 | 1022 | +8.2% | **0.92x** COWTree | 3839 | 4181 | +8.9% | **0.92x(?)** </details> <details > <summary>Improvement (31)</summary> TEST | OLD_MIN | NEW_MIN | DELTA (%) | SPEEDUP --- | --- | --- | --- | --- ObjectiveCBridgeFromNSDictionaryAnyObjectToString | 174526 | 165392 | -5.2% | **1.06x** RGBHistogram | 3128 | 2957 | -5.5% | **1.06x** ObjectiveCBridgeToNSDictionary | 16510 | 15494 | -6.2% | **1.07x** LuhnAlgoLazy | 2294 | 2120 | -7.6% | **1.08x** DictionarySwapOfObjects | 6477 | 5994 | -7.5% | **1.08x** StringRemoveDupes | 1610 | 1485 | -7.8% | **1.08x** ObjectiveCBridgeFromNSSetAnyObjectToString | 159358 | 147824 | -7.2% | **1.08x** ObjectiveCBridgeToNSSet | 16191 | 14924 | -7.8% | **1.08x** DictionaryHashableClass | 1839 | 1704 | -7.3% | **1.08x** DictionaryLiteral | 2906 | 2678 | -7.8% | **1.09x(?)** StringUtilsUnderscoreCase | 10031 | 9187 | -8.4% | **1.09x** LuhnAlgoEager | 2320 | 2113 | -8.9% | **1.10x** ObjectiveCBridgeFromNSSetAnyObjectToStringForced | 99553 | 90348 | -9.2% | **1.10x** RIPEMD | 3327 | 3009 | -9.6% | **1.11x** Combos | 595 | 538 | -9.6% | **1.11x** Roman | 10 | 9 | -10.0% | **1.11x** StringUtilsCamelCase | 10783 | 9646 | -10.5% | **1.12x** SetIntersect_OfObjects | 2511 | 2182 | -13.1% | **1.15x** SwiftStructuresTrie | 28331 | 24339 | -14.1% | **1.16x** Dictionary2OfObjects | 3748 | 3115 | -16.9% | **1.20x** DictionaryOfObjects | 2473 | 2050 | -17.1% | **1.21x** Dictionary | 894 | 737 | -17.6% | **1.21x** Dictionary2 | 2268 | 1859 | -18.0% | **1.22x** StringIteration | 8027 | 6344 | -21.0% | **1.27x** Phonebook | 8207 | 6436 | -21.6% | **1.28x** BenchLangArray | 119 | 91 | -23.5% | **1.31x** LinkedList | 8267 | 6297 | -23.8% | **1.31x** StrToInt | 5585 | 4180 | -25.2% | **1.34x** Dictionary3OfObjects | 1122 | 831 | -25.9% | **1.35x** Dictionary3 | 731 | 515 | -29.6% | **1.42x** SuperChars | 513353 | 258735 | -49.6% | **1.98x**
2150 lines
67 KiB
Plaintext
2150 lines
67 KiB
Plaintext
// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=0 -arc-sequence-opts -disable-code-motion-arc=0 %s | FileCheck %s
|
|
// RUN: %target-sil-opt -enable-sil-verify-all -enable-loop-arc=1 -arc-sequence-opts -disable-code-motion-arc=0 %s | FileCheck %s
|
|
// RUN: %target-sil-opt -enable-sil-verify-all -arc-loop-opts -disable-code-motion-arc=0 %s | FileCheck %s
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
|
|
// Utilities
|
|
|
|
sil @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
|
|
sil @owned_user : $@convention(thin) (@owned @box Builtin.Int32) -> ()
|
|
|
|
struct Int {
|
|
var value : Builtin.Int64
|
|
}
|
|
|
|
struct S {
|
|
var x : Builtin.NativeObject
|
|
}
|
|
sil @S_user : $@convention(thin) (S) -> ()
|
|
|
|
struct S2 {
|
|
var x : Builtin.Int32
|
|
var y : Builtin.NativeObject
|
|
var z : Builtin.Int32
|
|
}
|
|
|
|
struct S3 {
|
|
var x : Builtin.Int32
|
|
var y : Builtin.NativeObject
|
|
var y1 : Builtin.NativeObject
|
|
var z : Builtin.Int32
|
|
}
|
|
|
|
class Cls {
|
|
var random : Builtin.Int32
|
|
|
|
init()
|
|
}
|
|
|
|
public enum FakeOptional<T> {
|
|
case none
|
|
case some(T)
|
|
}
|
|
|
|
class C {
|
|
init()
|
|
var w : FakeOptional<Builtin.NativeObject>
|
|
}
|
|
|
|
sil @cls_use : $@convention(thin) (@owned Cls) -> ()
|
|
|
|
class Container {
|
|
@sil_stored var c : Cls
|
|
init()
|
|
}
|
|
|
|
class RetainUser { }
|
|
|
|
sil @rawpointer_use: $@convention(thin) (Builtin.RawPointer) -> ()
|
|
|
|
enum Either<LTy, RTy> {
|
|
case Left(LTy)
|
|
case Right(RTy)
|
|
}
|
|
|
|
struct StaticString {
|
|
/// Either a pointer to the start of UTF-8 data, or an integer representation
|
|
/// of a single Unicode scalar.
|
|
var _startPtrOrData: Builtin.RawPointer
|
|
|
|
/// If `_startPtrOrData` is a pointer, contains the length of the UTF-8 data
|
|
/// in bytes.
|
|
var _byteSize: Builtin.Word
|
|
|
|
/// Extra flags:
|
|
///
|
|
/// - bit 0: set to 0 if `_startPtrOrData` is a pointer, or to 1 if it is a
|
|
/// Unicode scalar.
|
|
///
|
|
/// - bit 1: set to 1 if `_startPtrOrData` is a pointer and string data is
|
|
/// ASCII.
|
|
var _flags: Builtin.Int8
|
|
}
|
|
|
|
public protocol ErrorProtocol {
|
|
var _domain: Builtin.Int32 { get }
|
|
var _code: Builtin.Int32 { get }
|
|
}
|
|
|
|
sil [fragile] @use : $@convention(thin) (Builtin.NativeObject) -> ()
|
|
sil [fragile] @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
|
|
sil [fragile] @owned_return : $@convention(thin) () -> (@owned @box Builtin.Int32)
|
|
|
|
sil [fragile] @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error ErrorProtocol
|
|
|
|
/////////////////
|
|
// 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) (@box 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) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> ()
|
|
// CHECK: bb0
|
|
// CHECK: integer_literal
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: strong_retain
|
|
// 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) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%2 = integer_literal $Builtin.Int32, 1
|
|
%3 = integer_literal $Builtin.Int32, 2
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @delete_copyvalue_over_decrement_use_when_knownsafe : $@convention(thin) (S) -> ()
|
|
// CHECK: bb0
|
|
// CHECK: integer_literal
|
|
// CHECK-NEXT: integer_literal
|
|
// CHECK-NEXT: retain_value
|
|
// 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) (@box 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) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%4 = integer_literal $Builtin.Int64, 0
|
|
%5 = string_literal utf8 "123"
|
|
strong_release %0 : $@box 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 @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_release %0 : $@box Builtin.Int32
|
|
br bb1
|
|
|
|
bb1:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> () {
|
|
// SHOULD-NOT: strong_retain
|
|
// SHOULD-NOT: strong_release
|
|
sil @simple_alias_store_use_test : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = project_box %0 : $@box Builtin.Int32
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%3 = integer_literal $Builtin.Int32, 2
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %2 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
store %3 to %1 : $*Builtin.Int32
|
|
strong_release %0 : $@box 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 $Builtin.Int32
|
|
%1a = project_box %1 : $@box Builtin.Int32
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %1 : $@box Builtin.Int32
|
|
apply %2 (%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%3 = load %1a : $*Builtin.Int32
|
|
strong_release %1 : $@box 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 $Builtin.Int32
|
|
%1a = project_box %1 : $@box Builtin.Int32
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %1 : $@box Builtin.Int32
|
|
strong_retain %1 : $@box Builtin.Int32
|
|
apply %2 (%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%3 = load %1a : $*Builtin.Int32
|
|
strong_release %1 : $@box Builtin.Int32
|
|
strong_release %1 : $@box Builtin.Int32
|
|
%4 = tuple()
|
|
return %4: $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @silargument_retain_iterated : $@convention(thin) (@owned @box 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 @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1 (%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> ()
|
|
%3 = unchecked_ref_cast %0 : $Cls to $@box Builtin.Int32
|
|
strong_retain %1 : $Cls
|
|
apply %2(%3) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %2(%3) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %1 : $Cls
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @escaping_pointer_can_have_refcount_decremented_indirectly : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
|
|
sil @the_kraken : $@convention(thin) () -> ()
|
|
sil @escaping_pointer_can_have_refcount_decremented_indirectly : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @the_kraken : $@convention(thin) () -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1() : $@convention(thin) () -> ()
|
|
apply %1() : $@convention(thin) () -> ()
|
|
strong_release %0 : $@box 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 $Builtin.Int32
|
|
strong_retain %3 : $@box Builtin.Int32
|
|
apply %1() : $@convention(thin) () -> Builtin.RawPointer
|
|
strong_release %3 : $@box Builtin.Int32
|
|
strong_retain %3 : $@box Builtin.Int32
|
|
apply %2(%0) : $@convention(thin) (Builtin.RawPointer) -> ()
|
|
strong_release %3 : $@box Builtin.Int32
|
|
strong_release %3 : $@box 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 $Builtin.Int32
|
|
%2 = alloc_stack $@box Builtin.Int32
|
|
store %1 to %2 : $*@box Builtin.Int32
|
|
%4 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %1 : $@box Builtin.Int32
|
|
%6 = load %2 : $*@box Builtin.Int32
|
|
%7 = apply %4(%6) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %6 : $@box Builtin.Int32
|
|
strong_release %1 : $@box Builtin.Int32
|
|
dealloc_stack %2 : $*@box Builtin.Int32
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @retain_can_be_used_by_other_pointer : $@convention(thin) (RetainUser, @box Builtin.Int32) -> @box Builtin.Int32 {
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
sil @retain_can_be_used_by_other_pointer : $@convention(thin) (RetainUser, @box Builtin.Int32) -> @box Builtin.Int32 {
|
|
bb0(%0 : $RetainUser, %1 : $@box Builtin.Int32):
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $RetainUser
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %1 : $@box Builtin.Int32
|
|
strong_release %0 : $RetainUser
|
|
return %1 : $@box 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: strong_retain
|
|
// CHECK: strong_release
|
|
sil @dont_remove_as_arg0_may_be_indirectly_released_by_callee : $@convention(thin) (Cls, Cls) -> () {
|
|
bb0(%0 : $Cls, %1 : $Cls):
|
|
%2 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> ()
|
|
retain_value %0 : $Cls
|
|
apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %2 (%0, %1) : $@convention(thin) (Cls, Cls) -> ()
|
|
release_value %0 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @remove_as_local_object_does_not_escape_to_callee
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @remove_as_local_object_does_not_escape_to_callee : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%1 = alloc_ref $Cls
|
|
retain_value %1 : $Cls
|
|
%f1 = function_ref @release_arg1 : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> ()
|
|
apply %f1 (%0, %0) : $@convention(thin) (Cls, Cls) -> ()
|
|
release_value %1 : $Cls
|
|
%f2 = function_ref @no_release_func : $@convention(thin) (Cls) -> ()
|
|
apply %f2 (%1) : $@convention(thin) (Cls) -> ()
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dont_remove_as_local_object_indirectly_escapes_to_callee
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
sil @dont_remove_as_local_object_indirectly_escapes_to_callee : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%1 = alloc_ref $Cls
|
|
%2 = alloc_ref $Container
|
|
%3 = ref_element_addr %2 : $Container, #Container.c
|
|
store %1 to %3 : $*Cls
|
|
retain_value %1 : $Cls
|
|
%f1 = function_ref @release_container : $@convention(thin) (Container) -> ()
|
|
apply %f1 (%2) : $@convention(thin) (Container) -> ()
|
|
apply %f1 (%2) : $@convention(thin) (Container) -> ()
|
|
release_value %1 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @release_arg1 : $@convention(thin) (Cls, Cls) -> () {
|
|
bb0(%0 : $Cls, %1 : $Cls):
|
|
strong_release %1 : $Cls
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @release_container : $@convention(thin) (Container) -> () {
|
|
bb0(%0 : $Container):
|
|
strong_release %0 : $Container
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @no_release_func : $@convention(thin) (Cls) -> () {
|
|
bb0(%0 : $Cls):
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
////////////////////
|
|
// Multi-BB tests //
|
|
////////////////////
|
|
|
|
//////////////
|
|
// Hammocks //
|
|
//////////////
|
|
|
|
// CHECK-LABEL: sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock1 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This hammock cannot be optimized.
|
|
// CHECK-LABEL: sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
/// This hammock can't be optimized.
|
|
// CHECK-LABEL: sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// This should not be optimizable.
|
|
// CHECK-LABEL: sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock4 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_release
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock5 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_release
|
|
sil @hammock6 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
br bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock7 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK: bb0
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @hammock8 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
br bb2
|
|
|
|
bb2:
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
////////////////////
|
|
// Double Hammock //
|
|
////////////////////
|
|
|
|
// Make sure we do not do anything in the presence of double partial
|
|
// applies. This is due to issues related to the two branches of the two
|
|
// diamonds not being control dependent.
|
|
// CHECK-LABEL: sil @double_hammock1 : $@convention(thin) (@box 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) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
br bb2
|
|
|
|
bb2:
|
|
cond_br undef, bb3, bb4
|
|
|
|
bb3:
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
br bb4
|
|
|
|
bb4:
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> () {
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
sil @dont_move_values_in_face_of_partial_merges : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @do_remove_values_in_face_of_partial_merges : $@convention(thin) (@box 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) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @release_use_optimization : $@convention(thin) (@owned @box Builtin.Int32) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: strong_release
|
|
// CHECK-NOT: strong_release
|
|
sil @release_use_optimization : $@convention(thin) (@owned @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @increment_known_safe_merge_with_last_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb2:
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK-NEXT: strong_retain
|
|
// 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) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
br bb3
|
|
|
|
bb3:
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
// CHECK: bb0(
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: function_ref
|
|
// CHECK-NEXT: strong_retain
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: apply
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: cond_br
|
|
// CHECK: bb1:
|
|
// CHECK-NEXT: strong_release
|
|
// CHECK-NEXT: br bb3
|
|
// CHECK-NOT: strong_release
|
|
sil @decrement_known_safe_merge_with_last_knownsafe : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_release %0 : $@box Builtin.Int32
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_release %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box 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-NOT: strong_retain
|
|
// CHECK: bb2:
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK: bb3:
|
|
// CHECK: retain_value
|
|
// CHECK: release_value
|
|
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 $@box Builtin.Int32
|
|
strong_retain %2 : $@box Builtin.Int32
|
|
br bb3
|
|
|
|
bb2:
|
|
%3 = struct_extract %0 : $S, #S.x
|
|
%4 = unchecked_ref_cast %3 : $Builtin.NativeObject to $@box Builtin.Int32
|
|
strong_retain %4 : $@box Builtin.Int32
|
|
br bb3
|
|
|
|
bb3:
|
|
%5 = struct_extract %0 : $S, #S.x
|
|
%6 = unchecked_ref_cast %5 : $Builtin.NativeObject to $@box Builtin.Int32
|
|
%7 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %7(%6) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %7(%6) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %6 : $@box Builtin.Int32
|
|
%11 = tuple()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @strip_off_layout_compatible_typed_geps : $@convention(thin) (S, FakeOptional<Builtin.NativeObject>) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: release_value
|
|
sil @strip_off_layout_compatible_typed_geps : $@convention(thin) (S, FakeOptional<Builtin.NativeObject>) -> () {
|
|
bb0(%0 : $S, %1 : $FakeOptional<Builtin.NativeObject>):
|
|
%2 = struct_extract %0 : $S, #S.x
|
|
strong_retain %2 : $Builtin.NativeObject
|
|
release_value %0 : $S
|
|
%3 = unchecked_enum_data %1 : $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt.1
|
|
strong_retain %3 : $Builtin.NativeObject
|
|
release_value %1 : $FakeOptional<Builtin.NativeObject>
|
|
%5 = tuple()
|
|
return %5 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @strip_off_single_pred_args : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: strong_release
|
|
sil @strip_off_single_pred_args : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
|
|
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
|
|
switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
|
|
|
|
bb1(%1 : $Builtin.NativeObject):
|
|
retain_value %0 : $FakeOptional<Builtin.NativeObject>
|
|
strong_release %1 : $Builtin.NativeObject
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @unreachable_bb_2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @unreachable_bb_2 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
%4 = integer_literal $Builtin.Int1, -1
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
|
|
bb2:
|
|
cond_fail %4 : $Builtin.Int1
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil @unreachable_bb_3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @unreachable_bb_3 : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_release %0 : $Builtin.NativeObject
|
|
%1 = tuple()
|
|
return %1 : $()
|
|
|
|
bb2:
|
|
%4 = integer_literal $Builtin.Int1, -1
|
|
cond_fail %4 : $Builtin.Int1
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil @strip_off_multi_payload_unchecked_enum_data : $@convention(thin) (Either<C, S>) -> () {
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: release_value
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @strip_off_multi_payload_unchecked_enum_data : $@convention(thin) (Either<C, S>) -> () {
|
|
bb0(%0 : $Either<C, S>):
|
|
retain_value %0 : $Either<C, S>
|
|
%1 = unchecked_enum_data %0 : $Either<C, S>, #Either.Right!enumelt.1
|
|
release_value %1 : $S
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @strip_off_structs_only_non_trivial_field : $@convention(thin) (S2, S3) -> () {
|
|
// CHECK: bb0([[ARG0:%[0-9]+]] : $S2, [[ARG1:%[0-9]+]] : $S3):
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: release_value
|
|
// CHECK: retain_value [[ARG1]]
|
|
// CHECK-NEXT: [[EXT:%[0-9]+]] = struct_extract [[ARG1]]
|
|
// CHECK-NEXT: release_value [[EXT]]
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: release_value
|
|
sil @strip_off_structs_only_non_trivial_field : $@convention(thin) (S2, S3) -> () {
|
|
bb0(%0 : $S2, %1 : $S3):
|
|
retain_value %0 : $S2
|
|
%2 = struct_extract %0 : $S2, #S2.y
|
|
release_value %2 : $Builtin.NativeObject
|
|
retain_value %1 : $S3
|
|
%3 = struct_extract %1 : $S3, #S3.y
|
|
release_value %3 : $Builtin.NativeObject
|
|
%4 = tuple()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @strip_off_enum_from_payload : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
// CHECK-NOT: retain_value
|
|
// CHECK-NOT: release_value
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @strip_off_enum_from_payload : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
%1 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt.1, %0 : $Builtin.NativeObject
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
release_value %1 : $FakeOptional<Builtin.NativeObject>
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
// For now make sure we don't eliminate this.
|
|
// CHECK-LABEL: sil @guaranteed_is_always_known_safe : $@convention(thin) (@guaranteed @box Builtin.Int32) -> () {
|
|
// CHECK: retain
|
|
// CHECK: release
|
|
sil @guaranteed_is_always_known_safe : $@convention(thin) (@guaranteed @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%2 = tuple()
|
|
return %2 : $()
|
|
}
|
|
|
|
sil [_semantics "arc.programtermination_point"] @fatalError : $@convention(thin) @noreturn (StaticString, StaticString, StaticString) -> () // user: %43
|
|
|
|
// 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) @noreturn (StaticString, StaticString, StaticString) -> () // user: %43
|
|
%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) @noreturn (StaticString, StaticString, StaticString) -> ()
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil @propagate_postdominating_owned_release_info : $@convention(thin) (@owned @box Builtin.Int32) -> () {
|
|
// CHECK: bb0(
|
|
// CHECK-NOT: retain
|
|
// CHECK-NOT: release
|
|
// CHECK: bb1:
|
|
// CHECK-NOT: retain
|
|
// CHECK-NOT: release
|
|
// CHECK: bb2:
|
|
// CHECK: strong_release
|
|
sil @propagate_postdominating_owned_release_info : $@convention(thin) (@owned @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
br bb1
|
|
|
|
bb1:
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb2:
|
|
strong_release %0 : $@box 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: function_ref @guaranteed_use
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
// CHECK: apply
|
|
// CHECK: function_ref @guaranteed_use
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
// CHECK: function_ref @guaranteed_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> ()
|
|
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) (@box Builtin.Int32) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @branch_use1 : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> () {
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_retain
|
|
// CHECK: strong_release
|
|
sil @branch_use2 : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
br bb3
|
|
|
|
bb2:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @branch_use3 : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
br bb3(undef : $@box Builtin.Int32)
|
|
|
|
bb2:
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
br bb3(%0 : $@box Builtin.Int32)
|
|
|
|
bb3(%2 : $@box Builtin.Int32):
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @cond_branch_use1 : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%2 = integer_literal $Builtin.Int1, 0
|
|
cond_br %2, bb1, bb2
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @cond_branch_use2 : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%2 = integer_literal $Builtin.Int1, 0
|
|
cond_br %2, bb1(%0 : $@box Builtin.Int32), bb2
|
|
|
|
bb1(%3 : $@box Builtin.Int32):
|
|
br bb3
|
|
|
|
bb2:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @cond_branch_use3 : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @cond_branch_use3 : $@convention(thin) (@box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
%2 = integer_literal $Builtin.Int1, 0
|
|
cond_br %2, bb2(%0 : $@box Builtin.Int32), bb1
|
|
|
|
bb2(%3 : $@box Builtin.Int32):
|
|
br bb3
|
|
|
|
bb1:
|
|
br bb3
|
|
|
|
bb3:
|
|
strong_release %0 : $@box 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 @box Builtin.Int32)
|
|
%1 = apply %0() : $@convention(thin) () -> (@owned @box Builtin.Int32)
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %1 : $@box Builtin.Int32
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %1 : $@box Builtin.Int32
|
|
strong_release %1 : $@box Builtin.Int32
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @retains_that_are_not_removed_preserves_known_safety : $@convention(thin) (@owned @box Builtin.Int32, @box 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 @box Builtin.Int32, @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32, %1 : $@box Builtin.Int32):
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @retains_that_are_removed_do_not_preserve_known_safety : $@convention(thin) (@owned @box Builtin.Int32, @box 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 @box Builtin.Int32, @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32, %1 : $@box Builtin.Int32):
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %2(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box 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 $@box Builtin.Int32
|
|
strong_retain %0 : $Cls
|
|
%2 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %2(%1) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %1 : $@box Builtin.Int32
|
|
strong_release %1 : $@box 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 $@box Builtin.Int32
|
|
strong_retain %1 : $Cls
|
|
%3 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %3(%2) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %3(%2) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %2 : $@box Builtin.Int32
|
|
strong_release %2 : $@box Builtin.Int32
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @must_use_test : $@convention(thin) (@owned @box Builtin.Int32) -> () {
|
|
// CHECK-NOT: strong_retain
|
|
// CHECK-NOT: strong_release
|
|
sil @must_use_test : $@convention(thin) (@owned @box Builtin.Int32) -> () {
|
|
bb0(%0 : $@box Builtin.Int32):
|
|
%1 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
apply %1(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box 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 $Builtin.Int32
|
|
strong_retain %0 : $@box Builtin.Int32
|
|
%3 = function_ref @user : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %3(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
apply %3(%0) : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_release %0 : $@box Builtin.Int32
|
|
strong_release %0 : $@box 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) (@box Builtin.Int32) -> ()
|
|
%1 = partial_apply %0() : $@convention(thin) (@box Builtin.Int32) -> ()
|
|
strong_retain %1 : $@callee_owned (@box Builtin.Int32) -> ()
|
|
%2 = convert_function %1 : $@callee_owned (@box Builtin.Int32) -> () to $@callee_owned (@box Builtin.Int32) -> ()
|
|
strong_release %2 : $@callee_owned (@box Builtin.Int32) -> ()
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [fragile] @try_apply_test_1 : $@convention(thin) (Builtin.NativeObject) -> @error ErrorProtocol {
|
|
// CHECK: bb0
|
|
// CHECK: strong_retain
|
|
// CHECK: bb1
|
|
// CHECK: strong_release
|
|
// CHECK: bb2
|
|
// CHECK: strong_release
|
|
sil [fragile] @try_apply_test_1 : $@convention(thin) (Builtin.NativeObject) -> @error ErrorProtocol {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
strong_retain %0 : $Builtin.NativeObject
|
|
%1 = function_ref @guaranteed_throwing_use : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error ErrorProtocol
|
|
try_apply %1(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error ErrorProtocol, normal bb1, error bb2
|
|
|
|
bb1(%2 : $()):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return undef : $()
|
|
|
|
bb2(%3 : $ErrorProtocol):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
throw %3 : $ErrorProtocol
|
|
}
|
|
|
|
// CHECK-LABEL: sil [fragile] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error ErrorProtocol {
|
|
// CHECK: bb0(
|
|
// CHECK: strong_retain
|
|
// CHECK: try_apply
|
|
// CHECK: bb1(
|
|
// CHECK: strong_release
|
|
// CHECK: bb2(
|
|
// CHECK: strong_release
|
|
sil [fragile] @try_apply_test_2 : $@convention(thin) (Builtin.NativeObject) -> @error ErrorProtocol {
|
|
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 ErrorProtocol
|
|
try_apply %2(%0) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> @error ErrorProtocol, normal bb1, error bb2
|
|
|
|
bb1(%3 : $()):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
return undef : $()
|
|
|
|
bb2(%4 : $ErrorProtocol):
|
|
strong_release %0 : $Builtin.NativeObject
|
|
throw %4 : $ErrorProtocol
|
|
}
|
|
|
|
// 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 : $()
|
|
}
|