Files
swift-mirror/test/SILOptimizer/allocbox_to_stack_ownership.sil
Michael Gottesman f854547c55 [ownership] Enable ownership verification by default.
I also removed the -verify-sil-ownership flag in favor of a disable flag
-disable-sil-ownership-verifier. I used this on only two tests that still need
work to get them to pass with ownership, but whose problems are well understood,
small corner cases. I am going to fix them in follow on commits. I detail them
below:

1. SILOptimizer/definite_init_inout_super_init.swift. This is a test case where
DI is supposed to error. The only problem is that we crash before we error since
the code emitting by SILGen to trigger this error does not pass ownership
invariants. I have spoken with JoeG about this and he suggested that I fix this
earlier in the compiler. Since we do not run the ownership verifier without
asserts enabled, this should not affect compiler users. Given that it has
triggered DI errors previously I think it is safe to disable ownership here.

2. PrintAsObjC/extensions.swift. In this case, the signature generated by type
lowering for one of the thunks here uses an unsafe +0 return value instead of
doing an autorelease return. The ownership checker rightly flags this leak. This
is going to require either an AST level change or a change to TypeLowering. I
think it is safe to turn this off since it is such a corner case that it was
found by a test that has nothing to do with it.

rdar://43398898
2019-03-25 00:11:52 -07:00

1096 lines
40 KiB
Plaintext

// RUN: %target-sil-opt -enable-sil-verify-all %s -allocbox-to-stack | %FileCheck %s
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 {
bb0:
%1 = alloc_box ${ var Int }
%1a = project_box %1 : ${ var Int }, 0
%3 = load [trivial] %1a : $*Int
destroy_value %1 : ${ var Int }
return %3 : $Int
// CHECK: %0 = alloc_stack
// CHECK-NOT: alloc_box
// CHECK-NOT: destroy_value
// CHECK-NOT: destroy_addr
// CHECK: dealloc_stack %0 : $*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 [take] %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 $LogicValue
copy_addr [take] %0 to [initialization] %2a : $*LogicValue
%6 = open_existential_addr mutable_access %2a : $*LogicValue to $*@opened("01234567-89ab-cdef-0123-000000000000") LogicValue
%7 = witness_method $@opened("01234567-89ab-cdef-0123-000000000000") LogicValue, #LogicValue.getLogicValue!1, %6 : $*@opened("01234567-89ab-cdef-0123-000000000000") LogicValue : $@convention(witness_method: LogicValue) <T: LogicValue> (@in_guaranteed T) -> Bool
%8 = apply %7<@opened("01234567-89ab-cdef-0123-000000000000") LogicValue>(%6) : $@convention(witness_method: LogicValue) <T: LogicValue> (@in_guaranteed T) -> Bool
destroy_value %2 : ${ var LogicValue }
// CHECK: destroy_addr %2 : $*LogicValue
// CHECK-NEXT: dealloc_stack %2 : $*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 shared [ossa] @$s6struct8useStack1tySi_tFSiycfU_Tf0s_n
// CHECK-LABEL: sil private [ossa] @$s6struct8useStack1tySi_tFSiycfU_
// struct.(useStack (t : Swift.Int) -> ()).(closure #1)
sil private [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 [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 : $()
}
// CHECK-LABEL: sil [ossa] @callWithAutoclosure
sil [ossa] @callWithAutoclosure : $@convention(thin) <T where T : P> (@in T) -> () {
// CHECK: bb0
bb0(%0 : $*T):
// CHECK: debug_value_addr
debug_value_addr %0 : $*T
// 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 [initialization] [[STACK]] : $*T
copy_addr %0 to [initialization] %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 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 [initialization] %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_addr %1 : $*S<Q>
%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 [initialization] %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_addr %1 : $*S<T>
%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 [initialization] %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 [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 [initialization] %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 [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 [initialization] %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>
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 [initialization] [[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 [initialization] %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 [initialization] %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 [initialization] %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_addr %0 : $*T
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 Error)
sil [ossa] @fake_throwing_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error Error)
sil hidden [ossa] @try_apply_during_chaining_init : $@convention(method) (Int, @owned ThrowDerivedClass) -> (@owned ThrowDerivedClass, @error 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 Error)
%10 = function_ref @throwing_unwrap : $@convention(thin) (Int) -> (Int, @error Error)
try_apply %10(%0) : $@convention(thin) (Int) -> (Int, @error 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 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_ref [stack] [[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 [stack] %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 : $()
}
// CHECK-LABEL: sil [ossa] @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
// 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 [ossa] @nesting_and_unreachable_critical_edge : $@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, bb3
bb1:
%as2 = alloc_stack $Bool
cond_br undef, bb2, bb3
bb2:
store %0 to [trivial] %1a : $*Int
%3 = load [trivial] %1a : $*Int
dealloc_stack %as2 : $*Bool
dealloc_stack %as1 : $*Bool
destroy_value %1 : ${ var Int }
%r = tuple ()
return %r : $()
bb3:
destroy_value %1 : ${ var Int }
unreachable
}
// 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 [initialization] [[STK]] : $*T
// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*T
// CHECK: copy_addr [[READ]] to [initialization] %0 : $*T
// CHECK: end_access [[READ]] : $*T
// CHECK: [[READ:%.*]] = begin_access [deinit] [static] [[STK]] : $*T
// CHECK: copy_addr [take] [[READ]] to [initialization] %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 : @owned $*T, %1 : @owned $*T, %2 : @owned $*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 [initialization] %5 : $*T
%7 = begin_access [read] [static] %5 : $*T
copy_addr %7 to [initialization] %0 : $*T
end_access %7 : $*T
%10 = begin_access [read] [static] %5 : $*T
copy_addr %10 to [initialization] %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 [initialization] [[STK]] : $*T
// CHECK: [[READ:%.*]] = begin_access [read] [static] [[STK]] : $*T
// CHECK: copy_addr [[READ]] to [initialization] %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 [initialization] %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 : @owned $*T, %1 : @owned $*T, %2 : @owned $*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 [initialization] %5 : $*T
%7 = begin_access [read] [static] %5 : $*T
copy_addr %7 to [initialization] %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 [initialization] %1 : $*T
end_access %10 : $*T
destroy_value %4 : $<τ_0_0> { var τ_0_0 } <T>
destroy_addr %2 : $*T
%15 = tuple ()
return %15 : $()
}