Files
swift-mirror/test/SILOptimizer/allocbox_to_stack_ownership.sil
Joe Groff 3d5285be6f Arrange for closure bodies promoted by AllocBoxToStack to have their originals removed by MoveOnlyChecker.
This is an improvement of #67031 which avoids deleting the closure function
body during AllocBoxToStack, which still breaks pass invariants by modifying
functions other than the currently-analyzed function. As a function pass,
AllocBoxToStack also doesn't really know with certainty whether the original
closure function is unused after stack promotion or not. We still want to
eliminate the original when it may contain invalid SIL for move-only values
that rely on the escape analysis for correct semantics, so rather than mark the
original function to be *ignored* during move-only checking, mark it to be
*deleted* by move-only checking if the function is in fact unused at that
point.

If the marked function is still used, we let it pass through move-only
checking normally, which may cause redundant diagnostics but is the right
thing to do since code is still potentially using the closure with escaping
semantics. We should rearrange things to make this situation impossible in
the future.

rdar://110675352
2023-07-10 15:18:16 -07:00

1206 lines
46 KiB
Plaintext

// RUN: %target-sil-opt -enable-sil-verify-all %s -allocbox-to-stack -enable-copy-propagation=requested-passes-only -enable-lexical-borrow-scopes=false | %FileCheck %s
sil_stage raw
import Builtin
struct Int {
var _value: Builtin.Int64
}
struct Bool {
var _value: Builtin.Int1
}
protocol Error {}
// CHECK-LABEL: sil [ossa] @simple_promotion
sil [ossa] @simple_promotion : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %1a : $*Int
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
return %3 : $Int
// CHECK: alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: destroy_value
// CHECK: return
}
// CHECK-LABEL: sil [ossa] @double_project_box
sil [ossa] @double_project_box : $@convention(thin) (Int) -> (Int, Int) {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %1a : $*Int
%3 = load [trivial] %1a : $*Int
%1b = project_box %1 : ${ var Int }, 0
%3b = load [trivial] %1b : $*Int
destroy_value %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: destroy_value
// CHECK: return
}
// CHECK-LABEL: sil [ossa] @init_var
sil [ossa] @init_var : $@convention(thin) (Int) -> Int {
bb0(%0 : $Int):
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %1a : $*Int
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
return %3 : $Int
// CHECK: %1 = alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: destroy_value
// CHECK-NOT: destroy_addr
// CHECK: dealloc_stack %1 : $*Int
// CHECK: return
}
// CHECK-LABEL: sil [ossa] @multi_destroy_value
sil [ossa] @multi_destroy_value : $@convention(thin) () -> Int {
bb0:
%1 = alloc_box ${ var Int }
%1a = mark_uninitialized [rootself] %1 : ${ var Int }
%2 = project_box %1a : ${ var Int }, 0
%3 = load [trivial] %2 : $*Int
%x = copy_value %1a : ${ var Int }
destroy_value %1a : ${ var Int }
br bb1
bb1:
destroy_value %x : ${ 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 [ossa] @struct_tuple_element_addr
sil [ossa] @struct_tuple_element_addr : $@convention(thin) (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 [trivial] %2 : $*Int
%b = tuple_element_addr %aa : $*(Int, Int), 0
store %0 to [trivial] %b : $*Int
%6 = struct_element_addr %1a : $*TestStruct, #TestStruct.Elt
%7 = load [trivial] %6 : $*Int
destroy_value %a : ${ var (Int, Int) }
destroy_value %1 : ${ var TestStruct }
return %7 : $Int
// CHECK-DAG: dealloc_stack [[STRUCT]]
// CHECK-DAG: dealloc_stack [[TUPLE]]
// CHECK: return
}
sil [ossa] @callee : $@convention(thin) (@inout Int) -> ()
// CHECK-LABEL: sil [ossa] @inout_nocapture
sil [ossa] @inout_nocapture : $@convention(thin) () -> Int {
bb0:
// CHECK: alloc_stack
%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 [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
%10 = address_to_pointer %1a : $*Int to $Builtin.RawPointer
%11 = pointer_to_address %10 : $Builtin.RawPointer to [strict] $*Int
%12 = load [trivial] %11 : $*Int
return %8 : $Int
// CHECK: return
}
protocol P {
}
sil [ossa] @returns_protocol : $@convention(thin) () -> @out P
// CHECK-LABEL: sil [ossa] @test_indirect_return
sil [ossa] @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
destroy_value %2 : ${ var P }
%0 = tuple ()
return %0 : $()
// CHECK: return
}
class SomeClass {}
// CHECK-LABEL: sil [ossa] @class_promotion
sil [ossa] @class_promotion : $@convention(thin) (@owned SomeClass) -> @owned SomeClass {
bb0(%0 : @owned $SomeClass):
%1 = alloc_box ${ var SomeClass }
%1a = project_box %1 : ${ var SomeClass }, 0
store %0 to [init] %1a : $*SomeClass
%3 = load [copy] %1a : $*SomeClass
destroy_value %1 : ${ var SomeClass }
return %3 : $SomeClass
// CHECK: %1 = alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: destroy_value
// CHECK: destroy_addr {{.*}} : $*SomeClass
// CHECK: return
}
protocol LogicValue {
func getLogicValue() -> Bool
}
// CHECK-LABEL: @protocols
sil [ossa] @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
destroy_value %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 [ossa] @dealloc_box_test
sil [ossa] @dealloc_box_test : $@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 [ossa] @$s1t9SomeUnionO1yfMS0_FCS_9SomeClassS0_ : $@convention(thin) (@owned SomeClass, @thin SomeUnion.Type) -> @owned SomeUnion
sil [ossa] @$s1t9SomeClassCCfMS0_FT_S0_ : $@convention(thin) (@thick SomeClass.Type) -> @owned SomeClass
// CHECK-LABEL: sil [ossa] @union_test
sil [ossa] @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 [init] %1a : $*SomeUnion
destroy_value %1 : ${ var SomeUnion }
%10 = tuple ()
return %10 : $()
// CHECK: dealloc_stack [[UNION]]
// CHECK: [[T0:%.*]] = tuple ()
// CHECK-NEXT: return [[T0]] : $()
}
// CHECK-LABEL: sil [ossa] @multiple_destroy_test
sil [ossa] @multiple_destroy_test : $@convention(thin) (Bool) -> Bool {
bb0(%0 : $Bool):
%1 = alloc_box ${ var Bool }
%1a = project_box %1 : ${ var Bool }, 0
store %0 to [trivial] %1a : $*Bool
%2 = copy_value %1 : ${ var Bool }
%3 = copy_value %1 : ${ var Bool }
%5 = tuple ()
%6 = load [trivial] %1a : $*Bool
destroy_value %3 : ${ var Bool }
destroy_value %2 : ${ var Bool }
destroy_value %1 : ${ var Bool }
return %6 : $Bool
// CHECK: alloc_stack $Bool
// CHECK-NEXT: store
// 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 [ossa] @box_reachable_from_destroy_test
sil [ossa] @box_reachable_from_destroy_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:
destroy_value %1 : ${ var Bool }
br bb1
// CHECK: bb3:
// CHECK-NEXT: dealloc_stack
bb3:
destroy_value %1 : ${ var Bool }
%2 = tuple ()
// CHECK: return
return %2 : $()
}
sil [ossa] @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
// destroy_values 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 [ossa] @test_mui
sil [ossa] @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 [copy] %3 : $*SomeClass
%14 = apply %11(%12) : $@convention(thin) (@owned SomeClass) -> ()
destroy_value %2a : ${ var SomeClass }
// CHECK: destroy_addr [[MUI]]
// CHECK-NEXT: dealloc_stack [[STACK]]
br bb2
// CHECK: bb2
bb2:
%17 = tuple ()
// CHECK: return
return %17 : $()
bb3:
destroy_value %2a : ${ var SomeClass }
// CHECK: destroy_addr [[MUI]]
// CHECK-NEXT: dealloc_stack [[STACK]]
br bb2
}
// CHECK-LABEL: sil [ossa] @$s6struct5apply1fS2iyc_tF
// struct.apply (f : () -> Swift.Int) -> Swift.Int
sil [ossa] @$s6struct5apply1fS2iyc_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> Int {
bb0(%0 : @owned $@callee_owned () -> Int):
debug_value %0 : $@callee_owned () -> Int, let, name "f" // id: %1
%1 = copy_value %0 : $@callee_owned () -> Int // id: %2
%3 = apply %1() : $@callee_owned () -> Int // user: %5
destroy_value %0 : $@callee_owned () -> Int // id: %4
return %3 : $Int // id: %5
}
// CHECK-LABEL: sil [ossa] @$s6struct6escape1fSiycSiyc_tF
// struct.escape (f : () -> Swift.Int) -> () -> Swift.Int
sil [ossa] @$s6struct6escape1fSiycSiyc_tF : $@convention(thin) (@owned @callee_owned () -> Int) -> @owned @callee_owned () -> Int {
bb0(%0 : @owned $@callee_owned () -> Int):
debug_value %0 : $@callee_owned () -> Int, let, name "f" // id: %1
return %0 : $@callee_owned () -> Int // id: %2
}
// CHECK-LABEL: sil [ossa] @$s6struct8useStack1tySi_tF
// struct.useStack (t : Swift.Int) -> ()
sil [ossa] @$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 [trivial] %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
%6 = copy_value %2 : $<τ_0_0> { var τ_0_0 } <Int> // id: %6
// CHECK: [[PA:%[a-zA-Z0-9]+]] = partial_apply [[FUNC]]
%7 = partial_apply %5(%6) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int // user: %8
%8 = apply %4(%7) : $@convention(thin) (@owned @callee_owned () -> Int) -> Int
destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int>
%10 = tuple () // user: %11
return %10 : $() // id: %11
}
// CHECK-LABEL: sil private [transparent] [ossa] @$s6struct8useStack1tySi_tFSiycfU_Tf0s_n
// CHECK-LABEL: sil private [transparent] [_semantics "sil.optimizer.moveonly.delete_if_unused"] [ossa] @$s6struct8useStack1tySi_tFSiycfU_
// struct.(useStack (t : Swift.Int) -> ()).(closure #1)
sil private [transparent] [ossa] @$s6struct8useStack1tySi_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
bb0(%0 : @owned $<τ_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 [trivial] %3 : $*Int // user: %8
dealloc_stack %3 : $*Int // id: %6
destroy_value %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 [ossa] @$s6struct6useBox1tySi_tF
// struct.useBox (t : Swift.Int) -> ()
sil [ossa] @$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 [trivial] %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
%6 = copy_value %2 : $<τ_0_0> { var τ_0_0 } <Int> // id: %6
%7 = partial_apply %5(%6) : $@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
destroy_value %2 : $<τ_0_0> { var τ_0_0 } <Int> // id: %10
%11 = tuple () // user: %12
return %11 : $() // id: %12
}
// CHECK-LABEL: sil private [ossa] @$s6struct6useBox1tySi_tFSiycfU_
// struct.(useBox (t : Swift.Int) -> ()).(closure #1)
sil private [ossa] @$s6struct6useBox1tySi_tFSiycfU_ : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> Int {
bb0(%0 : @owned $<τ_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 [trivial] %3 : $*Int // user: %8
dealloc_stack %3 : $*Int // id: %6
destroy_value %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 [ossa] @no_final_destroy
sil [ossa] @no_final_destroy : $@convention(thin) (Int) -> Bool {
bb0(%0 : $Int):
// This is not destroyed, but the unreachable makes the verifier not trip.
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Int>, 0
store %0 to [trivial] %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>) -> ()
%4 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Int>
%5 = partial_apply %3(%4) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
%6 = copy_value %5 : $@callee_owned () -> ()
apply %6() : $@callee_owned () -> ()
destroy_value %5 : $@callee_owned () -> ()
unreachable
}
// CHECK-LABEL: sil [ossa] @test_copy_and_borrow_of_closure
// CHECK-NOT: alloc_box
// CHECK: alloc_stack
// CHECK-NOT: alloc_box
// CHECK: } // end sil function 'test_copy_and_borrow_of_closure'
sil [ossa] @test_copy_and_borrow_of_closure : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
// This is not destroyed, but the unreachable makes the verifier not trip.
%1 = alloc_box $<τ_0_0> { var τ_0_0 } <Int>
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Int>, 0
store %0 to [trivial] %1a : $*Int
%3 = function_ref @closure3 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
%4 = copy_value %1 : $<τ_0_0> { var τ_0_0 } <Int>
%5 = partial_apply %3(%4) : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> ()
%6 = begin_borrow %5 : $@callee_owned () -> ()
%7 = copy_value %6 : $@callee_owned () -> ()
apply %7() : $@callee_owned () -> ()
end_borrow %6 : $@callee_owned () -> ()
destroy_value %5 : $@callee_owned () -> ()
destroy_value %1 : $<τ_0_0> { var τ_0_0 } <Int>
%r = tuple ()
return %r : $()
}
sil [ossa] @closure3 : $@convention(thin) (@owned <τ_0_0> { var τ_0_0 } <Int>) -> () {
bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Int>):
%1 = project_box %0 : $<τ_0_0> { var τ_0_0 } <Int>, 0
destroy_value %0 : $<τ_0_0> { var τ_0_0 } <Int> // id: %7
%r = tuple ()
return %r : $()
}
sil [ossa] @closureWithBoxArg : $@convention(thin) (@guaranteed { var SomeClass }) -> () {
bb0(%0 : @guaranteed ${ var SomeClass }):
%r = tuple ()
return %r : $()
}
sil [ossa] @useClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> () {
bb0(%0 : @guaranteed $@callee_guaranteed () -> ()):
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @finalReleaseWithBorrow
// CHECK: [[S:%[0-9]+]] = alloc_stack {{.*}}$SomeClass
// CHECK-NOT: destroy_addr
// CHECK: [[F:%[0-9]+]] = function_ref @useClosure
// CHECK: apply [[F]]
// CHECK: destroy_addr [[S]]
// CHECK: } // end sil function 'finalReleaseWithBorrow'
sil [ossa] @finalReleaseWithBorrow : $@convention(thin) (@owned SomeClass) -> () {
bb0(%0 : @owned $SomeClass):
%1 = alloc_box $ { var SomeClass }
%2 = begin_borrow %1 : ${ var SomeClass }
%1a = project_box %2 : ${ var SomeClass }, 0
store %0 to [init] %1a : $*SomeClass
%3 = function_ref @closureWithBoxArg : $@convention(thin) (@guaranteed { var SomeClass }) -> ()
%4 = copy_value %2 : ${ var SomeClass }
%5 = partial_apply [callee_guaranteed] %3(%4) : $@convention(thin) (@guaranteed { var SomeClass }) -> ()
end_borrow %2 : ${ var SomeClass }
destroy_value %1 : ${ var SomeClass }
%6 = function_ref @useClosure : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
apply %6(%5) : $@convention(thin) (@guaranteed @callee_guaranteed () -> ()) -> ()
destroy_value %5 : $@callee_guaranteed () -> ()
%10 = tuple ()
return %10 : $()
}
// CHECK-LABEL: sil [transparent] [serialized] [ossa] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> ()
sil [transparent] [serialized] [ossa] @mightApply : $@convention(thin) <U where U : P> (@owned @callee_owned () -> @out U) -> () {
// CHECK: bb0
bb0(%0 : @owned $@callee_owned () -> @out U):
debug_value %0 : $@callee_owned () -> @out U
%1 = copy_value %0 : $@callee_owned () -> @out U
%3 = alloc_stack $U
%4 = apply %1(%3) : $@callee_owned () -> @out U
destroy_addr %3 : $*U
dealloc_stack %3 : $*U
destroy_value %0 : $@callee_owned () -> @out U
%8 = tuple ()
// CHECK: return
return %8 : $()
}
sil [transparent] [serialized] [ossa] @mightApplyGuaranteed : $@convention(thin) <U where U : P> (@guaranteed @callee_guaranteed () -> @out U) -> () {
// CHECK: bb0
bb0(%0 : @guaranteed $@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 ()
// CHECK: return
return %8 : $()
}
// CHECK-LABEL: sil [ossa] @callWithAutoclosure
sil [ossa] @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 [ossa] @callWithAutoclosure_2 : $@convention(thin) <T where T : P> (@in T) -> () {
sil [ossa] @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
%4copy = copy_value %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>(%4copy) : $@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
destroy_value %4 : $<τ_0_0> { var τ_0_0 } <T>
%9 = tuple ()
// CHECK: return
return %9 : $()
}
// CHECK: } // end sil function 'callWithAutoclosure_2'
// CHECK-LABEL: sil [ossa] @callWithAutoclosure_3 : $@convention(thin) <T where T : P> (@in T) -> () {
sil [ossa] @callWithAutoclosure_3 : $@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_UNMARKED:%[0-9a-zA-Z_]+]] = alloc_stack $T
// CHECK: [[STACK:%.*]] = mark_uninitialized [var] [[STACK_UNMARKED]]
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>
%4c = mark_uninitialized [var] %4 : $<τ_0_0> { var τ_0_0 } <T>
%4a = project_box %4c : $<τ_0_0> { var τ_0_0 } <T>, 0
%4copy = copy_value %4c : $<τ_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>(%4copy) : $@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_UNMARKED]] : $*T
destroy_addr %0 : $*T
destroy_value %4c : $<τ_0_0> { var τ_0_0 } <T>
%9 = tuple ()
// CHECK: return
return %9 : $()
}
// CHECK: } // end sil function 'callWithAutoclosure_3'
// CHECK-LABEL: sil shared [ossa] @$s21closure_to_specializeTf0ns_n : $@convention(thin) <T where T : P> (@inout_aliasable T) -> @out T
sil shared [ossa] @closure_to_specialize : $@convention(thin) <T where T : P> (@owned <τ_0_0> { var τ_0_0 } <T>) -> @out T {
// CHECK: bb0
bb0(%0 : $*T, %1 : @owned $<τ_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: destroy_value
destroy_value %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] [ossa] @inner
sil [noinline] [ossa] @inner : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool {
// CHECK: bb0
bb0(%0 : @owned $@callee_owned () -> Bool):
debug_value %0 : $@callee_owned () -> Bool
%1 = copy_value %0 : $@callee_owned () -> Bool
%3 = apply %1() : $@callee_owned () -> Bool
destroy_value %0 : $@callee_owned () -> Bool
// CHECK: return
return %3 : $Bool
}
// CHECK-LABEL: sil [noinline] [ossa] @outer
sil [noinline] [ossa] @outer : $@convention(thin) (@owned @callee_owned () -> Bool) -> Bool {
// CHECK: bb0
bb0(%0 : @owned $@callee_owned () -> Bool):
debug_value %0 : $@callee_owned () -> Bool
%1 = copy_value %0 : $@callee_owned () -> Bool
%3 = apply %1() : $@callee_owned () -> Bool
destroy_value %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 [ossa] @specialized
sil shared [ossa] @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 [ossa] @unspecialized
sil [ossa] @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 [_semantics "sil.optimizer.moveonly.delete_if_unused"] [ossa] @closure1
sil shared [ossa] @closure1 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
// CHECK: bb0
bb0(%0 : $Int, %1 : @owned $<τ_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
destroy_value %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
// CHECK: return
return %8 : $Bool
}
// CHECK-LABEL: sil shared [ossa] @$s8closure2Tf0ns_n
// CHECK: bb0
// CHECK: return
// CHECK-NOT: bb1
// CHECK-LABEL: sil shared [_semantics "sil.optimizer.moveonly.delete_if_unused"] [ossa] @closure2
sil shared [ossa] @closure2 : $@convention(thin) <T where T : Count> (Int, @owned <τ_0_0 : Count> { var S<τ_0_0> } <T>) -> Bool {
// CHECK: bb0
bb0(%0 : $Int, %1 : @owned $<τ_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
%9 = copy_value %1 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
%10 = project_box %9 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>, 0
copy_addr %10 to [init] %4 : $*S<T>
destroy_value %9 : $<τ_0_0 where τ_0_0 : Count> { var S<τ_0_0> } <T>
destroy_addr %4 : $*S<T>
dealloc_stack %4 : $*S<T>
destroy_value %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 [ossa] @destroy_stack_value_after_closure
sil [ossa] @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: [[COPIED_PARTIAL:%.*]] = copy_value [[PARTIAL]]
%7 = copy_value %6 : $@callee_owned () -> ()
// CHECK: apply [[COPIED_PARTIAL]]() : $@callee_owned () -> ()
%9 = apply %7() : $@callee_owned () -> ()
copy_addr %1 to [init] %0 : $*T
// CHECK: destroy_value [[PARTIAL]]
destroy_value %6 : $@callee_owned () -> ()
// CHECK: destroy_addr [[STACK]]
// CHECK: destroy_addr %1
destroy_addr %1 : $*T
%13 = tuple ()
return %13 : $()
}
sil [ossa] @applied : $@convention(thin) <T> (@owned <τ_0_0> { var τ_0_0 } <T>) -> () {
bb0(%0 : @owned $<τ_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
destroy_value %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 [ossa] @throwing_unwrap : $@convention(thin) (Int) -> (Int, @error any Error)
sil [ossa] @fake_throwing_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error any Error)
sil hidden [ossa] @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 : @owned $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 [init] %4 : $*ThrowDerivedClass
%8 = load [take] %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 : @owned $ThrowDerivedClass): // Preds: bb1
store %14 to [init] %4 : $*ThrowDerivedClass
%16 = load [copy] %4 : $*ThrowDerivedClass
destroy_value %3 : ${ var ThrowDerivedClass }
return %16 : $ThrowDerivedClass
// %20 // user: %22
bb3(%20 : @owned $Error): // Preds: bb0
destroy_value %8 : $ThrowDerivedClass
br bb5(%20 : $Error)
// %23 // user: %24
bb4(%23 : @owned $Error): // Preds: bb1
br bb5(%23 : $Error)
// %25 // user: %27
bb5(%25 : @owned $Error): // Preds: bb4 bb3
destroy_value %3 : ${ var ThrowDerivedClass }
throw %25 : $Error
}
// CHECK-LABEL: sil [ossa] @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
// CHECK: [[STACK2:%[0-9]+]] = alloc_stack $Bool
// CHECK-NEXT: dealloc_stack [[STACK2]]
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack [[STACK1]]
// CHECK: bb3:
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @deal_with_wrong_nesting : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%as1 = alloc_stack $Bool
%1 = alloc_box ${ var Int }
cond_br undef, bb1, bb2
bb1:
destroy_value %1 : ${ var Int }
dealloc_stack %as1 : $*Bool
br bb3
bb2:
%1a = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %1a : $*Int
dealloc_stack %as1 : $*Bool
%3 = load [trivial] %1a : $*Int
%as2 = alloc_stack $Bool
destroy_value %1 : ${ var Int }
dealloc_stack %as2 : $*Bool
br bb3
bb3:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @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
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack_ref [[REF]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @wrong_nesting_with_alloc_ref : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%as1 = alloc_ref [stack] $SomeClass
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
store %0 to [trivial] %1a : $*Int
dealloc_ref %as1 : $SomeClass
dealloc_stack_ref %as1 : $SomeClass
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @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
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack [[STACK1]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @nesting_and_unreachable1 : $@convention(thin) (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 [trivial] %1a : $*Int
dealloc_stack %as1 : $*Bool
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @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: dealloc_stack [[BOX]]
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK: store
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: dealloc_stack [[STACK1]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @nesting_and_unreachable2 : $@convention(thin) (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
destroy_value %1 : ${ var Int }
dealloc_stack %as2 : $*Bool
unreachable
bb2:
store %0 to [trivial] %1a : $*Int
dealloc_stack %as1 : $*Bool
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @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
// CHECK: dealloc_stack [[STACK]]
// CHECK-NEXT: dealloc_stack [[BOX]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @nesting_and_unreachable3 : $@convention(thin) (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:
destroy_value %1 : ${ var Int }
unreachable
bb2:
store %0 to [trivial] %1a : $*Int
%3 = load [trivial] %1a : $*Int
dealloc_stack %as1 : $*Bool
destroy_value %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @nesting_and_unreachable4
// CHECK: bb0(%0 : $Int):
// CHECK-NEXT: [[BOX:%[0-9]+]] = alloc_stack $Int
// CHECK: bb1:
// CHECK-NEXT: unreachable
// CHECK: bb2:
// CHECK: store
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @nesting_and_unreachable4 : $@convention(thin) (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 [trivial] %1a : $*Int
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: sil [ossa] @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
// CHECK: dealloc_stack [[BOX]]
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil [ossa] @nesting_and_unreachable5 : $@convention(thin) (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 [trivial] %1a : $*Int
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
%r = tuple ()
return %r : $()
}
// Test that
// begin_access [read], copy_addr, end_access, destroy_addr
// is folded into
// begin_access [deinit], copy_addr [take], end_access
//
// CHECK-LABEL: sil [ossa] @deinit_access : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T):
// CHECK: [[STK:%.*]] = alloc_stack $T, var, name "x"
// CHECK: copy_addr %2 to [init] [[STK]] : $*T
// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*T
// CHECK: copy_addr [[READ]] to [init] %0 : $*T
// CHECK: end_access [[READ]] : $*T
// CHECK: [[READ:%.*]] = begin_access [deinit] [static] [[STK]] : $*T
// CHECK: copy_addr [take] [[READ]] to [init] %1 : $*T
// CHECK: end_access [[READ]] : $*T
// CHECK-NOT: destroy_addr
// CHECK: dealloc_stack [[STK]] : $*T
// CHECK: destroy_addr %2 : $*T
// CHECK: return %{{.*}} : $()
// CHECK-LABEL: } // end sil function 'deinit_access'
sil [ossa] @deinit_access : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
bb0(%0 : $*T, %1 : $*T, %2 : $*T):
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>, var, name "x"
%5 = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
copy_addr %2 to [init] %5 : $*T
%7 = begin_access [read] [static] %5 : $*T
copy_addr %7 to [init] %0 : $*T
end_access %7 : $*T
%10 = begin_access [read] [static] %5 : $*T
copy_addr %10 to [init] %1 : $*T
end_access %10 : $*T
destroy_value %4 : $<τ_0_0> { var τ_0_0 } <T>
destroy_addr %2 : $*T
%15 = tuple ()
return %15 : $()
}
// Test that
// begin_access [read], <other access>, copy_addr, end_access, destroy_addr
// is *not* folded into
// begin_access [deinit], copy_addr [take], end_access
//
// CHECK-LABEL: sil [ossa] @nodeinit_access : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
// CHECK: bb0(%0 : $*T, %1 : $*T, %2 : $*T):
// CHECK: [[STK:%.*]] = alloc_stack $T, var, name "x"
// CHECK: copy_addr %2 to [init] [[STK]] : $*T
// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*T
// CHECK: copy_addr [[READ]] to [init] %0 : $*T
// CHECK: end_access [[READ]] : $*T
// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*T
// CHECK: [[INNER:%.*]] = begin_access [read] [static] [[READ]] : $*T
// CHECK: end_access [[INNER]] : $*T
// CHECK: copy_addr [[READ]] to [init] %1 : $*T
// CHECK: end_access [[READ]] : $*T
// CHECK: destroy_addr [[STK]] : $*T
// CHECK: dealloc_stack [[STK]] : $*T
// CHECK: destroy_addr %2 : $*T
// CHECK: return %{{.*}} : $()
// CHECK-LABEL: } // end sil function 'nodeinit_access'
sil [ossa] @nodeinit_access : $@convention(thin) <T> (@in T) -> (@out T, @out T) {
bb0(%0 : $*T, %1 : $*T, %2 : $*T):
%4 = alloc_box $<τ_0_0> { var τ_0_0 } <T>, var, name "x"
%5 = project_box %4 : $<τ_0_0> { var τ_0_0 } <T>, 0
copy_addr %2 to [init] %5 : $*T
%7 = begin_access [read] [static] %5 : $*T
copy_addr %7 to [init] %0 : $*T
end_access %7 : $*T
%10 = begin_access [read] [static] %5 : $*T
%innerAccess = begin_access [read] [static] %10 : $*T
end_access %innerAccess : $*T
copy_addr %10 to [init] %1 : $*T
end_access %10 : $*T
destroy_value %4 : $<τ_0_0> { var τ_0_0 } <T>
destroy_addr %2 : $*T
%15 = tuple ()
return %15 : $()
}