mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Once we have promoted the box to stack, access violations can be detected statically by the DiagnoseStaticExclusivity pass (which runs after MandatoryAllocBoxToStack). Therefore we can convert dynamic accesses to static accesses. rdar://157458037
1454 lines
53 KiB
Plaintext
1454 lines
53 KiB
Plaintext
// RUN: %target-sil-opt -sil-print-types %s -allocbox-to-stack | %FileCheck %s --check-prefix=CHECK --check-prefix=OPT
|
|
// RUN: %target-sil-opt -sil-print-types %s -mandatory-allocbox-to-stack | %FileCheck %s --check-prefix=CHECK --check-prefix=MANDATORY
|
|
|
|
sil_stage raw
|
|
|
|
import Builtin
|
|
|
|
struct Int {
|
|
var _value: Builtin.Int64
|
|
}
|
|
|
|
struct Bool {
|
|
var _value: Builtin.Int1
|
|
}
|
|
|
|
protocol Error {}
|
|
|
|
class C {}
|
|
|
|
// 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] @escaping_pointer
|
|
sil [ossa] @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 [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
|
|
// OPT-LABEL: sil private [transparent] [ossa] @$s6struct8useStack1tySi_tFSiycfU_ :
|
|
// MANDATORY-NOT: sil private [transparent] [ossa] @$s6struct8useStack1tySi_tFSiycfU_ :
|
|
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
|
|
}
|
|
|
|
// OPT-LABEL: sil shared [ossa] @closure1 :
|
|
// MANDATORY-NOT: 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 [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
|
|
|
|
// OPT-LABEL: sil shared [ossa] @closure2 :
|
|
// MANDATORY-NOT: 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 {
|
|
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>
|
|
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: 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] @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 [read] [static] [[STK]] : $*T
|
|
// CHECK: copy_addr [[READ]] to [init] %1 : $*T
|
|
// CHECK: end_access [[READ]] : $*T
|
|
// CHECK: destroy_addr [[STK]]
|
|
// 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 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @alloc_box_in_specialized_callee :
|
|
// CHECK-NOT: alloc_box
|
|
// CHECK-LABEL: } // end sil function 'alloc_box_in_specialized_callee'
|
|
sil [ossa] @alloc_box_in_specialized_callee : $@convention(thin) (Int) -> () {
|
|
bb0(%0 : $Int):
|
|
%1 = alloc_box ${ var Int }
|
|
%2 = project_box %1, 0
|
|
store %0 to [trivial] %2
|
|
%4 = function_ref @callee_with_allocbox : $@convention(thin) (@guaranteed { var Int }) -> ()
|
|
%5 = apply %4(%1) : $@convention(thin) (@guaranteed { var Int }) -> ()
|
|
destroy_value %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
// CHECK-LABEL: sil shared [ossa] @$s20callee_with_allocboxTf0s_n :
|
|
// CHECK-NOT: alloc_box
|
|
// CHECK-LABEL: } // end sil function '$s20callee_with_allocboxTf0s_n'
|
|
|
|
// CHECK-LABEL: sil [ossa] @callee_with_allocbox :
|
|
// CHECK-NOT: alloc_box
|
|
// CHECK-LABEL: } // end sil function 'callee_with_allocbox'
|
|
sil [ossa] @callee_with_allocbox : $@convention(thin) (@guaranteed { var Int }) -> () {
|
|
bb0(%0 : @guaranteed ${ var Int }):
|
|
%1 = alloc_box ${ var Int }
|
|
%2 = project_box %1 : ${ var Int }, 0
|
|
%3 = project_box %0 : ${ var Int }, 0
|
|
copy_addr %3 to %2
|
|
destroy_value %1
|
|
%r = tuple ()
|
|
return %r
|
|
}
|
|
|
|
sil @getC : $@convention(thin) () -> (@owned C)
|
|
|
|
// CHECK-LABEL: sil [ossa] @leak_to_inf_loop_1 : {{.*}} {
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK-LABEL: } // end sil function 'leak_to_inf_loop_1'
|
|
sil [ossa] @leak_to_inf_loop_1 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
%box = alloc_box ${ var C }
|
|
%c_addr = project_box %box, 0
|
|
store %c to [init] %c_addr
|
|
%copy = copy_value %box
|
|
destroy_value %box
|
|
br loop
|
|
|
|
loop:
|
|
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
|
|
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
|
|
%c_old = load [take] %c_addr
|
|
store %c2 to [init] %c_addr
|
|
destroy_value %c_old
|
|
br loop
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @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 [ossa] @leak_to_inf_loop_2 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
%box = alloc_box ${ var C }
|
|
%c_addr = project_box %box, 0
|
|
store %c to [init] %c_addr
|
|
%copy = copy_value %box
|
|
destroy_value %box
|
|
cond_br undef, exit, to_loop
|
|
|
|
exit:
|
|
destroy_value %copy
|
|
return undef : $()
|
|
|
|
to_loop:
|
|
%copy2 = copy_value %copy
|
|
destroy_value %copy
|
|
br loop
|
|
|
|
loop:
|
|
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
|
|
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
|
|
%c_old = load [take] %c_addr
|
|
store %c2 to [init] %c_addr
|
|
destroy_value %c_old
|
|
br loop
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @leak_to_inf_loop_3 : {{.*}} {
|
|
// CHECK-NOT: destroy_addr
|
|
// CHECK-NOT: dealloc_stack
|
|
// CHECK-LABEL: } // end sil function 'leak_to_inf_loop_3'
|
|
sil [ossa] @leak_to_inf_loop_3 : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
%box = alloc_box ${ var C }
|
|
%c_addr = project_box %box, 0
|
|
store %c to [init] %c_addr
|
|
br to_loop
|
|
|
|
to_loop:
|
|
%copy = copy_value %box
|
|
destroy_value %box
|
|
br loop
|
|
|
|
loop:
|
|
%getC = function_ref @getC : $@convention(thin) () -> (@owned C)
|
|
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
|
|
%c_old = load [take] %c_addr
|
|
store %c2 to [init] %c_addr
|
|
destroy_value %c_old
|
|
br loop
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @dealloc_box_before_loop
|
|
// CHECK: dealloc_stack
|
|
// CHECK-LABEL: } // end sil function 'dealloc_box_before_loop'
|
|
sil [ossa] @dealloc_box_before_loop : $@convention(thin) (@owned C) -> () {
|
|
entry(%c : @owned $C):
|
|
%box = alloc_box ${ var C }
|
|
%c_addr = project_box %box, 0
|
|
store %c to [init] %c_addr
|
|
cond_br undef, exit, to_loop
|
|
|
|
exit:
|
|
destroy_value %box
|
|
return undef : $()
|
|
|
|
to_loop:
|
|
dealloc_box %box
|
|
br loop
|
|
|
|
loop:
|
|
br loop
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @alloc_box_in_deadend_loop
|
|
// CHECK: alloc_stack
|
|
// CHECK: dealloc_stack
|
|
// CHECK-LABEL: } // end sil function 'alloc_box_in_deadend_loop'
|
|
sil [ossa] @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 [init] %c_addr
|
|
destroy_value %box
|
|
br loop
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @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 [ossa] @alloc_box_in_exiting_loop : $@convention(thin) () -> () {
|
|
entry:
|
|
br exiting_loop
|
|
|
|
exiting_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 [init] %c_addr
|
|
cond_br undef, exit, latch
|
|
|
|
latch:
|
|
cond_br undef, backedge, to_infinite_loop
|
|
|
|
backedge:
|
|
destroy_value %box
|
|
br exiting_loop
|
|
|
|
exit:
|
|
destroy_value %box
|
|
return undef : $()
|
|
|
|
to_infinite_loop:
|
|
br infinite_loop
|
|
|
|
infinite_loop:
|
|
%c2 = apply %getC() : $@convention(thin) () -> (@owned C)
|
|
store %c2 to [assign] %c_addr
|
|
%copy = copy_value %box
|
|
destroy_value %copy
|
|
br infinite_loop
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @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 [ossa] @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:
|
|
destroy_value %box
|
|
br loop
|
|
|
|
die:
|
|
%copy = copy_value %box
|
|
destroy_value %copy
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_access_enforcement :
|
|
// OPT: begin_access [modify] [dynamic]
|
|
// MANDATORY: begin_access [modify] [static]
|
|
// CHECK-LABEL: } // end sil function 'test_access_enforcement'
|
|
sil [ossa] @test_access_enforcement : $(Int) -> Int {
|
|
bb0(%0 : $Int):
|
|
%1 = alloc_box ${ var Int }
|
|
%2 = project_box %1 : ${ var Int }, 0
|
|
%3 = begin_access [modify] [dynamic] %2
|
|
store %0 to [trivial] %3
|
|
end_access %3
|
|
%4 = load [trivial] %2
|
|
destroy_value %1
|
|
return %4 : $Int
|
|
}
|