Files
swift-mirror/test/SILOptimizer/latecodemotion.sil
Roman Levenstein 8ad61d5cd6 Use function signatures for SILDeclRefs in witness_tables, vtables and witness_method instructions.
Textual SIL was sometimes ambiguous when SILDeclRefs were used, because the textual representation of SILDeclRefs was the same for functions that have the same name, but different signatures.
2017-01-27 12:16:14 -08:00

1454 lines
39 KiB
Plaintext

// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -late-codemotion -release-hoisting -retain-sinking -disable-with-critical-edge=1 | %FileCheck %s
import Builtin
import Swift
class B { }
class E : B { }
struct A {
var i : Builtin.Int32
}
enum FakeOptional<T> {
case none
case some(T)
}
class C {}
class C2 {
var current: A
init()
}
enum Either {
case First(Builtin.NativeObject)
case Second(C)
}
enum ThreeCaseEnum {
case A
case B
case C
}
struct S {
var ptr : Builtin.NativeObject
}
enum ThreeCaseAbstractionDifference {
case A(Builtin.Int32)
case B(Builtin.NativeObject)
case C(S)
}
class X {}
sil @user : $@convention(thin) (Builtin.NativeObject) -> ()
sil @use_C2 : $@convention(thin) (C2) -> ()
sil @optional_user : $@convention(thin) (FakeOptional<Builtin.Int32>) -> ()
sil @blocker : $@convention(thin) () -> ()
sil @get_object : $@convention(thin) () -> Builtin.NativeObject
// CHECK-LABEL: sil @sink_from_preds
// CHECK: bb1:
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK: strong_retain
// CHECK: return
sil @sink_from_preds : $@convention(thin) (Builtin.Int1, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B):
cond_br %0, bb1, bb2
bb1:
%2 = strong_retain %1 : $B
br bb3
bb2:
%3 = strong_retain %1 : $B
br bb3
bb3:
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: sil @sink_from_preds_through_args
// CHECK: bb1:
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: br bb3
// CHECK: bb3([[A:%[0-9]+]] : $B):
// CHECK: strong_retain [[A]]
// CHECK: return
sil @sink_from_preds_through_args : $@convention(thin) (Builtin.Int1, B, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B, %2 : $B):
cond_br %0, bb1, bb2
bb1:
%r1 = strong_retain %1 : $B
br bb3(%1 : $B)
bb2:
%r2 = strong_retain %2 : $B
br bb3(%2 : $B)
bb3(%a1 : $B):
%t1 = tuple()
return %t1 : $()
}
// CHECK-LABEL: sil @sink_from_preds_not_through_args
// CHECK: bb1:
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: br bb3
// CHECK: bb3({{%[0-9]+}} : $B):
// CHECK: strong_retain %1
// CHECK: return
sil @sink_from_preds_not_through_args : $@convention(thin) (Builtin.Int1, B, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B, %2 : $B):
cond_br %0, bb1, bb2
bb1:
%r1 = strong_retain %1 : $B
br bb3(%1 : $B)
bb2:
%r2 = strong_retain %1 : $B
br bb3(%2 : $B)
bb3(%a1 : $B):
%t1 = tuple()
return %t1 : $()
}
// CHECK-LABEL: sil @sink_from_preds_through_args2
// CHECK: bb1:
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: br bb3
// CHECK: bb3({{%[0-9]+}} : $B, [[A:%[0-9]+]] : $B):
// CHECK: strong_retain [[A]]
// CHECK: return
sil @sink_from_preds_through_args2 : $@convention(thin) (Builtin.Int1, B, B, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B, %2 : $B, %3 : $B):
cond_br %0, bb1, bb2
bb1:
%r1 = strong_retain %1 : $B
br bb3(%3 : $B, %1 : $B)
bb2:
%r2 = strong_retain %2 : $B
br bb3(%3 : $B, %2 : $B)
bb3(%a1 : $B, %a2 : $B):
%t1 = tuple()
return %t1 : $()
}
// CHECK-LABEL: sil @do_not_sink_from_preds_through_args
// CHECK: bb1:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb3
// CHECK-NOT: strong_retain
// CHECK: return
sil @do_not_sink_from_preds_through_args : $@convention(thin) (Builtin.Int1, B, B, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B, %2 : $B, %3 : $B):
cond_br %0, bb1, bb2
bb1:
%r1 = strong_retain %1 : $B
br bb3(%1 : $B)
bb2:
%r2 = strong_retain %2 : $B
br bb3(%3 : $B)
bb3(%a1 : $B):
%t1 = tuple()
return %t1 : $()
}
// CHECK-LABEL: sil @do_not_sink_from_preds_through_args2
// CHECK: bb1:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb3
// CHECK-NOT: strong_retain
// CHECK: return
sil @do_not_sink_from_preds_through_args2 : $@convention(thin) (Builtin.Int1, B, B, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B, %2 : $B, %3 : $B):
cond_br %0, bb1, bb2
bb1:
%r1 = strong_retain %1 : $B
br bb3(%1 : $B, %3 : $B)
bb2:
%r2 = strong_retain %2 : $B
br bb3(%3 : $B, %2 : $B)
bb3(%a1 : $B, %a2 : $B):
%t1 = tuple()
return %t1 : $()
}
// CHECK-LABEL: sil @do_not_sink_from_preds_through_args3
// CHECK: bb2:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb5
// CHECK: bb3:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb5
// CHECK: bb4:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb5
// CHECK-NOT: strong_retain
// CHECK: return
sil @do_not_sink_from_preds_through_args3 : $@convention(thin) (Builtin.Int1, B, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B, %2 : $B):
cond_br %0, bb1, bb2
bb1:
cond_br %0, bb3, bb4
bb2:
%r1 = strong_retain %1 : $B
br bb5(%1 : $B)
bb3:
%r2 = strong_retain %2 : $B
br bb5(%2 : $B)
bb4:
%r3 = strong_retain %1 : $B
br bb5(%2 : $B)
bb5(%a1 : $B):
%t1 = tuple()
return %t1 : $()
}
// CHECK-LABEL: sil @do_not_sink_from_preds_through_args4
// CHECK: bb2:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb5
// CHECK: bb3:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb5
// CHECK: bb4:
// CHECK-NEXT: strong_retain
// CHECK-NEXT: br bb5
// CHECK-NOT: strong_retain
// CHECK: return
sil @do_not_sink_from_preds_through_args4 : $@convention(thin) (Builtin.Int1, B, B) -> () {
bb0(%0 : $Builtin.Int1, %1 : $B, %2 : $B):
cond_br %0, bb1, bb2
bb1:
cond_br %0, bb3, bb4
bb2:
%r1 = strong_retain %1 : $B
br bb5(%2 : $B)
bb3:
%r2 = strong_retain %2 : $B
br bb5(%2 : $B)
bb4:
%r3 = strong_retain %1 : $B
br bb5(%1 : $B)
bb5(%a1 : $B):
%t1 = tuple()
return %t1 : $()
}
// CHECK-LABEL: sil @do_not_sink_local_uses
// CHECK: integer_literal
// CHECK: integer_literal
// CHECK: return
sil @do_not_sink_local_uses : $@convention(thin) (Builtin.Int1) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int1):
cond_br %0, bb1, bb3
bb1:
%1 = integer_literal $Builtin.Int32, 7
br bb2(%1 : $Builtin.Int32)
bb3:
%2 = integer_literal $Builtin.Int32, 8
br bb2(%2 : $Builtin.Int32)
bb2(%3 : $Builtin.Int32):
return %3 : $Builtin.Int32
}
// CHECK-LABEL: sil @deep_sink1
// CHECK: integer_literal
// CHECK: br bb3
// CHECK: integer_literal
// CHECK: br bb3
// CHECK: bb3
// CHECK: strong_retain
// CHECK-NEXT: return
sil @deep_sink1 : $@convention(thin) (Builtin.Int1, B) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int1, %1 : $B):
cond_br %0, bb1, bb2
bb1:
%2 = strong_retain %1 : $B
%3 = integer_literal $Builtin.Int32, 9
br bb3(%3 : $Builtin.Int32)
bb2:
%4 = strong_retain %1 : $B
%5 = integer_literal $Builtin.Int32, 7
br bb3(%5 : $Builtin.Int32)
bb3(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
// CHECK-LABEL: sil @deep_sink2
// CHECK-NOT: integer_literal
// CHECK: br bb3
// CHECK-NOT: integer_literal
// CHECK: br bb3
// CHECK: bb3
// CHECK: integer_literal
// CHECK: strong_retain
// CHECK-NEXT: return
sil @deep_sink2 : $@convention(thin) (Builtin.Int1, B) -> Builtin.Int32 {
bb0(%0 : $Builtin.Int1, %1 : $B):
cond_br %0, bb1, bb2
bb1:
%2 = strong_retain %1 : $B
%3 = integer_literal $Builtin.Int32, 7
br bb3(%3 : $Builtin.Int32)
bb2:
%4 = strong_retain %1 : $B
%5 = integer_literal $Builtin.Int32, 7
br bb3(%5 : $Builtin.Int32)
bb3(%6 : $Builtin.Int32):
return %6 : $Builtin.Int32
}
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_switch_enum_1 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb0({{.*}}):
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: retain_value
// CHECK-NEXT: apply
// CHECK-NEXT: alloc_stack
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: switch_enum
// CHECK: bb1({{.*}}):
// CHECK: strong_retain
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK-NOT: strong_retain
// CHECK: bb3:
// CHECK-NOT: retain_value
// CHECK-NOT: strong_retain
sil @sink_ref_count_ops_enum_over_switch_enum_1 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
%1 = function_ref @blocker : $@convention(thin) () -> ()
retain_value %0 : $FakeOptional<Builtin.NativeObject>
apply %1() : $@convention(thin) () -> ()
%3 = alloc_stack $Builtin.Int32
retain_value %0 : $FakeOptional<Builtin.NativeObject>
dealloc_stack %3 : $*Builtin.Int32
switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
bb1(%2 : $Builtin.NativeObject):
apply %1() : $@convention(thin) () -> ()
br bb3
bb2:
br bb3
bb3:
%4 = tuple()
return %4 : $()
}
// This test makes sure that if any of the switches targets have a predecessor
// besides the switch enum, we don't do anything.
//
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_switch_enum_2 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb0({{.*}}):
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK-NEXT: retain_value
// CHECK-NEXT: switch_enum
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb3:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb4:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
sil @sink_ref_count_ops_enum_over_switch_enum_2 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
%1 = function_ref @blocker : $@convention(thin) () -> ()
cond_br undef, bb1, bb2
bb1:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb2, case #FakeOptional.none!enumelt: bb3
bb2:
br bb4
bb3:
br bb4
bb4:
%2 = tuple()
return %2 : $()
}
// This test makes sure that if any of the switches targets have a predecessor
// besides the switch enum, we don't do anything.
//
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_switch_enum_3 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
// CHECK: bb0({{.*}}):
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK-NEXT: retain_value
// CHECK-NEXT: switch_enum
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb3:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb4:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
sil @sink_ref_count_ops_enum_over_switch_enum_3 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
bb0(%0 : $FakeOptional<Builtin.Int32>):
%1 = function_ref @blocker : $@convention(thin) () -> ()
cond_br undef, bb1, bb3
bb1:
retain_value %0 : $FakeOptional<Builtin.Int32>
switch_enum %0 : $FakeOptional<Builtin.Int32>, case #FakeOptional.some!enumelt.1: bb2, case #FakeOptional.none!enumelt: bb3
bb2:
br bb4
bb3:
br bb4
bb4:
%2 = tuple()
return %2 : $()
}
// This test makes sure that we do move ref counts over instructions that cannot reference it.
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_switch_enum_4 :
// CHECK: bb0({{%[0-9]+}} : $FakeOptional<Builtin.Int32>, [[ARG1:%[0-9]+]] : $FakeOptional<Builtin.NativeObject>):
// CHECK-NOT: retain_value [[ARG1]]
// CHECK: switch_enum
// CHECK: bb1:
// CHECK: retain_value
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value [[ARG1]]
// CHECK-NOT: strong_retain
// CHECK: bb3:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value [[ARG1]]
// CHECK-NOT: strong_retain
sil @sink_ref_count_ops_enum_over_switch_enum_4 : $@convention(thin) (FakeOptional<Builtin.Int32>, FakeOptional<Builtin.NativeObject>) -> FakeOptional<Builtin.NativeObject> {
bb0(%0 : $FakeOptional<Builtin.Int32>, %1 : $FakeOptional<Builtin.NativeObject>):
%2 = function_ref @blocker : $@convention(thin) () -> ()
retain_value %1 : $FakeOptional<Builtin.NativeObject>
%3 = alloc_stack $FakeOptional<Builtin.Int32>
retain_value %0 : $FakeOptional<Builtin.Int32>
switch_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
apply %2() : $@convention(thin) () -> ()
br bb3
bb2:
br bb3
bb3:
dealloc_stack %3 : $*FakeOptional<Builtin.Int32>
return %1 : $FakeOptional<Builtin.NativeObject>
}
/// This version does not work since we have a release before the terminator
/// even though we have the select_enum before it.
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_switch_enum_5 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
// CHECK: bb0({{.*}}):
// CHECK: bb1:
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: alloc_stack
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: retain_value
// CHECK-NEXT: release_value
// CHECK-NEXT: switch_enum
// CHECK: bb2:
// CHECK-NOT: retain_value
// CHECK: bb3:
// CHECK-NOT: retain_value
// CHECK: bb4:
// CHECK-NOT: retain_value
sil @sink_ref_count_ops_enum_over_switch_enum_5 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
bb0(%0 : $FakeOptional<Builtin.Int32>):
br bb10
bb10:
%1 = function_ref @blocker : $@convention(thin) () -> ()
retain_value %0 : $FakeOptional<Builtin.Int32>
%3 = alloc_stack $Builtin.Int32
dealloc_stack %3 : $*Builtin.Int32
release_value %0 : $FakeOptional<Builtin.Int32>
switch_enum %0 : $FakeOptional<Builtin.Int32>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_select_enum_1 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb0({{.*}}):
// CHECK-NEXT: integer_literal
// CHECK-NEXT: integer_literal
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: retain_value
// CHECK-NEXT: apply
// CHECK-NEXT: alloc_stack
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: select_enum
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK: strong_retain
// CHECK-NOT: retain_value
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK-NOT: strong_retain
// CHECK: bb3:
// CHECK-NOT: retain_value
// CHECK-NOT: strong_retain
sil @sink_ref_count_ops_enum_over_select_enum_1 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
%1 = function_ref @blocker : $@convention(thin) () -> ()
retain_value %0 : $FakeOptional<Builtin.NativeObject>
apply %1() : $@convention(thin) () -> ()
%3 = alloc_stack $Builtin.Int32
retain_value %0 : $FakeOptional<Builtin.NativeObject>
dealloc_stack %3 : $*Builtin.Int32
%100 = select_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: %t, case #FakeOptional.none!enumelt: %f : $Builtin.Int1
cond_br %100, bb1, bb2
bb1:
apply %1() : $@convention(thin) () -> ()
br bb3
bb2:
br bb3
bb3:
%4 = tuple()
return %4 : $()
}
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_select_enum_2 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
// CHECK: bb0({{.*}}):
// CHECK-NEXT: integer_literal
// CHECK-NEXT: integer_literal
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK-NEXT: retain_value
// CHECK-NEXT: select_enum
// CHECK-NEXT: cond_br
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb3:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb4:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
sil @sink_ref_count_ops_enum_over_select_enum_2 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
bb0(%0 : $FakeOptional<Builtin.Int32>):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
%1 = function_ref @blocker : $@convention(thin) () -> ()
cond_br undef, bb1, bb2
bb1:
retain_value %0 : $FakeOptional<Builtin.Int32>
%100 = select_enum %0 : $FakeOptional<Builtin.Int32>, case #FakeOptional.some!enumelt.1: %t, case #FakeOptional.none!enumelt: %f : $Builtin.Int1
cond_br %100, bb2, bb3
bb2:
br bb4
bb3:
br bb4
bb4:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_select_enum_3 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
// CHECK: bb0({{.*}}):
// CHECK-NEXT: integer_literal
// CHECK-NEXT: integer_literal
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK-NEXT: retain_value
// CHECK-NEXT: select_enum
// CHECK-NEXT: cond_br
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb3:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
// CHECK: bb4:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value
sil @sink_ref_count_ops_enum_over_select_enum_3 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
bb0(%0 : $FakeOptional<Builtin.Int32>):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
%1 = function_ref @blocker : $@convention(thin) () -> ()
cond_br undef, bb1, bb3
bb1:
retain_value %0 : $FakeOptional<Builtin.Int32>
%100 = select_enum %0 : $FakeOptional<Builtin.Int32>, case #FakeOptional.some!enumelt.1: %t, case #FakeOptional.none!enumelt: %f : $Builtin.Int1
cond_br %100, bb2, bb3
bb2:
br bb4
bb3:
br bb4
bb4:
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_select_enum_4 : $@convention(thin) (FakeOptional<Builtin.Int32>, FakeOptional<Builtin.NativeObject>) -> FakeOptional<Builtin.NativeObject> {
// CHECK: bb0({{%[0-9]+}} : $FakeOptional<Builtin.Int32>, [[ARG1:%[0-9]+]] : $FakeOptional<Builtin.NativeObject>):
// CHECK-NOT: retain_value [[ARG1]]
// CHECK: select_enum
// CHECK: cond_br
// CHECK: bb1:
// CHECK: retain_value
// CHECK: bb2:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value [[ARG1]]
// CHECK: bb3:
// CHECK-NOT: unchecked_enum_data
// CHECK-NOT: retain_value [[ARG1]]
sil @sink_ref_count_ops_enum_over_select_enum_4 : $@convention(thin) (FakeOptional<Builtin.Int32>, FakeOptional<Builtin.NativeObject>) -> FakeOptional<Builtin.NativeObject> {
bb0(%0 : $FakeOptional<Builtin.Int32>, %1 : $FakeOptional<Builtin.NativeObject>):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
%2 = function_ref @blocker : $@convention(thin) () -> ()
retain_value %1 : $FakeOptional<Builtin.NativeObject>
retain_value %0 : $FakeOptional<Builtin.Int32>
%100 = select_enum %1 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: %t, case #FakeOptional.none!enumelt: %f : $Builtin.Int1
cond_br %100, bb1, bb2
bb1:
apply %2() : $@convention(thin) () -> ()
br bb3
bb2:
br bb3
bb3:
return %1 : $FakeOptional<Builtin.NativeObject>
}
/// This version does not work since we have a release before the terminator
/// even though we have the select_enum before it.
// CHECK-LABEL: sil @sink_ref_count_ops_enum_over_select_enum_5 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
// CHECK: bb0({{.*}}):
// CHECK: bb1:
// CHECK-NEXT: function_ref blocker
// CHECK-NEXT: function_ref @blocker
// CHECK-NEXT: alloc_stack
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: select_enum
// CHECK-NEXT: retain_value
// CHECK-NEXT: release_value
// CHECK-NEXT: cond_br
// CHECK: bb2:
// CHECK-NOT: retain_value
// CHECK: bb3:
// CHECK-NOT: retain_value
// CHECK: bb4:
// CHECK-NOT: retain_value
sil @sink_ref_count_ops_enum_over_select_enum_5 : $@convention(thin) (FakeOptional<Builtin.Int32>) -> () {
bb0(%0 : $FakeOptional<Builtin.Int32>):
%t = integer_literal $Builtin.Int1, 1
%f = integer_literal $Builtin.Int1, 0
br bb10
bb10:
%1 = function_ref @blocker : $@convention(thin) () -> ()
retain_value %0 : $FakeOptional<Builtin.Int32>
%3 = alloc_stack $Builtin.Int32
dealloc_stack %3 : $*Builtin.Int32
%100 = select_enum %0 : $FakeOptional<Builtin.Int32>, case #FakeOptional.some!enumelt.1: %t, case #FakeOptional.none!enumelt: %f : $Builtin.Int1
release_value %0 : $FakeOptional<Builtin.Int32>
cond_br %100, bb1, bb2
bb1:
br bb3
bb2:
br bb3
bb3:
%4 = tuple()
return %4 : $()
}
// Sink the struct instruction
// CHECK-LABEL: sil @sink_struct : $@convention(thin) (FakeOptional<Builtin.Int32>) -> Bool {
// CHECK: bb0({{.*}}):
// CHECK: switch_enum
// CHECK: bb1:
// CHECK: integer_literal $Builtin.Int1, -1
// CHECK: br bb3({{.*}} : $Builtin.Int1)
// CHECK: bb2:
// CHECK: integer_literal $Builtin.Int1, 0
// CHECK: br bb3({{.*}} : $Builtin.Int1)
// CHECK: bb3({{.*}} : $Builtin.Int1):
// CHECK: struct $Bool
// CHECK: return
sil @sink_struct : $@convention(thin) (FakeOptional<Builtin.Int32>) -> Bool {
bb0(%0 : $FakeOptional<Builtin.Int32>):
switch_enum %0 : $FakeOptional<Builtin.Int32>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
%6 = integer_literal $Builtin.Int1, -1
%7 = struct $Bool (%6 : $Builtin.Int1)
br bb3(%7 : $Bool)
bb2:
%9 = integer_literal $Builtin.Int1, 0
%10 = struct $Bool (%9 : $Builtin.Int1)
br bb3(%10 : $Bool)
bb3(%12 : $Bool):
return %12 : $Bool
}
// Sink retain down the successors so we can pair up retain with release on the
// fast path.
class Test {
func testing() -> UInt64
}
sil_global @test : $Test
sil_global @x : $UInt64
// CHECK-LABEL: @sink_refcount_to_succs
sil @sink_refcount_to_succs : $@convention(thin) () -> () {
bb0:
%0 = global_addr @test : $*Test
%1 = alloc_ref $Test
store %1 to %0 : $*Test
%7 = global_addr @x : $*UInt64
%8 = integer_literal $Builtin.Int64, 0
%9 = struct $UInt64 (%8 : $Builtin.Int64)
store %9 to %7 : $*UInt64
br bb1
bb1:
// CHECK: bb1:
// CHECK-NOT: strong_retain
%17 = load %0 : $*Test
strong_retain %17 : $Test
%19 = class_method %17 : $Test, #Test.testing!1 : (Test) -> () -> UInt64, $@convention(method) (@guaranteed Test) -> UInt64
%20 = load %7 : $*UInt64
checked_cast_br [exact] %17 : $Test to $Test, bb3, bb4
bb2:
// CHECK: bb2:
// CHECK-NOT: strong_retain
%36 = tuple ()
return %36 : $()
bb3(%38 : $Test):
// CHECK: bb3(
// CHECK: strong_retain
// CHECK: strong_release
strong_release %17 : $Test
br bb2
bb4:
// CHECK: bb4:
// CHECK: strong_retain
// CHECK: apply
%65 = apply %19(%17) : $@convention(method) (@guaranteed Test) -> UInt64
br bb2
}
sil @virtual_callee : $@convention(method) (@guaranteed Test) -> UInt64
sil_vtable Test {
#Test.testing!1: virtual_callee
}
sil @arc_user : $@convention(thin) () -> ()
// CHECK-LABEL: sil @enum_simplification_test1 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb0
// CHECK-NEXT: retain_value
// CHECK-NEXT: release_value
sil @enum_simplification_test1 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
retain_value %0 : $FakeOptional<Builtin.NativeObject>
release_value %0 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_test2 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb0
// CHECK: strong_retain
// CHECK: release_value
sil @enum_simplification_test2 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
%1 = unchecked_enum_data %0 : $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt.1
retain_value %0 : $FakeOptional<Builtin.NativeObject>
release_value %0 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_test3 : $@convention(thin) () -> () {
// CHECK: bb0
// CHECK-NEXT: enum
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @enum_simplification_test3 : $@convention(thin) () -> () {
bb0:
%0 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
retain_value %0 : $FakeOptional<Builtin.NativeObject>
release_value %0 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_test4 : $@convention(thin) () -> () {
// CHECK: bb0
// CHECK-NEXT: get_object
// CHECK-NEXT: function_ref @get_object
// CHECK-NEXT: apply
// CHECK: strong_retain
// CHECK: strong_release
sil @enum_simplification_test4 : $@convention(thin) () -> () {
bb0:
%0 = function_ref @get_object : $@convention(thin) () -> Builtin.NativeObject
%1 = apply %0() : $@convention(thin) () -> Builtin.NativeObject
%2 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.some!enumelt.1, %1 : $Builtin.NativeObject
retain_value %2 : $FakeOptional<Builtin.NativeObject>
release_value %2 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
////////////////
// Loop Tests //
////////////////
// CHECK-LABEL: sil @enum_simplification_test10 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb0([[INPUT:%[0-9]+]] : $FakeOptional<Builtin.NativeObject>):
// CHECK: retain_value [[INPUT]]
// CHECK: retain_value [[INPUT]]
// CHECK: retain_value [[INPUT]]
// CHECK: retain_value [[INPUT]]
sil @enum_simplification_test10 : $@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
// Single BB Loop
bb1:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
cond_br undef, bb1, bb9999
// Two BB Loop. We can use loop or domination to handle this case. But we don't
// handle it now.
bb2:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
br bb3
bb3:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
cond_br undef, bb2, bb9999
bb9999:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// Make sure we don't propagate state out of loops.
// CHECK-LABEL: sil @enum_simplification_test11 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb0([[INPUT:%[0-9]+]] : $FakeOptional<Builtin.NativeObject>):
// CHECK: retain_value [[INPUT]]
// CHECK: retain_value [[INPUT]]
sil @enum_simplification_test11 : $@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:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
cond_br undef, bb1, bb2
bb2:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_test12 : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb1:
// CHECK: release
// CHECK: bb2:
// CHECK-NOT: release
// CHECK: bb3:
// CHECK-NOT: release
sil @enum_simplification_test12 : $@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:
br bb3
bb2:
br bb3
bb3:
release_value %0 : $FakeOptional<Builtin.NativeObject>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_test13 : $@convention(thin) (Either) -> () {
// CHECK: bb0
// CHECK: release_value
// CHECK: bb1:
// CHECK-NOT: strong_release
// CHECK-NOT: release_value
// CHECK: bb2:
// CHECK-NOT: strong_release
// CHECK-NOT: release_value
// CHECK: bb3:
// CHECK-NOT: release_value
sil @enum_simplification_test13 : $@convention(thin) (Either) -> () {
bb0(%0 : $Either):
cond_br undef, bb1, bb2
bb1:
%1 = unchecked_enum_data %0 : $Either, #Either.First!enumelt.1
br bb3
bb2:
%2 = unchecked_enum_data %0 : $Either, #Either.Second!enumelt.1
br bb3
bb3:
release_value %0 : $Either
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_test14 : $@convention(thin) (Either) -> () {
// CHECK: bb0(
// CHECK-NOT: release
// CHECK: bb1:
// CHECK: release
sil @enum_simplification_test14 : $@convention(thin) (Either) -> () {
bb0(%0 : $Either):
%1 = unchecked_enum_data %0 : $Either, #Either.First!enumelt.1
cond_br undef, bb1, bb2
bb1:
release_value %0 : $Either
br bb3
bb2:
br bb3
bb3:
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_test15 : $@convention(thin) (Either, ThreeCaseEnum) -> () {
// CHECK: bb1:
// CHECK: release
// CHECK: bb2:
// CHECK-NOT: release
// CHECK: bb3:
// CHECK-NOT: release
sil @enum_simplification_test15 : $@convention(thin) (Either, ThreeCaseEnum) -> () {
bb0(%0 : $Either, %1 : $ThreeCaseEnum):
%2 = unchecked_enum_data %0 : $Either, #Either.First!enumelt.1
switch_enum %1 : $ThreeCaseEnum, case #ThreeCaseEnum.A!enumelt: bb1,
case #ThreeCaseEnum.B!enumelt: bb2,
case #ThreeCaseEnum.C!enumelt: bb3
bb1:
release_value %0 : $Either
br bb4
bb2:
br bb4
bb3:
br bb4
bb4:
%9999 = tuple()
return %9999 : $()
}
sil @unknown : $@convention(thin) () -> ()
// CHECK-LABEL: sil @enum_simplification_test16 : $@convention(thin) (FakeOptional<C>) -> () {
// CHECK: bb1:
// CHECK-NOT: release
// CHECK: bb2:
// CHECK: release_value
// CHECK: bb3
// CHECK: release
sil @enum_simplification_test16 : $@convention(thin) (FakeOptional<C>) -> () {
bb0(%0 : $FakeOptional<C>):
switch_enum %0 : $FakeOptional<C>,
case #FakeOptional.none!enumelt: bb1,
case #FakeOptional.some!enumelt.1: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
%2 = integer_literal $Builtin.Word, 2
%3 = integer_literal $Builtin.Word, 3
%4 = integer_literal $Builtin.Int1, 0
%5 = builtin "sadd_with_overflow_Word"(%2 : $Builtin.Word, %3 : $Builtin.Word, %4 : $Builtin.Int1) : $(Builtin.Word, Builtin.Int1)
release_value %0 : $FakeOptional<C>
%9998 = function_ref @unknown : $@convention(thin) () -> ()
apply %9998() : $@convention(thin) () -> ()
release_value %0 : $FakeOptional<C>
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @enum_simplification_abstraction_differences : $@convention(thin) (ThreeCaseAbstractionDifference) -> () {
// CHECK: bb0(
// CHECK-NOT: release
// CHECK: bb1:
// CHECK-NOT: release
// CHECK: bb2:
// CHECK: release_value
// CHECK: bb3:
// CHECK: release_value
// CHECK: bb4:
// CHECK-NOT: release_value
sil @enum_simplification_abstraction_differences : $@convention(thin) (ThreeCaseAbstractionDifference) -> () {
bb0(%0 : $ThreeCaseAbstractionDifference):
switch_enum %0 : $ThreeCaseAbstractionDifference,
case #ThreeCaseAbstractionDifference.A!enumelt.1: bb1,
case #ThreeCaseAbstractionDifference.B!enumelt.1: bb2,
case #ThreeCaseAbstractionDifference.C!enumelt.1: bb3
bb1:
br bb4
bb2:
br bb4
bb3:
br bb4
bb4:
release_value %0 : $ThreeCaseAbstractionDifference
%9999 = tuple()
return %9999 : $()
}
// CHECK-LABEL: sil @sink_retains_out_of_switch_regions : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb1:
// CHECK-NOT: retain_value
// CHECK: bb2:
// CHECK-NOT: retain_value
// CHECK: bb3:
// CHECK: retain_value
sil @sink_retains_out_of_switch_regions : $@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:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
br bb3
bb2:
br bb3
bb3:
%1 = tuple()
return %1 : $()
}
// CHECK-LABEL: sil @sink_retains_through_multiple_switches : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: retain_value
// CHECK: bb9:
// CHECK: retain_value
sil @sink_retains_through_multiple_switches : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
retain_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
br bb3
bb2:
br bb3
bb3:
switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb4, case #FakeOptional.none!enumelt: bb5
bb4:
br bb6
bb5:
br bb6
bb6:
switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb7, case #FakeOptional.none!enumelt: bb8
bb7:
br bb9
bb8:
br bb9
bb9:
%1 = tuple()
return %1 : $()
}
// CHECK-LABEL: sil @sink_retains_through_switch_with_body : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK-NOT: retain_value
// CHECK: bb5:
// CHECK: retain_value
sil @sink_retains_through_switch_with_body : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
bb0(%0 : $FakeOptional<Builtin.NativeObject>):
retain_value %0 : $FakeOptional<Builtin.NativeObject>
switch_enum %0 : $FakeOptional<Builtin.NativeObject>, case #FakeOptional.some!enumelt.1: bb1, case #FakeOptional.none!enumelt: bb2
bb1:
br bb3
bb2:
br bb4
bb3:
br bb5
bb4:
br bb5
bb5:
%1 = tuple()
return %1 : $()
}
// Make sure that we blot pointers from the enumbbtoenumbbcaselist map after
// merging predecessors. This ensures that the failure to merge unrelating
// values does not stop sinking out of retain, release regions.
// CHECK-LABEL: sil @enumbbtoenumbbcaselist_invalidation_test : $@convention(thin) (FakeOptional<Builtin.NativeObject>) -> () {
// CHECK: bb3:
// CHECK: retain_value
sil @enumbbtoenumbbcaselist_invalidation_test : $@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:
retain_value %0 : $FakeOptional<Builtin.NativeObject>
br bb3
bb2:
%1 = enum $FakeOptional<Builtin.NativeObject>, #FakeOptional.none!enumelt
br bb3
bb3:
%2 = tuple()
return %2 : $()
}
class F {}
class G {}
// CHECK-LABEL: sil @cast_consumption
// CHECK: store
// CHECK-NEXT: strong_retain
// CHECK-NEXT: unconditional_checked_cast_addr
// CHECK-NEXT: strong_release
sil @cast_consumption : $@convention(thin) (@owned F) -> () {
bb0(%0 : $F):
%1 = alloc_stack $F
store %0 to %1 : $*F
strong_retain %0 : $F
unconditional_checked_cast_addr take_always F in %1 : $*F to G in %1 : $*F
strong_release %0 : $F
dealloc_stack %1 : $*F
%2 = tuple ()
return %2 : $()
}
// Make sure that is_unique stops code motion.
// CHECK-LABEL: sil @is_unique_stops_codemotion : $@convention(thin) (@inout Builtin.NativeObject) -> () {
// CHECK: bb0([[IN:%[0-9]+]] : $*Builtin.NativeObject):
// CHECK: [[LD:%[0-9]+]] = load [[IN]] : $*Builtin.NativeObject
// CHECK: strong_retain [[LD]] : $Builtin.NativeObject
// CHECK: is_unique [[IN]] : $*Builtin.NativeObject
sil @is_unique_stops_codemotion : $@convention(thin) (@inout Builtin.NativeObject) -> () {
bb0(%0 : $*Builtin.NativeObject):
%1 = load %0 : $*Builtin.NativeObject
strong_retain %1 : $Builtin.NativeObject
is_unique %0 : $*Builtin.NativeObject
%9999 = tuple()
return %9999 : $()
}
sil @no_return_func : $@convention(thin) () -> Never
// Make sure that we do not move retains over noreturn functions.
// CHECK-LABEL: sil @no_return_stops_codemotion : $@convention(thin) (Builtin.NativeObject) -> () {
// CHECK: apply
// CHECK-NEXT: unreachable
sil @no_return_stops_codemotion : $@convention(thin) (Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject):
%1 = alloc_ref $C
strong_retain %1 : $C
%9999 = function_ref @no_return_func : $@convention(thin) () -> Never
apply %9999() : $@convention(thin) () -> Never
unreachable
}
// CHECK-LABEL: sil @hoist_release_partially_available_retain
// CHECK: bb0
// CHECK: cond_br undef, bb1, bb2
// CHECK: bb1:
// CHECK: strong_retain
// CHECK: strong_release
// CHECK: br bb3
// CHECK: bb2:
// CHECK: strong_retain
// CHECK: apply
// CHECK: strong_release
// CHECK: br bb3
// CHECK: bb3:
// CHECK-NOT: strong_release
// CHECK: return
sil @hoist_release_partially_available_retain : $@convention(thin) (Builtin.NativeObject, Builtin.NativeObject) -> () {
bb0(%0 : $Builtin.NativeObject, %1: $Builtin.NativeObject):
cond_br undef, bb1, bb2
bb1:
strong_retain %0: $Builtin.NativeObject
br bb3
bb2:
strong_retain %0: $Builtin.NativeObject
%2 = function_ref @blocker : $@convention(thin) () -> ()
apply %2() : $@convention(thin) () -> ()
br bb3
bb3:
strong_release %0: $Builtin.NativeObject
%5 = tuple()
return %5 : $()
}
// Make sure release can be hoisted across memory that do not escape.
// CHECK-LABEL: sil @hoist_release_across_local_memory_use
// CHECK: bb1:
// CHECK: strong_release
// CHECK: br bb3
// CHECK: bb2:
// CHECK: strong_release
// CHECK: br bb3
// CHECK: bb3:
// CHECK-NOT: strong_release
// CHECK: return
sil @hoist_release_across_local_memory_use : $@convention(thin) (Builtin.NativeObject) ->() {
bb0(%0 : $Builtin.NativeObject):
%1 = alloc_stack $A
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $Builtin.NativeObject
br bb3
bb2:
br bb3
bb3:
%2 = integer_literal $Builtin.Int32, 0
%3 = struct $A (%2 : $Builtin.Int32)
store %3 to %1 : $*A
strong_release %0 : $Builtin.NativeObject
dealloc_stack %1 : $*A
%5 = tuple()
return %5 : $()
}
// Make sure release can not be hoisted across memory that do escape. i.e. the release
// deinit can read or write to the memory.
// CHECK-LABEL: sil @hoist_release_across_escaping_param_memory_use
// CHECK: bb1:
// CHECK-NOT: strong_release
// CHECK: br bb3
// CHECK: bb2:
// CHECK-NOT: strong_release
// CHECK: br bb3
// CHECK: bb3:
// CHECK: store
// CHECK: strong_release
// CHECK: return
sil @hoist_release_across_escaping_param_memory_use : $@convention(thin) (Builtin.NativeObject, C2) ->() {
bb0(%0 : $Builtin.NativeObject, %1 : $C2):
%2 = ref_element_addr %1 : $C2, #C2.current
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $Builtin.NativeObject
br bb3
bb2:
br bb3
bb3:
%3 = integer_literal $Builtin.Int32, 0
%4 = struct $A (%3 : $Builtin.Int32)
store %4 to %2 : $*A
strong_release %0 : $Builtin.NativeObject
%5 = tuple()
return %5 : $()
}
// Make sure release can not be hoisted across memory that do escape, even though its allocated locally.
// i.e. the release
// deinit can read or write to the memory.
// CHECK-LABEL: sil @hoist_release_across_escaping_local_alloc_memory_use
// CHECK: bb1:
// CHECK-NOT: strong_release
// CHECK: br bb3
// CHECK: bb2:
// CHECK-NOT: strong_release
// CHECK: br bb3
// CHECK: bb3:
// CHECK: store
// CHECK: strong_release
// CHECK: return
sil @hoist_release_across_escaping_local_alloc_memory_use : $@convention(thin) (Builtin.NativeObject) ->() {
bb0(%0 : $Builtin.NativeObject):
%1 = alloc_ref $C2
%2 = ref_element_addr %1 : $C2, #C2.current
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $Builtin.NativeObject
br bb3
bb2:
br bb3
bb3:
%22 = function_ref @use_C2 : $@convention(thin) (C2) -> ()
%23 = apply %22(%1) : $@convention(thin) (C2) -> ()
%3 = integer_literal $Builtin.Int32, 0
%4 = struct $A (%3 : $Builtin.Int32)
store %4 to %2 : $*A
strong_release %0 : $Builtin.NativeObject
%5 = tuple()
return %5 : $()
}
// CHECK-LABEL: sil @hoist_silargument_release
// CHECK: bb1
// CHECK: release
// CHECK: br
// CHECK: bb2
// CHECK: release
// CHECK: br
// CHECK: bb3
sil @hoist_silargument_release : $@convention(thin) (@owned X, @owned X) -> () {
bb0(%0 : $X, %1 : $X):
cond_br undef, bb1, bb2
bb1:
strong_retain %0 : $X
%5 = function_ref @blocker : $@convention(thin) () -> ()
apply %5() : $@convention(thin) () -> ()
br bb3(%0 : $X)
bb2:
strong_retain %1 : $X
br bb3(%1 : $X)
bb3(%3 : $X):
strong_release %3 : $X
%23 = tuple ()
return %23 : $()
}