Files
swift-mirror/test/SILOptimizer/allocbox_to_stack.sil
Nate Chandler 1eafced6a2 [AllocBoxToStack] Don't destroy in dead-ends.
It is valid to leak a value on paths into dead-end regions.
Specifically, it is valid to leak an `alloc_box`.  Thus, "final
releases" in dead-end regions may not destroy the box and consequently
may not release its contents.  Therefore it's invalid to lower such final
releases to `dealloc_stack`s, let alone `destroy_addr`s.  The in-general
invalidity of that transformation results in miscompiling whenever a box
is leaked and its projected address is used after such final releases.

Fix this by not treating final releases as boundary markers of the
`alloc_box` and not lowering them to `destroy_addr`s and
`dealloc_stack`s.

rdar://158149082
2025-08-27 17:03:48 -07:00

1425 lines
48 KiB
Plaintext

// RUN: %target-sil-opt -sil-print-types -sil-print-debuginfo -enable-sil-verify-all %s -allocbox-to-stack -enable-copy-propagation=requested-passes-only | %FileCheck %s
sil_stage raw
import Builtin
struct Int {
var _value: Builtin.Int64
}
struct Bool {
var _value: Builtin.Int1
}
protocol Error {}
class C {}
// CHECK-LABEL: sil @simple_promotion
sil @simple_promotion : $(Int) -> Int {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to %1a : $*Int
%3 = load %1a : $*Int
strong_release %1 : ${ var Int }
return %3 : $Int
// CHECK: alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: strong_release
// CHECK: return
}
// CHECK-LABEL: sil @double_project_box
sil @double_project_box : $(Int) -> (Int, Int) {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to %1a : $*Int
%3 = load %1a : $*Int
%1b = project_box %1 : ${ var Int }, 0
%3b = load %1b : $*Int
strong_release %1 : ${ var Int }
%r = tuple (%3 : $Int, %3b : $Int)
return %r : $(Int, Int)
// CHECK: alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: project_box
// CHECK-NOT: strong_release
// CHECK: return
}
// CHECK-LABEL: sil @init_var
sil @init_var : $() -> Int {
bb0:
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
%3 = load %1a : $*Int
strong_release %1 : ${ var Int }
return %3 : $Int
// CHECK: %0 = alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: strong_release
// CHECK-NOT: destroy_addr
// CHECK: dealloc_stack %0 : $*Int
// CHECK: return
}
// CHECK-LABEL: sil @multi_strong_release
sil @multi_strong_release : $() -> Int {
bb0:
%1 = alloc_box ${ var Int }
%1a = mark_uninitialized [rootself] %1 : ${ var Int }
%2 = project_box %1a : ${ var Int }, 0
%3 = load %2 : $*Int
strong_retain %1a : ${ var Int }
strong_release %1a : ${ var Int }
br bb1
bb1:
strong_release %1a : ${ var Int }
return %3 : $Int
// CHECK: %0 = alloc_stack
// CHECK: bb1:
// CHECK: dealloc_stack %0 : $*Int
// CHECK: return
}
struct TestStruct {
var Elt : Int
}
// CHECK-LABEL: sil @struct_tuple_element_addr
sil @struct_tuple_element_addr : $(Int) -> Int {
bb1(%0 : $Int):
// CHECK-DAG: [[STRUCT:%.*]] = alloc_stack $TestStruct
// CHECK-DAG: [[TUPLE:%.*]] = alloc_stack $(Int, Int)
%1 = alloc_box ${ var TestStruct }
%1a = project_box %1 : ${ var TestStruct }, 0
%a = alloc_box ${ var (Int, Int) }
%aa = project_box %a : ${ var (Int, Int) }, 0
%2 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
store %0 to %2 : $*Int
%b = tuple_element_addr %aa : $*(Int, Int), 0
store %0 to %b : $*Int
%6 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
%7 = load %6 : $*Int
strong_release %a : ${ var (Int, Int) }
strong_release %1 : ${ var TestStruct }
return %7 : $Int
// CHECK-DAG: dealloc_stack [[STRUCT]]
// CHECK-DAG: dealloc_stack [[TUPLE]]
// CHECK: return
}
sil @callee : $@convention(thin) (@inout Int) -> ()
// CHECK-LABEL: sil @escaping_pointer
sil @escaping_pointer : $@convention(thin) () -> Int {
bb0:
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
%6 = function_ref @callee : $@convention(thin) (@inout Int) -> ()
%7 = apply %6(%1a) : $@convention(thin) (@inout Int) -> ()
%8 = load %1a : $*Int
strong_release %1 : ${ var Int }
%10 = address_to_pointer %1a : $*Int to $Builtin.RawPointer
%11 = pointer_to_address %10 : $Builtin.RawPointer to [strict] $*Int
%12 = load %11 : $*Int
return %8 : $Int
// CHECK: return
}
protocol P {
}
sil @returns_protocol : $@convention(thin) () -> @out P
// CHECK-LABEL: sil @test_indirect_return
sil @test_indirect_return : $@convention(thin) () -> () {
bb0:
// CHECK: alloc_stack
%1 = function_ref @returns_protocol : $@convention(thin) () -> @out P
%2 = alloc_box ${ var P }
%2a = project_box %2 : ${ var P }, 0
%3 = apply %1(%2a) : $@convention(thin) () -> @out P
strong_release %2 : ${ var P }
%0 = tuple ()
return %0 : $()
// CHECK: return
}
class SomeClass {}
// CHECK-LABEL: sil @class_promotion
sil @class_promotion : $(SomeClass) -> SomeClass {
bb0(%0 : $SomeClass):
%1 = alloc_box ${ var SomeClass }
%1a = project_box %1 : ${ var SomeClass }, 0
store %0 to %1a : $*SomeClass
%3 = load %1a : $*SomeClass
strong_release %1 : ${ var SomeClass }
return %3 : $SomeClass
// CHECK: %1 = alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: strong_release
// CHECK: destroy_addr {{.*}} : $*SomeClass
// CHECK: return
}
protocol LogicValue {
func getLogicValue() -> Bool
}
// CHECK-LABEL: @protocols
sil @protocols : $@convention(thin) (@in LogicValue, @thin Bool.Type) -> Bool {
bb0(%0 : $*LogicValue, %1 : $@thin Bool.Type):
%2 = alloc_box ${ var LogicValue }
%2a = project_box %2 : ${ var LogicValue }, 0
// CHECK: %2 = alloc_stack $any LogicValue
copy_addr [take] %0 to [init] %2a : $*LogicValue
%6 = open_existential_addr mutable_access %2a : $*LogicValue to $*@opened("01234567-89ab-cdef-0123-000000000000", LogicValue) Self
%7 = witness_method $@opened("01234567-89ab-cdef-0123-000000000000", LogicValue) Self, #LogicValue.getLogicValue, %6 : $*@opened("01234567-89ab-cdef-0123-000000000000", LogicValue) Self : $@convention(witness_method: LogicValue) <T: LogicValue> (@in_guaranteed T) -> Bool
%8 = apply %7<@opened("01234567-89ab-cdef-0123-000000000000", LogicValue) Self>(%6) : $@convention(witness_method: LogicValue) <T: LogicValue> (@in_guaranteed T) -> Bool
strong_release %2 : ${ var LogicValue }
// CHECK: destroy_addr %2 : $*any LogicValue
// CHECK-NEXT: dealloc_stack %2 : $*any LogicValue
// CHECK-NEXT: return
return %8 : $Bool
}
// Generics test, which is address-only.
class Generic<T> {}
// CHECK-LABEL: sil @dealloc_box
sil @dealloc_box : $@convention(thin) <T> () -> () {
bb0: // CHECK-NEXT: bb0:
// CHECK-NEXT: alloc_stack
%1 = alloc_box $<τ_0_0> { var Generic<τ_0_0> } <T>
dealloc_box %1 : $<τ_0_0> { var Generic<τ_0_0> } <T>
%0 = tuple () // CHECK: tuple ()
return %0 : $()
// CHECK: return
}
enum SomeUnion {
case x(Int)
case y(SomeClass)
}
sil @$s1t9SomeUnionO1yfMS0_FCS_9SomeClassS0_ : $@convention(thin) (@owned SomeClass, @thin SomeUnion.Type) -> @owned SomeUnion
sil @$s1t9SomeClassCCfMS0_FT_S0_ : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass
// CHECK-LABEL: sil @union_test
sil @union_test : $@convention(thin) () -> () {
bb0:
// CHECK: [[UNION:%.*]] = alloc_stack
%1 = alloc_box ${ var SomeUnion }
%1a = project_box %1 : ${ var SomeUnion }, 0
%2 = function_ref @$s1t9SomeUnionO1yfMS0_FCS_9SomeClassS0_ : $@convention(thin) (@owned SomeClass, @thin SomeUnion.Type) -> @owned SomeUnion // user: %7
%3 = metatype $@thin SomeUnion.Type
%4 = function_ref @$s1t9SomeClassCCfMS0_FT_S0_ : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass // user: %6
%5 = metatype $@thick SomeClass.Type
%6 = apply %4(%5) : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass
%7 = apply %2(%6, %3) : $@convention(thin) (@owned SomeClass, @thin SomeUnion.Type) -> @owned SomeUnion
store %7 to %1a : $*SomeUnion
strong_release %1 : ${ var SomeUnion }
%10 = tuple ()
return %10 : $()
// CHECK: dealloc_stack [[UNION]]
// CHECK: [[T0:%.*]] = tuple ()
// CHECK-NEXT: return [[T0]] : $()
}
// CHECK-LABEL: sil @multiple_release_test
sil @multiple_release_test : $@convention(thin) (Bool) -> Bool {
bb0(%0 : $Bool):
%1 = alloc_box ${ var Bool }
%1a = project_box %1 : ${ var Bool }, 0
store %0 to %1a : $*Bool
strong_retain %1 : ${ var Bool }
strong_retain %1 : ${ var Bool }
%5 = tuple ()
%6 = load %1a : $*Bool
strong_release %1 : ${ var Bool }
strong_release %1 : ${ var Bool }
strong_release %1 : ${ var Bool }
return %6 : $Bool
// CHECK: alloc_stack $Bool
// CHECK-NEXT: store {{%[0-9]+}}
// CHECK-NEXT: tuple ()
// CHECK-NEXT: load
// CHECK-NEXT: dealloc_stack
// CHECK-NEXT: return
}
// Make sure that we can promote this box and dealloc_stack
// on each path.
//
// CHECK-LABEL: sil @box_reachable_from_release_test
sil @box_reachable_from_release_test : $@convention(thin) () -> () {
bb0:
br bb1
// CHECK: bb1:
// CHECK-NEXT: alloc_stack
bb1:
%1 = alloc_box ${ var Bool }
cond_br undef, bb2, bb3
// CHECK: bb2:
// CHECK-NEXT: dealloc_stack
bb2:
strong_release %1 : ${ var Bool }
br bb1
// CHECK: bb3:
// CHECK-NEXT: dealloc_stack
bb3:
strong_release %1 : ${ var Bool }
%2 = tuple ()
// CHECK: return
return %2 : $()
}
sil @useSomeClass : $@convention(thin) (@owned SomeClass) -> ()
// <rdar://problem/16382973> DI misses destroy_addr because allocbox_to_stack isn't preserving mark_uninitialized invariants
// When allocbox_to_stack promotes the box, it should rewrite the multiple
// strong_releases into destroy_addr/dealloc_stack pairs. However, it needs to
// make sure to use the MUI result for the destroy addr.
public protocol My_Incrementable { }
extension Int : My_Incrementable { }
// CHECK-LABEL: sil @test_mui
sil @test_mui : $@convention(thin) (Builtin.Int1) -> () {
bb0(%0 : $Builtin.Int1):
%2 = alloc_box ${ var SomeClass }
%2a = mark_uninitialized [var] %2 : ${ var SomeClass }
%3 = project_box %2a : ${ var SomeClass }, 0
// CHECK: [[STACK:%[0-9]+]] = alloc_stack
// CHECK: [[MUI:%[0-9]+]] = mark_uninitialized
cond_br %0, bb1, bb3
bb1:
%7 = function_ref @$s1t9SomeClassCCfMS0_FT_S0_ : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass // user: %6
%8 = metatype $@thick SomeClass.Type
%9 = apply %7(%8) : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass
assign %9 to %3 : $*SomeClass
%11 = function_ref @useSomeClass : $@convention(thin) (@owned SomeClass) -> ()
%12 = load %3 : $*SomeClass
strong_retain %12 : $SomeClass
%14 = apply %11(%12) : $@convention(thin) (@owned SomeClass) -> ()
strong_release %2a : ${ var SomeClass }
// CHECK: destroy_addr [[MUI]]
// CHECK-NEXT: dealloc_stack [[STACK]]
br bb2
// CHECK: bb2
bb2:
%17 = tuple ()
// CHECK: return
return %17 : $()
bb3:
strong_release %2a : ${ var SomeClass }
// CHECK: destroy_addr [[MUI]]
// CHECK-NEXT: dealloc_stack [[STACK]]
br bb2
}
// CHECK-LABEL: sil @$s6struct5apply1fS2iyc_tF
// struct.apply (f : () -> Swift.Int) -> Swift.Int
sil @$s6struct5apply1fS2iyc_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> Int {
bb0(%0 : $@callee_owned () -> Int):
debug_value %0 : $@callee_owned () -> Int, let, name "f" // id: %1
strong_retain %0 : $@callee_owned () -> Int // id: %2
%3 = apply %0() : $@callee_owned () -> Int // user: %5
strong_release %0 : $@callee_owned () -> Int // id: %4
return %3 : $Int // id: %5
}
// CHECK-LABEL: sil @$s6struct6escape1fSiycSiyc_tF
// struct.escape (f : () -> Swift.Int) -> () -> Swift.Int
sil @$s6struct6escape1fSiycSiyc_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> @owned @callee_owned () -> Int {
bb0(%0 : $@callee_owned () -> Int):
debug_value %0 : $@callee_owned () -> Int, let, name "f" // id: %1
return %0 : $@callee_owned () -> Int // id: %2
}
// CHECK-LABEL: sil @$s6struct8useStack1tySi_tF
// struct.useStack (t : Swift.Int) -> ()
sil @$s6struct8useStack1tySi_tF : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
debug_value %0 : $Int, let, name "t" // id: %1
// CHECK: alloc_stack
%2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>, var, name "s" // users: %3, %6, %7, %7, %9
%2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
store %0 to %2a : $*Int // id: %3
// function_ref struct.apply (f : () -> Swift.Int) -> Swift.Int
%4 = function_ref @$s6struct5apply1fS2iyc_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> Int // user: %8
// CHECK: [[FUNC:%[a-zA-Z0-9]+]] = function_ref @$s6struct8useStack1tySi_tFSiycfU_Tf0s_n
// function_ref struct.(useStack (t : Swift.Int) -> ()).(closure #1)
%5 = function_ref @$s6struct8useStack1tySi_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %7
strong_retain %2 : $<τ_0_0> { var τ_0_0 } <Int> // id: %6
// CHECK: [[PA:%[a-zA-Z0-9]+]] = partial_apply [[FUNC]]
%7 = partial_apply %5(%2) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %8
%8 = apply %4(%7) : $@convention(thin) (@owned @callee_owned () -> Int) -> Int
strong_release %2 : $<τ_0_0> { var τ_0_0 } <Int>
%10 = tuple () // user: %11
return %10 : $() // id: %11
}
// CHECK-LABEL: sil private @$s6struct8useStack1tySi_tFSiycfU_Tf0s_n
// CHECK-LABEL: sil private @$s6struct8useStack1tySi_tFSiycfU_
// struct.(useStack (t : Swift.Int) -> ()).(closure #1)
sil private @$s6struct8useStack1tySi_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Int>):
%1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Int>, 0
// function_ref Swift.++ @postfix <A : Swift._Incrementable>(x : @inout A) -> A
%2 = function_ref @_TFsoP2ppUs14_Incrementable__FT1xRQ__Q_ : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0 // user: %4
%3 = alloc_stack $Int // users: %4, %5, %6
%4 = apply %2<Int>(%3, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0
%5 = load %3 : $*Int // user: %8
dealloc_stack %3 : $*Int // id: %6
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Int> // id: %7
return %5 : $Int // id: %8
}
// Swift.++ @postfix <A : Swift._Incrementable>(x : @inout A) -> A
sil [transparent] @_TFsoP2ppUs14_Incrementable__FT1xRQ__Q_ : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0
// CHECK-LABEL: sil @$s6struct6useBox1tySi_tF
// struct.useBox (t : Swift.Int) -> ()
sil @$s6struct6useBox1tySi_tF : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
debug_value %0 : $Int, let, name "t" // id: %1
// CHECK: alloc_box
%2 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>, var, name "s" // users: %3, %6, %7, %7, %10
%2a = project_box %2 : $<τ_0_0> { var τ_0_0 } <Int>, 0
store %0 to %2a : $*Int // id: %3
// function_ref struct.escape (f : () -> Swift.Int) -> () -> Swift.Int
%4 = function_ref @$s6struct6escape1fSiycSiyc_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> @owned @callee_owned () -> Int // user: %8
// function_ref struct.(useBox (t : Swift.Int) -> ()).(closure #1)
%5 = function_ref @$s6struct6useBox1tySi_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %7
strong_retain %2 : $<τ_0_0> { var τ_0_0 } <Int> // id: %6
%7 = partial_apply %5(%2) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %8
%8 = apply %4(%7) : $@convention(thin) (@owned @callee_owned () -> Int) -> @owned @callee_owned () -> Int // user: %9
%9 = apply %8() : $@callee_owned () -> Int
strong_release %2 : $<τ_0_0> { var τ_0_0 } <Int> // id: %10
%11 = tuple () // user: %12
return %11 : $() // id: %12
}
// CHECK-LABEL: sil private @$s6struct6useBox1tySi_tFSiycfU_
// struct.(useBox (t : Swift.Int) -> ()).(closure #1)
sil private @$s6struct6useBox1tySi_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Int>):
%1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Int>, 0
// function_ref Swift.++ @postfix <A : Swift._Incrementable>(x : @inout A) -> A
%2 = function_ref @_TFsoP2ppUs14_Incrementable__FT1xRQ__Q_ : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0 // user: %4
%3 = alloc_stack $Int // users: %4, %5, %6
%4 = apply %2<Int>(%3, %1) : $@convention(thin) <τ_0_0 where τ_0_0 : My_Incrementable> (@inout τ_0_0) -> @out τ_0_0
%5 = load %3 : $*Int // user: %8
dealloc_stack %3 : $*Int // id: %6
strong_release %0 : $<τ_0_0> { var τ_0_0 } <Int> // id: %7
return %5 : $Int // id: %8
}
// CHECK-LABEL: sil @closure
sil @closure : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
// CHECK-LABEL: sil @no_final_release
sil @no_final_release : $@convention(thin) (Int) -> Bool {
bb0(%0 : $Int):
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Int>, 0
store %0 to %1a : $*Int
// function_ref main.(newFoo (Swift.Int) -> Swift.Bool).(modify #1) (())()
%3 = function_ref @closure : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
strong_retain %1 : $<τ_0_0> { var τ_0_0 } <Int>
%5 = partial_apply %3(%1) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
strong_retain %5 : $@callee_owned () -> ()
%7 = apply %5() : $@callee_owned () -> ()
strong_release %5 : $@callee_owned () -> ()
unreachable
}
// CHECK-LABEL: sil [transparent] [serialized] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> ()
sil [transparent] [serialized] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> () {
// CHECK: bb0
bb0(%0 : $@callee_owned () -> @out U):
debug_value %0 : $@callee_owned () -> @out U
strong_retain %0 : $@callee_owned () -> @out U
%3 = alloc_stack $U
%4 = apply %0(%3) : $@callee_owned () -> @out U
destroy_addr %3 : $*U
dealloc_stack %3 : $*U
strong_release %0 : $@callee_owned () -> @out U
%8 = tuple ()
// CHECK: return
return %8 : $()
}
sil [transparent] [serialized] @mightApplyGuaranteed : $@convention(thin) <U where U : P> (@guaranteed @callee_guaranteed () -> @out U) -> () {
bb0(%0 : $@callee_guaranteed () -> @out U):
debug_value %0 : $@callee_guaranteed () -> @out U
%3 = alloc_stack $U
%4 = apply %0(%3) : $@callee_guaranteed () -> @out U
destroy_addr %3 : $*U
dealloc_stack %3 : $*U
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: sil @callWithAutoclosure
sil @callWithAutoclosure : $@convention(thin) <T where T : P> (@in T) -> () {
// CHECK: bb0
bb0(%0 : $*T):
// CHECK: debug_value {{.*}} expr op_deref
debug_value %0 : $*T, expr op_deref
// CHECK: function_ref @mightApply
%2 = function_ref @mightApply : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
%3 = function_ref @closure_to_specialize : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
// CHECK-NOT: alloc_box
// CHECK: [[STACK:%[0-9a-zA-Z_]+]] = alloc_stack $T
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
%4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
// CHECK: copy_addr %0 to [init] [[STACK]] : $*T
copy_addr %0 to [init] %4a : $*T
// CHECK: [[CLOSURE:%[0-9a-zA-Z]+]] = function_ref @$s21closure_to_specializeTf0ns_n
// CHECK: partial_apply [[CLOSURE]]<T>([[STACK]])
%6 = partial_apply %3<T>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
%7 = apply %2<T>(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
// CHECK: destroy_addr [[STACK]] : $*T
// CHECK: dealloc_stack [[STACK]] : $*T
destroy_addr %0 : $*T
%9 = tuple ()
// CHECK: return
return %9 : $()
}
// CHECK-LABEL: sil @callWithAutoclosure_2 : $@convention(thin) <T where T : P> (@in T) -> () {
sil @callWithAutoclosure_2 : $@convention(thin) <T where T : P> (@in T) -> () {
// CHECK: bb0
bb0(%0 : $*T):
// CHECK: debug_value {{.*}} expr op_deref
debug_value %0 : $*T, expr op_deref
// CHECK: function_ref @mightApply
%2 = function_ref @mightApply : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
%3 = function_ref @closure_to_specialize : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
// CHECK-NOT: alloc_box
// CHECK: [[STACK:%[0-9a-zA-Z_]+]] = alloc_stack $T
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
%4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
strong_retain %4 : $<τ_0_0> { var τ_0_0 } <T>
// CHECK: copy_addr %0 to [init] [[STACK]] : $*T
copy_addr %0 to [init] %4a : $*T
// CHECK: [[CLOSURE:%[0-9a-zA-Z]+]] = function_ref @$s21closure_to_specializeTf0ns_n
// CHECK: partial_apply [[CLOSURE]]<T>([[STACK]])
%6 = partial_apply %3<T>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
%7 = apply %2<T>(%6) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@owned @callee_owned () -> @out τ_0_0) -> ()
// CHECK: destroy_addr [[STACK]] : $*T
// CHECK: dealloc_stack [[STACK]] : $*T
destroy_addr %0 : $*T
strong_release %4 : $<τ_0_0> { var τ_0_0 } <T>
%9 = tuple ()
// CHECK: return
return %9 : $()
}
// CHECK: } // end sil function 'callWithAutoclosure_2'
// CHECK-LABEL: sil private @$s21closure_to_specializeTf0ns_n : $@convention(thin) <T where T : P> (@inout_aliasable T) -> @out T
sil private @closure_to_specialize : $@convention(thin) <T where T : P> (@owned <τ_0_0> { var τ_0_0 } <T>) -> @out T {
// CHECK: bb0
bb0(%0 : $*T, %1 : $<τ_0_0> { var τ_0_0 } <T>):
%2 = project_box %1 : $<τ_0_0> { var τ_0_0 } <T>, 0
// CHECK-NEXT: copy_addr
copy_addr %2 to [init] %0 : $*T
// CHECK-NOT: strong_release
strong_release %1 : $<τ_0_0> { var τ_0_0 } <T>
%5 = tuple ()
// CHECK: return
return %5 : $()
}
protocol Count {
var count: Int { get }
}
struct Q : Count {
var count: Int { get }
init()
}
struct S<T : Count> {
@_hasStorage var t: T
var count: Int { get }
func test(i: Int) -> Bool
init(t: T)
}
// CHECK-LABEL: sil [noinline] @inner
sil [noinline] @inner : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool {
// CHECK: bb0
bb0(%0 : $@callee_owned () -> Bool):
debug_value %0 : $@callee_owned () -> Bool
strong_retain %0 : $@callee_owned () -> Bool
%3 = apply %0() : $@callee_owned () -> Bool
strong_release %0 : $@callee_owned () -> Bool
// CHECK: return
return %3 : $Bool
}
// CHECK-LABEL: sil [noinline] @outer
sil [noinline] @outer : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool {
// CHECK: bb0
bb0(%0 : $@callee_owned () -> Bool):
debug_value %0 : $@callee_owned () -> Bool
strong_retain %0 : $@callee_owned () -> Bool
%3 = apply %0() : $@callee_owned () -> Bool
strong_release %0 : $@callee_owned () -> Bool
// CHECK: return
return %3 : $Bool
}
// CHECK-LABEL: sil @get
sil @get : $@convention(method) <T where T : Count> (@in S<T>) -> Int
// CHECK-LABEL: sil shared @specialized
sil shared @specialized : $@convention(method) (Int, @in S<Q>) -> Bool {
// CHECK: bb0
bb0(%0 : $Int, %1 : $*S<Q>):
debug_value %0 : $Int
debug_value %1 : $*S<Q>, expr op_deref
%4 = function_ref @outer : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
%5 = function_ref @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool
%6 = alloc_box $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <Q>
%6a = project_box %6 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <Q>, 0
copy_addr %1 to [init] %6a : $*S<Q>
%8 = partial_apply %5<Q>(%0, %6) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
%9 = apply %4(%8) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
destroy_addr %1 : $*S<Q>
// CHECK: return
return %9 : $Bool
}
// CHECK-LABEL: sil @unspecialized
sil @unspecialized : $@convention(method) <T where T : Count> (Int, @in S<T>) -> Bool {
// CHECK: bb0
bb0(%0 : $Int, %1 : $*S<T>):
debug_value %0 : $Int
debug_value %1 : $*S<T>, expr op_deref
%4 = function_ref @outer : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
%5 = function_ref @closure1 : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
%6 = alloc_box $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
%6a = project_box %6 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
copy_addr %1 to [init] %6a : $*S<T>
%8 = partial_apply %5<T>(%0, %6) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
%9 = apply %4(%8) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
destroy_addr %1 : $*S<T>
// CHECK: return
return %9 : $Bool
}
// CHECK-LABEL: sil shared @closure1
sil shared @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
// CHECK: bb0
bb0(%0 : $Int, %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>):
%2 = project_box %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
%3 = function_ref @inner : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
%4 = function_ref @closure2 : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
%5 = alloc_box $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
%5a = project_box %5 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
copy_addr %2 to [init] %5a : $*S<T>
%7 = partial_apply %4<T>(%0, %5) : $@convention(thin) <τ_0_0 where τ_0_0 : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <τ_0_0>) -> Bool
%8 = apply %3(%7) : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool
strong_release %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
// CHECK: return
return %8 : $Bool
}
// CHECK-LABEL: sil shared @$s8closure2Tf0ns_n
// CHECK: bb0
// CHECK: return
// CHECK-NOT: bb1
// CHECK-LABEL: sil shared @closure2
sil shared @closure2 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
// CHECK: bb0
bb0(%0 : $Int, %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>):
%2 = project_box %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
%3 = function_ref @binary : $@convention(thin) (Int, Int) -> Bool
%4 = alloc_stack $S<T>
copy_addr %2 to [init] %4 : $*S<T>
%6 = function_ref @get : $@convention(method) <τ_0_0 where τ_0_0 : Count> (@in S<τ_0_0>) -> Int
%7 = apply %6<T>(%4) : $@convention(method) <τ_0_0 where τ_0_0 : Count> (@in S<τ_0_0>) -> Int
%8 = apply %3(%0, %7) : $@convention(thin) (Int, Int) -> Bool
dealloc_stack %4 : $*S<T>
strong_release %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
// CHECK: return
return %8 : $Bool
}
// CHECK-LABEL: sil [transparent] [serialized] @binary
sil [transparent] [serialized] @binary : $@convention(thin) (Int, Int) -> Bool
// CHECK-LABEL: sil @destroy_stack_value_after_closure
sil @destroy_stack_value_after_closure : $@convention(thin) <T> (@in T) -> @out T {
// CHECK: bb0
bb0(%0 : $*T, %1 : $*T):
// CHECK: [[STACK:%.*]] = alloc_stack
// CHECK: copy_addr %1 to [init] [[STACK]]
// CHECK: [[APPLIED:%.*]] = function_ref
%3 = function_ref @applied : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> ()
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
%4a = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
copy_addr %1 to [init] %4a : $*T
// CHECK: [[PARTIAL:%.*]] = partial_apply [[APPLIED]]<T>([[STACK]])
%6 = partial_apply %3<T>(%4) : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> ()
// CHECK: debug_value [[PARTIAL]]
debug_value %6 : $@callee_owned () -> ()
// CHECK: strong_retain [[PARTIAL]]
strong_retain %6 : $@callee_owned () -> ()
// CHECK: apply [[PARTIAL]]
%9 = apply %6() : $@callee_owned () -> ()
copy_addr %1 to [init] %0 : $*T
// CHECK: strong_release [[PARTIAL]]
strong_release %6 : $@callee_owned () -> ()
// CHECK: destroy_addr [[STACK]]
// CHECK: destroy_addr %1
destroy_addr %1 : $*T
%13 = tuple ()
return %13 : $()
}
sil @applied : $@convention(thin) <T> (@owned <τ_0_0> { var τ_0_0 } <T>) -> () {
bb0(%0 : $<τ_0_0> { var τ_0_0 } <T>):
%1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <T>, 0
%2 = function_ref @consume : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
%3 = alloc_stack $T
copy_addr %1 to [init] %3 : $*T
%5 = apply %2<T>(%3) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> ()
dealloc_stack %3 : $*T
strong_release %0 : $<τ_0_0> { var τ_0_0 } <T>
%8 = tuple ()
return %8 : $()
}
sil hidden [noinline] @consume : $@convention(thin) <T> (@in T) -> () {
bb0(%0 : $*T):
debug_value %0 : $*T, expr op_deref
destroy_addr %0 : $*T
%3 = tuple ()
return %3 : $()
}
class ThrowBaseClass {
required init() throws
init(noFail: ())
}
class ThrowDerivedClass : ThrowBaseClass {
//final init(failBeforeFullInitialization: Int) throws
}
sil @throwing_unwrap : $@convention(thin) (Int) -> (Int, @error any Error)
sil @fake_throwing_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error any Error)
sil hidden @try_apply_during_chaining_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error any Error) {
// %0 // users: %11, %5
// %1 // user: %7
bb0(%0 : $Int, %1 : $ThrowDerivedClass):
%2 = alloc_box ${ var ThrowDerivedClass }, let, name "self"
%3 = mark_uninitialized [delegatingself] %2 : ${ var ThrowDerivedClass }
%4 = project_box %3 : ${ var ThrowDerivedClass }, 0
store %1 to %4 : $*ThrowDerivedClass
%8 = load %4 : $*ThrowDerivedClass
%9 = function_ref @fake_throwing_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error any Error)
%10 = function_ref @throwing_unwrap : $@convention(thin) (Int) -> (Int, @error any Error)
try_apply %10(%0) : $@convention(thin) (Int) -> (Int, @error any Error), normal bb1, error bb3
// %12 // user: %13
bb1(%12 : $Int): // Preds: bb0
try_apply %9(%12, %8) : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error any Error), normal bb2, error bb4
// %14 // user: %15
bb2(%14 : $ThrowDerivedClass): // Preds: bb1
store %14 to %4 : $*ThrowDerivedClass
%16 = load %4 : $*ThrowDerivedClass
strong_retain %16 : $ThrowDerivedClass
strong_release %3 : ${ var ThrowDerivedClass }
return %16 : $ThrowDerivedClass
// %20 // user: %22
bb3(%20 : $Error): // Preds: bb0
strong_release %8 : $ThrowDerivedClass
br bb5(%20 : $Error)
// %23 // user: %24
bb4(%23 : $Error): // Preds: bb1
br bb5(%23 : $Error)
// %25 // user: %27
bb5(%25 : $Error): // Preds: bb4 bb3
strong_release %3 : ${ var ThrowDerivedClass }
throw %25 : $Error
}
// CHECK-LABEL: sil @deal_with_wrong_nesting
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[STACK1:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: bb1:
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack [[STACK1]]
// CHECK: bb2:
// CHECK: store {{%[0-9]+}}
// CHECK: [[STACK2:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: dealloc_stack [[STACK2]] : $*Bool, loc "testloc":27:27
// CHECK-NEXT: dealloc_stack [[BOX]] : $*Int, loc "testloc":27:27
// CHECK-NEXT: dealloc_stack [[STACK1]] : $*Bool, loc "testloc":27:27
// CHECK: bb3:
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @deal_with_wrong_nesting : $(Int) -> () {
bb0(%0 : $Int):
%as1 = alloc_stack $Bool
%1 = alloc_box ${ var Int }
cond_br undef, bb1, bb2
bb1:
strong_release %1 : ${ var Int }
dealloc_stack %as1 : $*Bool
br bb3
bb2:
%1a = project_box %1 : ${ var Int }, 0
store %0 to %1a : $*Int
dealloc_stack %as1 : $*Bool
%3 = load %1a : $*Int
%as2 = alloc_stack $Bool
strong_release %1 : ${ var Int }
dealloc_stack %as2 : $*Bool, loc "testloc":27:27
br bb3
bb3:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @wrong_nesting_with_alloc_ref
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[REF:%[0-9]+]] = alloc_ref [stack] $SomeClass
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: store {{%[0-9]+}}
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack_ref [[REF]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @wrong_nesting_with_alloc_ref : $(Int) -> () {
bb0(%0 : $Int):
%as1 = alloc_ref [stack] $SomeClass
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to %1a : $*Int
dealloc_stack_ref %as1 : $SomeClass
%3 = load %1a : $*Int
strong_release %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @nesting_and_unreachable1
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[STACK1:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: bb1:
// CHECK-NEXT: [[STACK2:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: dealloc_stack [[STACK2]]
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK: store {{%[0-9]+}}
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack [[STACK1]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @nesting_and_unreachable1 : $(Int) -> () {
bb0(%0 : $Int):
%as1 = alloc_stack $Bool
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
cond_br undef, bb1, bb2
bb1:
%as2 = alloc_stack $Bool
dealloc_stack %as2 : $*Bool
unreachable
bb2:
store %0 to %1a : $*Int
dealloc_stack %as1 : $*Bool
%3 = load %1a : $*Int
strong_release %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @nesting_and_unreachable2
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[STACK1:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: bb1:
// CHECK-NEXT: [[STACK2:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: dealloc_stack [[STACK2]]
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK: store {{%[0-9]+}}
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack [[STACK1]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @nesting_and_unreachable2 : $(Int) -> () {
bb0(%0 : $Int):
%as1 = alloc_stack $Bool
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
cond_br undef, bb1, bb2
bb1:
%as2 = alloc_stack $Bool
strong_release %1 : ${ var Int }
dealloc_stack %as2 : $*Bool
unreachable
bb2:
store %0 to %1a : $*Int
dealloc_stack %as1 : $*Bool
%3 = load %1a : $*Int
strong_release %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @nesting_and_unreachable3
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK-NEXT: [[STACK:%[0-9]+]] = alloc_stack $Bool
// CHECK: bb1:
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK: store {{%[0-9]+}}
// CHECK: dealloc_stack [[STACK]]
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @nesting_and_unreachable3 : $(Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%as1 = alloc_stack $Bool
%1a = project_box %1 : ${ var Int }, 0
cond_br undef, bb1, bb2
bb1:
strong_release %1 : ${ var Int }
unreachable
bb2:
store %0 to %1a : $*Int
%3 = load %1a : $*Int
dealloc_stack %as1 : $*Bool
strong_release %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @nesting_and_unreachable4
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: bb1:
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK: store {{%[0-9]+}}
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @nesting_and_unreachable4 : $(Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
cond_br undef, bb1, bb2
bb1:
unreachable
bb2:
store %0 to %1a : $*Int
%3 = load %1a : $*Int
strong_release %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @nesting_and_unreachable5
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: bb1:
// CHECK-NEXT: {{.*}} = alloc_stack $Bool
// CHECK-NEXT: {{.*}} = alloc_stack $Bool
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK: store {{%[0-9]+}}
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @nesting_and_unreachable5 : $(Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
cond_br undef, bb1, bb2
bb1:
%as1 = alloc_stack $Bool
%as2 = alloc_stack $Bool
unreachable
bb2:
store %0 to %1a : $*Int
%3 = load %1a : $*Int
strong_release %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil @nesting_and_unreachable6
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: bb1:
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: alloc_stack
// CHECK-NEXT: unreachable
// CHECK: bb3:
// CHECK-NEXT: return
sil @nesting_and_unreachable6 : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to %1a : $*Int
%3 = load %1a : $*Int
cond_br undef, bb1, bb2
bb1:
strong_release %1 : ${ var Int }
br bb3
bb2:
%241 = alloc_stack $Int
strong_release %1 : ${ var Int }
unreachable
bb3:
return %3 : $Int
}
// CHECK-LABEL: sil @nesting_and_unreachable7
// CHECK: bb0(%0 : $Bool):
// CHECK-NEXT: [[AB:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: [[AI:%[0-9]+]] = alloc_stack $Int
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK-NEXT: br bb3
// CHECK: bb2:
// CHECK-NEXT: br bb3
// CHECK: bb3:
// CHECK-NEXT: store {{%[0-9]+}}
// CHECK-NEXT: load
// CHECK-NEXT: unreachable
sil @nesting_and_unreachable7 : $@convention(thin) (Bool) -> Bool {
bb0(%0 : $Bool):
%as1 = alloc_stack $Bool
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
cond_br undef, bb1, bb2
bb1:
strong_release %1 : ${ var Int }
br bb3
bb2:
strong_release %1 : ${ var Int }
br bb3
bb3:
store %0 to %as1 : $*Bool
%3 = load %as1 : $*Bool
unreachable
}
// CHECK-LABEL: sil @nesting_and_unreachable_critical_edge
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK-NEXT: [[STACK1:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: cond_br
// CHECK: bb1:
// CHECK-NEXT: [[STACK2:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: cond_br
// CHECK: bb2:
// CHECK-NEXT: dealloc_stack [[STACK2]]
// CHECK-NEXT: br bb4
// CHECK: bb3:
// CHECK: store {{%[0-9]+}}
// CHECK: dealloc_stack [[STACK2]]
// CHECK-NEXT: dealloc_stack [[STACK1]]
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
// CHECK: bb4:
// CHECK-NEXT: unreachable
sil @nesting_and_unreachable_critical_edge : $(Int) -> () {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%as1 = alloc_stack $Bool
%1a = project_box %1 : ${ var Int }, 0
cond_br undef, bb1, bb3
bb1:
%as2 = alloc_stack $Bool
cond_br undef, bb2, bb3
bb2:
store %0 to %1a : $*Int
%3 = load %1a : $*Int
dealloc_stack %as2 : $*Bool
dealloc_stack %as1 : $*Bool
strong_release %1 : ${ var Int }
%r = tuple ()
return %r : $()
bb3:
strong_release %1 : ${ var Int }
unreachable
}
// Verify that we don't crash on this one:
//
// CHECK-LABEL: sil @unreachable_with_two_predecessors
sil @unreachable_with_two_predecessors : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
cond_br undef, bb1, bb4
bb1:
%4 = alloc_stack $Bool
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to %1a : $*Int
cond_br undef, bb3, bb2
bb2:
dealloc_stack %4 : $*Bool
br bb4
bb3:
%9 = load %1a : $*Int
strong_release %1 : ${ var Int }
dealloc_stack %4 : $*Bool
%13 = tuple ()
return %13 : $()
bb4:
unreachable
}
// Verify the case in which a box used by a partial apply which is then used by a try_apply.
//
// <rdar://problem/42815224> Swift CI: 2. Swift Source Compatibility Suite (master): Kitura project fails with compiler crash
// CHECK-LABEL: sil @testPAUsedByTryApplyClosure : $@convention(thin) (@guaranteed { var Int }) -> () {
// CHECK-LABEL: } // end sil function 'testPAUsedByTryApplyClosure'
sil @testPAUsedByTryApplyClosure : $@convention(thin) (@guaranteed { var Int }) -> () {
bb0(%0: ${ var Int }):
%v = tuple ()
return %v : $()
}
// CHECK-LABEL: sil private @testPAUsedByTryApply : $@convention(method) (@callee_guaranteed (@guaranteed @callee_guaranteed () -> ()) -> @error any Error) -> () {
// CHECK-LABEL: } // end sil function 'testPAUsedByTryApply'
sil private @testPAUsedByTryApply : $@convention(method) (@callee_guaranteed (@guaranteed @callee_guaranteed () -> ()) -> @error any Error) -> () {
bb0(%0: $@callee_guaranteed (@guaranteed @callee_guaranteed () -> ()) -> @error any Error):
%box = alloc_box ${ var Int }, var
%closure = function_ref @testPAUsedByTryApplyClosure : $@convention(thin) (@guaranteed { var Int }) -> ()
%pa = partial_apply [callee_guaranteed] %closure(%box) : $@convention(thin) (@guaranteed { var Int }) -> ()
try_apply %0(%pa) : $@callee_guaranteed (@guaranteed @callee_guaranteed () -> ()) -> @error any Error, normal bb2, error bb3
bb2(%result : $()):
br bb4
bb3(%error : $Error):
br bb4
bb4:
%v = tuple ()
return %v : $()
}
sil [ossa] @move_closure_callee : $@convention(thin) (@guaranteed { var Builtin.Int32 }) -> () {
bb0(%box : @closureCapture @guaranteed ${ var Builtin.Int32 }):
%13 = integer_literal $Builtin.Int32, 13
%addr = project_box %box : ${ var Builtin.Int32 }, 0
store %13 to [trivial] %addr : $*Builtin.Int32
%retval = tuple ()
return %retval : $()
}
// CHECK-LABEL: sil [ossa] @move_closure : {{.*}} {
// CHECK: [[SPECIALIZED_CLOSURE:%[^,]+]] = function_ref @$s19move_closure_calleeTf0s_n : $@convention(thin) (@inout_aliasable Builtin.Int32) -> ()
// CHECK: partial_apply [callee_guaranteed] [[SPECIALIZED_CLOSURE]]
// CHECK-LABEL: } // end sil function 'move_closure'
sil [ossa] @move_closure : $@convention(thin) () -> Builtin.Int32 {
bb0:
%box = alloc_box ${ var Builtin.Int32 }
%addr = project_box %box : ${ var Builtin.Int32 }, 0
%42 = integer_literal $Builtin.Int32, 42
store %42 to [trivial] %addr : $*Builtin.Int32
%callee = function_ref @move_closure_callee : $@convention(thin) (@guaranteed { var Builtin.Int32 }) -> ()
%box_copy = copy_value %box : ${ var Builtin.Int32 }
mark_function_escape %addr : $*Builtin.Int32
%closure = partial_apply [callee_guaranteed] %callee(%box_copy) : $@convention(thin) (@guaranteed { var Builtin.Int32 }) -> ()
%closure_move = move_value %closure : $@callee_guaranteed () -> ()
apply %closure_move() : $@callee_guaranteed () -> ()
destroy_value %closure_move : $@callee_guaranteed () -> ()
%value = load [trivial] %addr : $*Builtin.Int32
destroy_value %box : ${ var Builtin.Int32 }
return %value : $Builtin.Int32
}
sil @getC : $@convention(thin) () -> (@owned C)
// CHECK-LABEL: sil @leak_to_inf_loop_1 : {{.*}} {
// CHECK-NOT: destroy_addr
// CHECK-NOT: dealloc_stack
// CHECK-LABEL: } // end sil function 'leak_to_inf_loop_1'
sil @leak_to_inf_loop_1 : $@convention(thin) (@owned C) -> () {
entry(%c : $C):
%box = alloc_box ${ var C }
%c_addr = project_box %box, 0
store %c to %c_addr
strong_retain %box
strong_release %box
br loop
loop:
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
%c_old = load %c_addr
store %c2 to %c_addr
release_value %c_old
br loop
}
// CHECK-LABEL: sil @leak_to_inf_loop_2 : {{.*}} {
// CHECK: cond_br undef, [[EXIT:bb[0-9]+]], [[TO_LOOP:bb[0-9]+]]
// CHECK: [[EXIT]]
// CHECK: destroy_addr
// CHECK: dealloc_stack
// CHECK: [[TO_LOOP]]
// CHECK-NOT: destroy_addr
// CHECK-NOT: dealloc_stack
// CHECK-LABEL: } // end sil function 'leak_to_inf_loop_2'
sil @leak_to_inf_loop_2 : $@convention(thin) (@owned C) -> () {
entry(%c : $C):
%box = alloc_box ${ var C }
%c_addr = project_box %box, 0
store %c to %c_addr
strong_retain %box
strong_release %box
cond_br undef, exit, to_loop
exit:
strong_release %box
return undef : $()
to_loop:
strong_retain %box
strong_release %box
br loop
loop:
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
%c_old = load %c_addr
store %c2 to %c_addr
release_value %c_old
br loop
}
// CHECK-LABEL: sil @leak_to_inf_loop_3 : {{.*}} {
// CHECK-NOT: destroy_addr
// CHECK-NOT: dealloc_stack
// CHECK-LABEL: } // end sil function 'leak_to_inf_loop_3'
sil @leak_to_inf_loop_3 : $@convention(thin) (@owned C) -> () {
entry(%c : $C):
%box = alloc_box ${ var C }
%c_addr = project_box %box, 0
store %c to %c_addr
br to_loop
to_loop:
strong_retain %box
strong_release %box
br loop
loop:
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
%c_old = load %c_addr
store %c2 to %c_addr
release_value %c_old
br loop
}
// CHECK-LABEL: sil @dealloc_box_before_loop
// CHECK: dealloc_stack
// CHECK-LABEL: } // end sil function 'dealloc_box_before_loop'
sil @dealloc_box_before_loop : $@convention(thin) (@owned C) -> () {
entry(%c : $C):
%box = alloc_box ${ var C }
%c_addr = project_box %box, 0
store %c to %c_addr
cond_br undef, exit, to_loop
exit:
strong_release %box
return undef : $()
to_loop:
dealloc_box %box
br loop
loop:
br loop
}
// CHECK-LABEL: sil @alloc_box_in_deadend_loop
// CHECK: alloc_stack
// CHECK: dealloc_stack
// CHECK-LABEL: } // end sil function 'alloc_box_in_deadend_loop'
sil @alloc_box_in_deadend_loop : $@convention(thin) () -> () {
entry:
br loop
loop:
%box = alloc_box ${ var C }
%c_addr = project_box %box, 0
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
%c = apply %getC() : $@convention(thin) () -> (@owned C)
store %c to %c_addr
strong_release %box
br loop
}
// CHECK-LABEL: sil @alloc_box_in_exiting_loop
// CHECK: br [[EXITING_LOOP:bb[0-9]+]]
// CHECK: [[EXITING_LOOP]]:
// CHECK: alloc_stack
// CHECK: cond_br undef, [[EXIT:bb[0-9]+]], [[LATCH:bb[0-9]+]]
// CHECK: [[LATCH]]:
// CHECK: cond_br undef, [[BACKEDGE:bb[0-9]+]], [[INFINITE_LOOP:bb[0-9]+]]
// CHECK: [[BACKEDGE]]:
// CHECK: dealloc_stack
// CHECK: br [[EXITING_LOOP]]
// CHECK: [[EXIT]]:
// CHECK: dealloc_stack
// CHECK: [[INFINITE_LOOP]]:
// CHECK-NOT: dealloc_stack
// CHECK-LABEL: } // end sil function 'alloc_box_in_exiting_loop'
sil @alloc_box_in_exiting_loop : $@convention(thin) () -> () {
entry:
br exiting_loop
exiting_loop:
%box = alloc_box ${ var C }
%c_addr = project_box %box, 0
cond_br undef, exit, latch
latch:
cond_br undef, backedge, infinite_loop
backedge:
strong_release %box
br exiting_loop
exit:
strong_release %box
return undef : $()
infinite_loop:
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
%c = apply %getC() : $@convention(thin) () -> (@owned C)
store %c to %c_addr
strong_retain %box
strong_release %box
br infinite_loop
}
// CHECK-LABEL: sil @alloc_box_in_deadend_loop_with_another_deadend
// CHECK: br [[LOOP:bb[0-9]+]]
// CHECK: [[LOOP]]:
// CHECK: alloc_stack
// CHECK: cond_br undef, [[BACKEDGE:bb[0-9]+]], [[DIE:bb[0-9]+]]
// CHECK: [[BACKEDGE]]:
// CHECK: dealloc_stack
// CHECK: br [[LOOP]]
// CHECK: [[DIE]]:
// CHECK-NOT: dealloc_stack
// CHECK-LABEL: } // end sil function 'alloc_box_in_deadend_loop_with_another_deadend'
sil @alloc_box_in_deadend_loop_with_another_deadend : $@convention(thin) () -> () {
entry:
br loop
loop:
%box = alloc_box ${ var C }
cond_br undef, backedge, die
backedge:
strong_release %box
br loop
die:
strong_retain %box
strong_release %box
unreachable
}