Files
swift-mirror/test/SILOptimizer/arcsequenceopts.sil
Xin Tong 51b1c0bc68 Implement retain, release code motion.
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**
2016-04-18 15:39:17 -07:00

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