mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
After computing side effects, we also remove any global or argument effects that are computed to happen, but are defined not to, based on the effect attribute. This allows us to compute the deinit_barrier effect for such functions, fixing the test case here: rdar://155870190 This supercedes #38324.
1400 lines
45 KiB
Plaintext
1400 lines
45 KiB
Plaintext
// RUN: %target-sil-opt %s -parse-serialized-sil -module-name test -compute-side-effects | %FileCheck %s
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
//////////////////
|
|
// Declarations //
|
|
//////////////////
|
|
|
|
enum Never {}
|
|
|
|
final class X {
|
|
@_hasStorage var a: Int32
|
|
@_hasStorage var x: X
|
|
|
|
init()
|
|
deinit
|
|
}
|
|
|
|
class Y {
|
|
}
|
|
|
|
final class Z {
|
|
@_hasStorage var a: Int32
|
|
|
|
init()
|
|
deinit
|
|
}
|
|
|
|
struct SP {
|
|
var value: X
|
|
}
|
|
|
|
struct TwoSPs {
|
|
var sp1: SP
|
|
var sp2: SP
|
|
}
|
|
|
|
enum EP {
|
|
case none
|
|
case data(SP, Builtin.Int1)
|
|
}
|
|
|
|
class List {
|
|
var x: Int32
|
|
let next: List
|
|
}
|
|
|
|
struct S {
|
|
var l: List
|
|
var y: Int32
|
|
}
|
|
|
|
struct Ptr {
|
|
var p: Int32
|
|
}
|
|
|
|
enum SomeErr : Error {
|
|
case err
|
|
}
|
|
|
|
sil_global public @global_var : $Int32
|
|
|
|
sil [_semantics "programtermination_point"] @exitfunc : $@convention(thin) () -> Never
|
|
sil [readnone] @pure_func : $@convention(thin) () -> ()
|
|
sil [readnone] @readnone_owned : $@convention(thin) (@owned X) -> @owned X
|
|
sil [releasenone] @releasenone_func : $@convention(thin) () -> ()
|
|
sil [readonly] @readonly_owned : $@convention(thin) (@owned X) -> ()
|
|
sil [readonly] @readonly_guaranteed : $@convention(thin) (@guaranteed X) -> ()
|
|
sil [readonly] @readonly_indirect_params : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X
|
|
sil [readnone] @readnone_indirect_params : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X
|
|
|
|
sil @unknown_func : $@convention(thin) () -> ()
|
|
sil @unknown_func_with_in_arg : $@convention(thin) (@in X) -> ()
|
|
sil @unknown_func_with_in_guaranteed_arg : $@convention(thin) (@in_guaranteed X) -> ()
|
|
sil @unknown_func_with_inout_arg : $@convention(thin) (@inout SP) -> ()
|
|
sil @unknown_func_with_trivial_args : $@convention(thin) (@in_guaranteed Int32, Int32) -> ()
|
|
|
|
|
|
sil @$s4test1XCfD : $@convention(method) (@owned X) -> () {
|
|
[global: copy, write]
|
|
}
|
|
|
|
sil @$s4test1ZCfD : $@convention(method) (@owned Z) -> () {
|
|
[%0: write c0.v**]
|
|
}
|
|
|
|
// CHECK-LABEL: sil @load_store_to_args
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [%1: write v**]
|
|
// CHECK-NEXT: [%2: noescape **, write c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> () {
|
|
[%2: noescape **]
|
|
bb0(%0 : $*Int32, %1 : $*Int32, %2 : $X):
|
|
%l1 = load %0 : $*Int32
|
|
store %l1 to %1 : $*Int32
|
|
%a = ref_element_addr %2 : $X, #X.a
|
|
store %l1 to %a : $*Int32
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_load_store_to_args1
|
|
// CHECK-NEXT: [%0: write c0.v**]
|
|
// CHECK-NEXT: [%1: read v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_load_store_to_args1 : $@convention(thin) (@guaranteed X, @inout Int32, @inout Int32) -> () {
|
|
bb0(%0 : $X, %1 : $*Int32, %2 : $*Int32):
|
|
%s = alloc_stack $Int32
|
|
|
|
%f = function_ref @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%ap = apply %f(%1, %s, %0) : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
|
|
dealloc_stack %s : $*Int32
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_load_store_to_args2
|
|
// CHECK-NEXT: [%0: read c1.v**, write c0.v**]
|
|
// CHECK-NEXT: [%1: read v**]
|
|
// CHECK-NEXT: [global: write]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_load_store_to_args2 : $@convention(thin) (@guaranteed X, @inout Int32) -> () {
|
|
bb0(%0 : $X, %1 : $*Int32):
|
|
%xa = ref_element_addr %0 : $X, #X.x
|
|
%x2 = load %xa : $*X
|
|
%a = ref_element_addr %x2 : $X, #X.a
|
|
|
|
%f = function_ref @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%ap = apply %f(%1, %a, %0) : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @partial_apply_load_store_to_args
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [%1: read v**, write v**]
|
|
// CHECK-NEXT: [%2: write c0.v**, destroy c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @partial_apply_load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> () {
|
|
bb0(%0 : $*Int32, %1 : $*Int32, %2 : $X):
|
|
%f = function_ref @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%c = partial_apply %f(%1, %2) : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
// The apply may call deinit of the callee_owned thick function. Therefore the
|
|
// function effects are conservative.
|
|
// %c is implicitly released which may call deinit of the boxed X.
|
|
%ap = apply %c(%0) : $@callee_owned (@inout Int32) -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @guaranteed_partial_apply_load_store_to_args
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [%1: read v**, write v**]
|
|
// CHECK-NEXT: [%2: write c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @guaranteed_partial_apply_load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> () {
|
|
bb0(%0 : $*Int32, %1 : $*Int32, %2 : $X):
|
|
%f = function_ref @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%c = partial_apply [callee_guaranteed] %f(%1, %2) : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%ap = apply %c(%0) : $@callee_guaranteed (@inout Int32) -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @stack_partial_apply_load_store_to_args
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [%1: write v**]
|
|
// CHECK-NEXT: [%2: write c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @stack_partial_apply_load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> () {
|
|
bb0(%0 : $*Int32, %1 : $*Int32, %2 : $X):
|
|
%f = function_ref @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%c = partial_apply [on_stack] %f(%1, %2) : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%ap = apply %c(%0) : $@noescape @callee_owned (@inout Int32) -> ()
|
|
dealloc_stack %c : $@noescape @callee_owned (@inout Int32) -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @load_store_to_unknown
|
|
// CHECK-NEXT: [%1: read c1.v**]
|
|
// CHECK-NEXT: [global: read,write]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @load_store_to_unknown : $@convention(thin) (Int32, @guaranteed X) -> () {
|
|
bb0(%0 : $Int32, %1 : $X):
|
|
%xa = ref_element_addr %1 : $X, #X.x
|
|
%x2 = load %xa : $*X
|
|
%a = ref_element_addr %x2 : $X, #X.a
|
|
store %0 to %a : $*Int32
|
|
%l = load %a : $*Int32
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @retain_and_store
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [%1: copy v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @retain_and_store : $@convention(thin) (@guaranteed X) -> @out X {
|
|
bb0(%0 : $*X, %1 : $X):
|
|
strong_retain %1 : $X
|
|
store %1 to %0 : $*X
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @release_owned
|
|
// CHECK-NEXT: [%0: destroy c*.v**]
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @release_owned : $@convention(thin) (@owned X) -> () {
|
|
bb0(%0 : $X):
|
|
strong_release %0 : $X
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_unknown
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_unknown : $@convention(thin) () -> () {
|
|
bb0:
|
|
%u = function_ref @unknown_func : $@convention(thin) () -> ()
|
|
%a = apply %u() : $@convention(thin) () -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_unknown_func_with_trivial_args
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_unknown_func_with_trivial_args : $@convention(thin) (@in Int32, Int32) -> () {
|
|
bb0(%0 : $*Int32, %1 : $Int32):
|
|
%2 = function_ref @unknown_func_with_trivial_args : $@convention(thin) (@in_guaranteed Int32, Int32) -> ()
|
|
%3 = apply %2(%0, %1) : $@convention(thin) (@in_guaranteed Int32, Int32) -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @load_store_to_local
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @load_store_to_local : $@convention(thin) (Int32) -> () {
|
|
bb0(%0 : $Int32):
|
|
%x = alloc_ref $X
|
|
%a = ref_element_addr %x : $X, #X.a
|
|
store %0 to %a : $*Int32
|
|
%l1 = load %a : $*Int32
|
|
|
|
%b = alloc_box $<τ_0_0> { var τ_0_0 } <Int32>
|
|
%ba = project_box %b : $<τ_0_0> { var τ_0_0 } <Int32>, 0
|
|
store %0 to %ba : $*Int32
|
|
%l2 = load %ba : $*Int32
|
|
|
|
%s = alloc_stack $Int32
|
|
store %0 to %s : $*Int32
|
|
%l3 = load %s : $*Int32
|
|
dealloc_stack %s : $*Int32
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @condfail
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @condfail : $@convention(thin) (Builtin.Int1) -> () {
|
|
bb0(%0 : $Builtin.Int1):
|
|
cond_fail %0 : $Builtin.Int1
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @checkedcast
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @checkedcast : $@convention(thin) (Builtin.NativeObject) -> () {
|
|
bb0(%0 : $Builtin.NativeObject):
|
|
unconditional_checked_cast %0 : $Builtin.NativeObject to X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @checkedaddr
|
|
sil @checkedaddr : $@convention(thin) (Builtin.NativeObject, X) -> () {
|
|
// CHECK-NEXT: [%0: read v**.c*.v**, write v**.c*.v**, copy v**.c*.v**, destroy v**.c*.v**]
|
|
// CHECK-NEXT: [%1: read c*.v**, write c*.v**, copy c*.v**, destroy c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
bb0(%0 : $Builtin.NativeObject, %1 : $X):
|
|
unconditional_checked_cast_addr Builtin.NativeObject in %0 : $Builtin.NativeObject to X in %1 : $X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_project_box
|
|
// CHECK-NEXT: [%0: read c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @test_project_box : $@convention(thin) (<τ_0_0> { var τ_0_0 } <Builtin.Int32>) -> Builtin.Int32 {
|
|
bb0(%0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>):
|
|
%a = project_box %0 : $<τ_0_0> { var τ_0_0 } <Builtin.Int32>, 0
|
|
%l = load %a : $*Builtin.Int32
|
|
return %l : $Builtin.Int32
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @projections
|
|
// CHECK-NEXT: [%0: read e1.0.s0.c0.s0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @projections : $@convention(thin) (@guaranteed EP) -> Builtin.Int32 {
|
|
bb0(%0 : @guaranteed $EP):
|
|
%1 = unchecked_enum_data %0 : $EP, #EP.data!enumelt
|
|
%2 = tuple_extract %1 : $(SP, Builtin.Int1), 0
|
|
%3 = struct_extract %2 : $SP, #SP.value
|
|
%b = begin_borrow %3 : $X
|
|
%4 = ref_element_addr %b : $X, #X.a
|
|
%5 = begin_access [read] [dynamic] %4 : $*Int32
|
|
%6 = struct_element_addr %5 : $*Int32, #Int32._value
|
|
%7 = load [trivial] %6 : $*Builtin.Int32
|
|
end_access %5 : $*Int32
|
|
end_borrow %b : $X
|
|
return %7 : $Builtin.Int32
|
|
}
|
|
|
|
sil @two_addr_args : $@convention(thin) (@inout Int32, @inout SP) -> () {
|
|
[%0: write s1]
|
|
[%1: write s0.v**]
|
|
[global: ]
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @path_concatenation
|
|
// CHECK-NEXT: [%0: write s0.c0.s1]
|
|
// CHECK-NEXT: [%1: write s1.s0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @path_concatenation : $@convention(thin) (@guaranteed SP, @inout TwoSPs) -> () {
|
|
bb0(%0 : @guaranteed $SP, %1 : $*TwoSPs):
|
|
%2 = struct_extract %0 : $SP, #SP.value
|
|
%3 = ref_element_addr %2 : $X, #X.a
|
|
%4 = struct_element_addr %1 : $*TwoSPs, #TwoSPs.sp2
|
|
%f = function_ref @two_addr_args : $@convention(thin) (@inout Int32, @inout SP) -> ()
|
|
%ap = apply %f(%3, %4) : $@convention(thin) (@inout Int32, @inout SP) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @two_addr_args2 : $@convention(thin) (@inout Int32, @inout X) -> () {
|
|
[%0: write v**]
|
|
[%1: write v**]
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @path_merging
|
|
// CHECK-NEXT: [%0: write s0.c*.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @path_merging : $@convention(thin) (@guaranteed SP) -> () {
|
|
bb0(%0 : @guaranteed $SP):
|
|
%1 = struct_extract %0 : $SP, #SP.value
|
|
%2 = ref_element_addr %1 : $X, #X.a
|
|
%3 = ref_element_addr %1 : $X, #X.x
|
|
%f = function_ref @two_addr_args2 : $@convention(thin) (@inout Int32, @inout X) -> ()
|
|
%ap = apply %f(%2, %3) : $@convention(thin) (@inout Int32, @inout X) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @multiple_arg_roots1
|
|
// CHECK-NEXT: [%0: read s0.c0.v**]
|
|
// CHECK-NEXT: [%1: read c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @multiple_arg_roots1 : $@convention(thin) (@guaranteed SP, @guaranteed X) -> Int32 {
|
|
bb0(%0 : $SP, %1 : $X):
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
%2 = struct_extract %0 : $SP, #SP.value
|
|
br bb3(%2 : $X)
|
|
bb2:
|
|
br bb3(%1 : $X)
|
|
bb3(%5 : $X):
|
|
%6 = ref_element_addr %5 : $X, #X.a
|
|
%7 = load %6 : $*Int32
|
|
return %7 : $Int32
|
|
}
|
|
|
|
// CHECK-LABEL: sil @multiple_arg_roots_and_load
|
|
// CHECK-NEXT: [%0: read s0.c0.v**]
|
|
// CHECK-NEXT: [%1: read c0.v**]
|
|
// CHECK-NEXT: [%2: read v**]
|
|
// CHECK-NEXT: [global: read]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @multiple_arg_roots_and_load : $@convention(thin) (@guaranteed SP, @guaranteed X, @in_guaranteed X) -> Int32 {
|
|
bb0(%0 : $SP, %1 : $X, %2 : $*X):
|
|
cond_br undef, bb1, bb2
|
|
bb1:
|
|
cond_br undef, bb3, bb4
|
|
bb2:
|
|
%5 = struct_extract %0 : $SP, #SP.value
|
|
br bb5(%5 : $X)
|
|
bb3:
|
|
br bb5(%1 : $X)
|
|
bb4:
|
|
%8 = load %2 : $*X
|
|
br bb5(%8 : $X)
|
|
bb5(%10 : $X):
|
|
%11 = ref_element_addr %10 : $X, #X.a
|
|
%12 = load %11 : $*Int32
|
|
return %12 : $Int32
|
|
}
|
|
|
|
// CHECK-LABEL: sil @load_from_global_var
|
|
// CHECK-NEXT: [global: read,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @load_from_global_var : $@convention(thin) () -> Int32 {
|
|
bb0:
|
|
%0 = global_addr @global_var : $*Int32
|
|
%1 = load %0 : $*Int32
|
|
return %1 : $Int32
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @forward_to_return
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @forward_to_return : $@convention(thin) (@owned SP) -> @owned SP {
|
|
bb0(%0 : @owned $SP):
|
|
return %0 : $SP
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @store_destroys
|
|
// CHECK-NEXT: [%0: read v**, write v**, destroy v**]
|
|
// CHECK-NEXT: [%1: write c*.v**, copy c*.v**]
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @store_destroys : $@convention(thin) (@inout X, @owned X) -> () {
|
|
bb0(%0 : $*X, %1 : @owned $X):
|
|
store %1 to [assign] %0 : $*X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @unknown_destructor_effects
|
|
// CHECK-NEXT: [%0: read v**, write v**, destroy v**]
|
|
// CHECK-NEXT: [%1: read c*.v**, write c*.v**, copy c*.v**, destroy c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @unknown_destructor_effects : $@convention(thin) (@inout Y, @owned Y) -> () {
|
|
bb0(%0 : $*Y, %1 : @owned $Y):
|
|
store %1 to [assign] %0 : $*Y
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @store_doesnt_destroy
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @store_doesnt_destroy : $@convention(thin) (@owned X) -> @out X {
|
|
bb0(%0 : $*X, %1 : @owned $X):
|
|
store %1 to [init] %0 : $*X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_destroys
|
|
// CHECK-NEXT: [%0: read v**, write v**, destroy v**]
|
|
// CHECK-NEXT: [%1: read v**, copy v**]
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @copy_destroys : $@convention(thin) (@inout X, @in_guaranteed X) -> () {
|
|
bb0(%0 : $*X, %1 : $*X):
|
|
copy_addr %1 to %0 : $*X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_doesnt_destroy
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [%1: read v**, copy v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @copy_doesnt_destroy : $@convention(thin) (@in_guaranteed X) -> @out X {
|
|
bb0(%0 : $*X, %1 : $*X):
|
|
copy_addr %1 to [init] %0 : $*X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @destroy_value_effects1
|
|
// CHECK-NEXT: [%0: read v**.c*.v**, write v**.c*.v**, copy v**.c*.v**, destroy v**.c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @destroy_value_effects1 : $@convention(thin) (@owned SP) -> () {
|
|
bb0(%0 : @owned $SP):
|
|
destroy_value %0 : $SP
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @destroy_value_effects2
|
|
// CHECK-NEXT: [%0: destroy s0.c*.v**]
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @destroy_value_effects2 : $@convention(thin) (@owned SP) -> () {
|
|
bb0(%0 : @owned $SP):
|
|
(%1) = destructure_struct %0 : $SP
|
|
destroy_value %1 : $X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @destroy_value_effects3
|
|
// CHECK-NEXT: [%0: write c0.v**, destroy c*.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @destroy_value_effects3 : $@convention(thin) (@owned Z) -> () {
|
|
bb0(%0 : @owned $Z):
|
|
destroy_value %0 : $Z
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @destroy_addr_effects
|
|
// CHECK-NEXT: [%0: read v**, write v**, destroy v**]
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @destroy_addr_effects : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
destroy_addr %0 : $*X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @release_value_effects
|
|
// CHECK-NEXT: [%0: destroy c*.v**]
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @release_value_effects : $@convention(thin) (@owned X) -> () {
|
|
bb0(%0 : $X):
|
|
release_value %0 : $X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @strong_release_effects
|
|
// CHECK-NEXT: [%0: destroy c*.v**]
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @strong_release_effects : $@convention(thin) (@owned X) -> () {
|
|
bb0(%0 : $X):
|
|
strong_release %0 : $X
|
|
%2 = tuple ()
|
|
return %2 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @load_and_release
|
|
// CHECK-NEXT: [%0: read v**, copy v**, destroy v**]
|
|
// CHECK-NEXT: [global: write,copy,destroy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @load_and_release : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = load %0 : $*X
|
|
strong_release %1 : $X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_take_and_destroy
|
|
// CHECK-NEXT: [%0: read v**, copy v**, destroy v**]
|
|
// CHECK-NEXT: [global: write,copy,destroy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @load_take_and_destroy : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = load [take] %0 : $*X
|
|
destroy_value %1 : $X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @load_copy_and_destroy
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [global: write,copy,destroy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @load_copy_and_destroy : $@convention(thin) (@in_guaranteed X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = load [copy] %0 : $*X
|
|
destroy_value %1 : $X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_addr_take_and_destroy
|
|
// CHECK-NEXT: [%0: read v**, copy v**, destroy v**]
|
|
// CHECK-NEXT: [global: write,copy,destroy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @copy_addr_take_and_destroy : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = alloc_stack $X
|
|
copy_addr [take] %0 to [init] %1 : $*X
|
|
destroy_addr %1 : $*X
|
|
dealloc_stack %1 : $*X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_addr_take_and_init
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [%1: read v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @copy_addr_take_and_init : $@convention(thin) (@in X) -> @out X {
|
|
bb0(%0 : $*X, %1 : $*X):
|
|
copy_addr [take] %1 to [init] %0 : $*X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_addr_and_destroy
|
|
// CHECK-NEXT: [%0: read v**, copy v**]
|
|
// CHECK-NEXT: [global: write,copy,destroy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @copy_addr_and_destroy : $@convention(thin) (@in_guaranteed X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = alloc_stack $X
|
|
copy_addr %0 to [init] %1 : $*X
|
|
destroy_addr %1 : $*X
|
|
dealloc_stack %1 : $*X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @pass_arg_to_unknown_function
|
|
// CHECK-NEXT: [%0: read s1.v**, write s1.v**, copy s1.v**, destroy s1.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @pass_arg_to_unknown_function : $@convention(thin) (@inout TwoSPs) -> () {
|
|
bb0(%0 : $*TwoSPs):
|
|
%1 = struct_element_addr %0 : $*TwoSPs, #TwoSPs.sp2
|
|
%f = function_ref @unknown_func_with_inout_arg : $@convention(thin) (@inout SP) -> ()
|
|
%a = apply %f(%1) : $@convention(thin) (@inout SP) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_addr_and_consume_by_unknown_func
|
|
// CHECK-NEXT: [%0: read v**, copy v**, destroy v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @copy_addr_and_consume_by_unknown_func : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = alloc_stack $X
|
|
copy_addr [take] %0 to [init] %1 : $*X
|
|
%f = function_ref @unknown_func_with_in_arg : $@convention(thin) (@in X) -> ()
|
|
%a = apply %f(%1) : $@convention(thin) (@in X) -> ()
|
|
dealloc_stack %1 : $*X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
sil [_semantics "programtermination_point"] @exitfunc_defined : $@convention(thin) () -> Never {
|
|
bb0:
|
|
%u = function_ref @unknown_func : $@convention(thin) () -> ()
|
|
%a = apply %u() : $@convention(thin) () -> ()
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_noreturn
|
|
// CHECK-NEXT: [global: read]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_noreturn : $@convention(thin) () -> () {
|
|
bb0:
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%u = function_ref @exitfunc : $@convention(thin) () -> Never
|
|
%a = apply %u() : $@convention(thin) () -> Never
|
|
unreachable
|
|
|
|
bb2:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_defined_noreturn
|
|
// CHECK-NEXT: [global: read]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_defined_noreturn : $@convention(thin) () -> () {
|
|
bb0:
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%u = function_ref @exitfunc_defined : $@convention(thin) () -> Never
|
|
%a = apply %u() : $@convention(thin) () -> Never
|
|
unreachable
|
|
|
|
bb2:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_readnone
|
|
// CHECK-NEXT: [global: copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_readnone : $@convention(thin) () -> () {
|
|
bb0:
|
|
%u = function_ref @pure_func : $@convention(thin) () -> ()
|
|
%a = apply %u() : $@convention(thin) () -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_releasenone
|
|
// CHECK-NEXT: [global: read,write,copy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_releasenone : $@convention(thin) () -> () {
|
|
bb0:
|
|
%u = function_ref @releasenone_func : $@convention(thin) () -> ()
|
|
%a = apply %u() : $@convention(thin) () -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil @call_readonly_owned
|
|
// CHECK-NEXT: [%0: read c*.v**, copy c*.v**]
|
|
// CHECK-NEXT: [global: read,copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_readonly_owned : $@convention(thin) (@owned X) -> () {
|
|
bb0(%0 : $X):
|
|
%u = function_ref @readonly_owned : $@convention(thin) (@owned X) -> ()
|
|
%a = apply %u(%0) : $@convention(thin) (@owned X) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @call_readnone_owned
|
|
// CHECK-NEXT: [%0: copy c*.v**]
|
|
// CHECK-NEXT: [global: copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @call_readnone_owned : $@convention(thin) (@owned X) -> @owned X {
|
|
bb0(%0 : @owned $X):
|
|
%u = function_ref @readnone_owned : $@convention(thin) (@owned X) -> @owned X
|
|
%a = apply %u(%0) : $@convention(thin) (@owned X) -> @owned X
|
|
return %a : $X
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_readonly_guaranteed
|
|
// CHECK-NEXT: [%0: read c*.v**, copy c*.v**]
|
|
// CHECK-NEXT: [global: read,copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_readonly_guaranteed : $@convention(thin) (@guaranteed X) -> () {
|
|
bb0(%0 : $X):
|
|
%u = function_ref @readonly_guaranteed : $@convention(thin) (@guaranteed X) -> ()
|
|
%a = apply %u(%0) : $@convention(thin) (@guaranteed X) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_readonly_indirect_params
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [%1: read v**, copy v**]
|
|
// CHECK-NEXT: [%2: read v**, copy v**]
|
|
// CHECK-NEXT: [global: read,copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_readonly_indirect_params : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X {
|
|
bb0(%0 : $*X, %1 : $*X, %2 : $*X):
|
|
%u = function_ref @readonly_indirect_params : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X
|
|
%a = apply %u(%0, %1, %2) : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_readnone_indirect_params
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [%1: read v**, copy v**]
|
|
// CHECK-NEXT: [%2: read v**, copy v**]
|
|
// CHECK-NEXT: [global: read,copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_readnone_indirect_params : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X {
|
|
bb0(%0 : $*X, %1 : $*X, %2 : $*X):
|
|
%u = function_ref @readonly_indirect_params : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X
|
|
%a = apply %u(%0, %1, %2) : $@convention(thin) (@in_guaranteed X, @inout X) -> @out X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_unknown_func_with_in_guaranteed_arg
|
|
// CHECK-NEXT: [%0: read v**, copy v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_unknown_func_with_in_guaranteed_arg : $@convention(thin) (@in_guaranteed X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = function_ref @unknown_func_with_in_guaranteed_arg : $@convention(thin) (@in_guaranteed X) -> ()
|
|
%2 = apply %1(%0) : $@convention(thin) (@in_guaranteed X) -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_escaping_in_argument
|
|
// CHECK-NEXT: [%0: read v**, copy v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @test_escaping_in_argument : $@convention(thin) (@in_guaranteed X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = address_to_pointer %0 : $*X to $Builtin.RawPointer
|
|
%3 = function_ref @unknown_func : $@convention(thin) () -> ()
|
|
%4 = apply %3() : $@convention(thin) () -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @copy_argument
|
|
// CHECK-NEXT: [%0: copy v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @copy_argument : $@convention(thin) (@owned SP) -> @owned TwoSPs {
|
|
bb0(%0 : @owned $SP):
|
|
%1 = copy_value %0 : $SP
|
|
%2 = struct $TwoSPs(%0 : $SP, %1 : $SP)
|
|
return %2 : $TwoSPs
|
|
}
|
|
|
|
// CHECK-LABEL: sil @fix_lifetime_test
|
|
// CHECK-NEXT: [%0: read c*.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @fix_lifetime_test : $@convention(thin) (@guaranteed X) -> () {
|
|
bb0(%0 : $X):
|
|
fix_lifetime %0 : $X
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @not_called_partial_apply
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @not_called_partial_apply : $@convention(thin) (@in Int32) -> @owned @callee_owned (Bool) -> Int32 {
|
|
bb0(%0 : $*Int32):
|
|
%2 = function_ref @closure : $@convention(thin) (Bool, @in Int32) -> Int32
|
|
%3 = partial_apply %2(%0) : $@convention(thin) (Bool, @in Int32) -> Int32
|
|
return %3 : $@callee_owned (Bool) -> Int32
|
|
}
|
|
|
|
// CHECK-LABEL: sil @partial_apply_chain
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [%1: read v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @partial_apply_chain : $@convention(thin) (@in Int32, @in Int32) -> @owned @callee_owned (Bool) -> Int32 {
|
|
bb0(%0 : $*Int32, %1 : $*Int32):
|
|
%3 = function_ref @closure2 : $@convention(thin) (Bool, @in Int32, @in Int32) -> Int32
|
|
%4 = partial_apply %3(%0) : $@convention(thin) (Bool, @in Int32, @in Int32) -> Int32
|
|
%5 = partial_apply %4(%1) : $@callee_owned (Bool, @in Int32) -> Int32
|
|
return %5 : $@callee_owned (Bool) -> Int32
|
|
}
|
|
|
|
// CHECK-LABEL: sil @two_nonstack_partial_applies
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [%1: read v**, write v**]
|
|
// CHECK-NEXT: [%2: write c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @two_nonstack_partial_applies : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> () {
|
|
bb0(%0 : $*Int32, %1 : $*Int32, %2 : $X):
|
|
%f = function_ref @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%c1 = partial_apply [callee_guaranteed] %f(%2) : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%c2 = partial_apply [callee_guaranteed] %c1(%1) : $@callee_guaranteed (@inout Int32, @inout Int32) -> ()
|
|
%ap = apply %c2(%0) : $@callee_guaranteed (@inout Int32) -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @two_stack_partial_applies
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [%1: write v**]
|
|
// CHECK-NEXT: [%2: write c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @two_stack_partial_applies : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> () {
|
|
bb0(%0 : $*Int32, %1 : $*Int32, %2 : $X):
|
|
%f = function_ref @load_store_to_args : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%c1 = partial_apply [on_stack] %f(%2) : $@convention(thin) (@inout Int32, @inout Int32, @guaranteed X) -> ()
|
|
%c2 = partial_apply [on_stack] %c1(%1) : $@noescape @callee_owned (@inout Int32, @inout Int32) -> ()
|
|
%ap = apply %c2(%0) : $@noescape @callee_owned (@inout Int32) -> ()
|
|
dealloc_stack %c2 : $@noescape @callee_owned (@inout Int32) -> ()
|
|
dealloc_stack %c1 : $@noescape @callee_owned (@inout Int32, @inout Int32) -> ()
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @closure : $@convention(thin) (Bool, @in Int32) -> Int32
|
|
sil @closure2 : $@convention(thin) (Bool, @in Int32, @in Int32) -> Int32
|
|
|
|
sil public_external @public_external_func : $@convention(thin) () -> () {
|
|
bb0:
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @call_public_external_func
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @call_public_external_func : $@convention(thin) () -> () {
|
|
bb0:
|
|
%u = function_ref @public_external_func : $@convention(thin) () -> ()
|
|
%a = apply %u() : $@convention(thin) () -> ()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @non_escaping_allocation
|
|
// CHECK-NEXT: [global: write,copy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @non_escaping_allocation : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_ref $X
|
|
destroy_value %0 :$X
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @escaping_allocation
|
|
// CHECK-NEXT: [global: allocate]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @escaping_allocation : $@convention(thin) () -> @owned X {
|
|
bb0:
|
|
%0 = alloc_ref $X
|
|
return %0 : $X
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @readIdentifiedArg
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @readIdentifiedArg : $@convention(thin) (@in Int32) -> Int32 {
|
|
bb0(%0 : $*Int32):
|
|
%res = load [trivial] %0 : $*Int32
|
|
return %res : $Int32
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @writeIdentifiedArg
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @writeIdentifiedArg : $@convention(thin) (@inout Int32) -> () {
|
|
bb0(%0 : $*Int32):
|
|
%2 = integer_literal $Builtin.Int32, 42
|
|
%3 = struct $Int32 (%2 : $Builtin.Int32)
|
|
store %3 to [trivial] %0 : $*Int32
|
|
%5 = tuple ()
|
|
return %5 : $()
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil [ossa] @$writeToHead
|
|
// CHECK-NEXT: [%0: write s0.c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @$writeToHead : $@convention(thin) (@guaranteed S) -> () {
|
|
bb0(%0 : @guaranteed $S):
|
|
debug_value %0 : $S, let, name "s", argno 1
|
|
%2 = struct_extract %0 : $S, #S.l
|
|
%3 = integer_literal $Builtin.Int32, 10
|
|
%4 = struct $Int32 (%3 : $Builtin.Int32)
|
|
%5 = begin_borrow [lexical] %2 : $List
|
|
%6 = ref_element_addr %5 : $List, #List.x
|
|
%7 = begin_access [modify] [dynamic] %6 : $*Int32
|
|
store %4 to [trivial] %7 : $*Int32
|
|
end_access %7 : $*Int32
|
|
end_borrow %5 : $List
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @storeToArgs
|
|
// CHECK-NEXT: [%0: noescape **, write c0.v**]
|
|
// CHECK-NEXT: [%1: noescape **, write c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @storeToArgs : $@convention(thin) (@guaranteed List, @guaranteed List) -> () {
|
|
[%0: noescape **]
|
|
[%1: noescape **]
|
|
bb0(%1 : @guaranteed $List, %2 : @guaranteed $List):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%8 = integer_literal $Builtin.Int32, 10
|
|
%9 = struct $Int32 (%8 : $Builtin.Int32)
|
|
%10 = ref_element_addr %1 : $List, #List.x
|
|
%11 = begin_access [modify] [dynamic] %10 : $*Int32
|
|
store %9 to [trivial] %11 : $*Int32
|
|
end_access %11 : $*Int32
|
|
%14 = tuple ()
|
|
br bb3
|
|
|
|
bb2:
|
|
%16 = integer_literal $Builtin.Int32, 20
|
|
%17 = struct $Int32 (%16 : $Builtin.Int32)
|
|
%18 = ref_element_addr %2 : $List, #List.x
|
|
%19 = begin_access [modify] [dynamic] %18 : $*Int32
|
|
store %17 to [trivial] %19 : $*Int32
|
|
end_access %19 : $*Int32
|
|
%22 = tuple ()
|
|
br bb3
|
|
|
|
bb3:
|
|
%24 = tuple ()
|
|
return %24 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @storeMaybeLocalPhi
|
|
// CHECK-NEXT: [%0: read c*.v**, write c*.v**, copy **, destroy c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @storeMaybeLocalPhi : $@convention(thin) (@guaranteed List) -> () {
|
|
bb0(%1 : $List):
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
strong_retain %1 : $List
|
|
br bb3(%1 : $List)
|
|
|
|
bb2:
|
|
%10 = alloc_ref $List
|
|
br bb3(%10 : $List)
|
|
|
|
bb3(%12 : $List):
|
|
%14 = integer_literal $Builtin.Int32, 20
|
|
%15 = struct $Int32 (%14 : $Builtin.Int32)
|
|
%16 = ref_element_addr %12 : $List, #List.x
|
|
%17 = begin_access [modify] [dynamic] %16 : $*Int32
|
|
store %15 to %17 : $*Int32
|
|
end_access %17 : $*Int32
|
|
%20 = tuple ()
|
|
strong_release %12 : $List
|
|
%22 = tuple ()
|
|
return %22 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @testStructPhiCommon
|
|
// CHECK-NEXT: [%0: write s0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @testStructPhiCommon : $@convention(thin) (@inout Ptr) -> () {
|
|
bb0(%0 : $*Ptr):
|
|
%2 = struct_element_addr %0 : $*Ptr, #Ptr.p
|
|
cond_br undef, bb1, bb2
|
|
|
|
bb1:
|
|
%3 = address_to_pointer %2 : $*Int32 to $Builtin.RawPointer
|
|
br bb3(%3 : $Builtin.RawPointer)
|
|
|
|
bb2:
|
|
%5 = address_to_pointer %2 : $*Int32 to $Builtin.RawPointer
|
|
br bb3(%5 : $Builtin.RawPointer)
|
|
|
|
bb3(%6 : $Builtin.RawPointer) :
|
|
%7 = pointer_to_address %6 : $Builtin.RawPointer to $*Int32
|
|
%8 = integer_literal $Builtin.Int32, 2
|
|
%9 = struct $Int32 (%8 : $Builtin.Int32)
|
|
store %9 to [trivial] %7 : $*Int32
|
|
%22 = tuple ()
|
|
return %22 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @calleeWriteToHead
|
|
// CHECK-NEXT: [%0: write s0.c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @calleeWriteToHead : $@convention(thin) (@guaranteed S) -> () {
|
|
bb0(%0 : @guaranteed $S):
|
|
debug_value %0 : $S, let, name "s", argno 1
|
|
%2 = struct_extract %0 : $S, #S.l
|
|
%3 = integer_literal $Builtin.Int32, 10
|
|
%4 = struct $Int32 (%3 : $Builtin.Int32)
|
|
%5 = begin_borrow [lexical] %2 : $List
|
|
%6 = ref_element_addr %5 : $List, #List.x
|
|
%7 = begin_access [modify] [dynamic] %6 : $*Int32
|
|
%writeArg = function_ref @writeIdentifiedArg : $@convention(thin) (@inout Int32) -> ()
|
|
%app = apply %writeArg(%7) : $@convention(thin) (@inout Int32) -> ()
|
|
end_access %7 : $*Int32
|
|
end_borrow %5 : $List
|
|
%11 = tuple ()
|
|
return %11 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @has_partial_apply
|
|
// CHECK-NEXT: [%0: write c0.v**]
|
|
// TODO: Teach analysis that destroying noescape closures has no side effects.
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @has_partial_apply : $@convention(thin) (@guaranteed List) -> () {
|
|
bb0(%0 : @guaranteed $List):
|
|
%f = function_ref @storeToArgs : $@convention(thin) (@guaranteed List, @guaranteed List) -> ()
|
|
%clo = partial_apply [callee_guaranteed] [on_stack] %f(%0) : $@convention(thin) (@guaranteed List, @guaranteed List) -> ()
|
|
%res = apply %clo(%0) : $@noescape @callee_guaranteed (@guaranteed List) -> ()
|
|
destroy_value %clo : $@noescape @callee_guaranteed (@guaranteed List) -> ()
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @readIdentifiedBoxArg
|
|
// CHECK-NEXT: [%0: read c0.v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @readIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int32 }) -> Int32 {
|
|
bb0(%0 : @guaranteed ${ var Int32 }):
|
|
%1 = project_box %0 : ${ var Int32 }, 0
|
|
%5 = begin_access [read] [dynamic] %1 : $*Int32
|
|
%6 = load [trivial] %5 : $*Int32
|
|
end_access %5 : $*Int32
|
|
return %6 : $Int32
|
|
}
|
|
|
|
|
|
// CHECK-LABEL: sil [ossa] @callUnknownIsDeinitBarrier : {{.*}} {
|
|
// CHECK-NEXT: [global: {{.*}}deinit_barrier]
|
|
// CHECK-LABEL: } // end sil function 'callUnknownIsDeinitBarrier'
|
|
sil [ossa] @callUnknownIsDeinitBarrier : $@convention(thin) () -> () {
|
|
%callee = function_ref @unknown_func : $@convention(thin) () -> ()
|
|
apply %callee() : $@convention(thin) () -> ()
|
|
%retval = tuple ()
|
|
return %retval : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @begin_cow_test
|
|
// CHECK-NEXT: [%0: destroy v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @begin_cow_test : $@convention(thin) (@guaranteed X) -> () {
|
|
bb0(%0 : $X):
|
|
(%1, %2) = begin_cow_mutation %0 : $X
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @is_unique_test
|
|
// CHECK-NEXT: [%0: destroy v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @is_unique_test : $@convention(thin) (@inout X) -> () {
|
|
bb0(%0 : $*X):
|
|
%1 = is_unique %0 : $*X
|
|
%3 = tuple()
|
|
return %3 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @destroy_not_escaped_closure_test
|
|
// CHECK-NEXT: [%0: read v**.c*.v**, write v**.c*.v**, copy v**.c*.v**, destroy v**.c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @destroy_not_escaped_closure_test : $@convention(thin)(@owned @callee_guaranteed () -> ()) -> Builtin.Int1 {
|
|
bb0(%0 : $@callee_guaranteed () -> ()):
|
|
%1 = destroy_not_escaped_closure %0: $@callee_guaranteed () -> ()
|
|
return %1 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_enum_and_p2a
|
|
// CHECK-NEXT: [%0: write v**.c*.v**]
|
|
// CHECK-NEXT: [global: write,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @test_enum_and_p2a : $@convention(thin) (Optional<UnsafeMutablePointer<Int>>, Int) -> () {
|
|
bb0(%0 : $Optional<UnsafeMutablePointer<Int>>, %1 : $Int):
|
|
switch_enum %0 : $Optional<UnsafeMutablePointer<Int>>, case #Optional.some!enumelt: bb1, case #Optional.none!enumelt: bb2
|
|
bb1(%2 : $UnsafeMutablePointer<Int>):
|
|
%3 = struct_extract %2 : $UnsafeMutablePointer<Int>, #UnsafeMutablePointer._rawValue
|
|
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Int
|
|
store %1 to %4 : $*Int
|
|
br bb3
|
|
bb2:
|
|
br bb3
|
|
bb3:
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_debug_value_address
|
|
// CHECK-NEXT: [%0: read v**, write v**, destroy v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @test_debug_value_address : $@convention(thin) <T> (@in T, @inout T) -> () {
|
|
bb0(%0 : $*T, %1 : $*T):
|
|
destroy_addr %0 : $*T
|
|
debug_value %1 : $*T
|
|
%4 = tuple ()
|
|
return %4 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [ossa] @test_explicit_copy_addr
|
|
// CHECK-NEXT: [%0: read v**, copy v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil [ossa] @test_explicit_copy_addr : $@convention(thin) <T> (@in_guaranteed T) -> () {
|
|
bb0(%0 : $*T):
|
|
%1 = alloc_stack $T
|
|
explicit_copy_addr %0 to [init] %1 : $*T
|
|
destroy_addr %1 : $*T
|
|
dealloc_stack %1 : $*T
|
|
%r = tuple()
|
|
return %r : $()
|
|
}
|
|
|
|
sil @store_owned_to_out : $@convention(thin) (@owned SP) -> @out SP {
|
|
[%0: noescape **, write v**]
|
|
[%1: escape v** -> %0.v**]
|
|
[global: ]
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_escaping_arg1
|
|
// CHECK-NEXT: [%0: write v**.c*.v**, copy v**.c*.v**, destroy v**.c*.v**]
|
|
// CHECK-NEXT: [global: write,copy,destroy]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @test_escaping_arg1 : $@convention(thin) (@owned SP) -> () {
|
|
bb0(%0 : $SP):
|
|
%1 = alloc_stack $SP
|
|
%2 = function_ref @store_owned_to_out : $@convention(thin) (@owned SP) -> @out SP
|
|
%3 = apply %2(%1, %0) : $@convention(thin) (@owned SP) -> @out SP
|
|
%4 = struct_element_addr %1 : $*SP, #SP.value
|
|
%5 = load %4 : $*X
|
|
strong_release %5 : $X
|
|
dealloc_stack %1 : $*SP
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_escaping_arg2
|
|
// CHECK-NEXT: [%0: read v**.c*.v**, write v**.c*.v**, copy v**.c*.v**, destroy v**.c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,destroy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @test_escaping_arg2 : $@convention(thin) (@owned SP) -> () {
|
|
bb0(%0 : $SP):
|
|
%1 = function_ref @forward_to_return : $@convention(thin) (@owned SP) -> @owned SP
|
|
%2 = apply %1(%0) : $@convention(thin) (@owned SP) -> @owned SP
|
|
release_value %2 : $SP
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_consuming_in_with_unreachable
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
sil @test_consuming_in_with_unreachable : $@convention(thin) (@in X) -> () {
|
|
bb0(%0 : $*X):
|
|
unreachable
|
|
}
|
|
|
|
// CHECK-LABEL: sil @test_willThrow_builtin
|
|
// CHECK: [%0: read v**.c*.v**, copy v**.c*.v**]
|
|
// CHECK: [global: read,copy,deinit_barrier]
|
|
|
|
sil @test_willThrow_builtin : $@convention(thin) (@guaranteed any Error) -> () {
|
|
bb0(%0: $any Error):
|
|
%1 = builtin "willThrow"(%0 : $any Error) : $()
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// Base case: @destroy_not_escaped_closure_test. It has every global and argument effect, so we can see which are removed.
|
|
// CHECK-LABEL: sil [readnone] @test_effect_attribute_readnone
|
|
// CHECK-NEXT: [global: copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_readnone'
|
|
sil [readnone] @test_effect_attribute_readnone : $@convention(thin)(@owned @callee_guaranteed () -> ()) -> Builtin.Int1 {
|
|
bb0(%0 : $@callee_guaranteed () -> ()):
|
|
%1 = destroy_not_escaped_closure %0: $@callee_guaranteed () -> ()
|
|
return %1 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil [readonly] @test_effect_attribute_readonly
|
|
// CHECK-NEXT: [%0: read v**.c*.v**, copy v**.c*.v**]
|
|
// CHECK-NEXT: [global: read,copy,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_readonly'
|
|
sil [readonly] @test_effect_attribute_readonly : $@convention(thin)(@owned @callee_guaranteed () -> ()) -> Builtin.Int1 {
|
|
bb0(%0 : $@callee_guaranteed () -> ()):
|
|
%1 = destroy_not_escaped_closure %0: $@callee_guaranteed () -> ()
|
|
return %1 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil [releasenone] @test_effect_attribute_releasenone
|
|
// CHECK-NEXT: [%0: read v**.c*.v**, write v**.c*.v**, copy v**.c*.v**]
|
|
// CHECK-NEXT: [global: read,write,copy,allocate,deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_releasenone'
|
|
sil [releasenone] @test_effect_attribute_releasenone : $@convention(thin)(@owned @callee_guaranteed () -> ()) -> Builtin.Int1 {
|
|
bb0(%0 : $@callee_guaranteed () -> ()):
|
|
%1 = destroy_not_escaped_closure %0: $@callee_guaranteed () -> ()
|
|
return %1 : $Builtin.Int1
|
|
}
|
|
|
|
// These tests are adapted from the test case in rdar://155870190
|
|
sil @test_effect_attribute_no_barrier : $@convention(thin) () -> () {
|
|
[global: ]
|
|
}
|
|
|
|
sil @test_effect_attribute_barrier : $@convention(thin) () -> () {
|
|
[global: deinit_barrier]
|
|
}
|
|
// CHECK-LABEL: sil [readnone] @test_effect_attribute_call_no_barrier
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_call_no_barrier'
|
|
sil [readnone] @test_effect_attribute_call_no_barrier : $@convention(thin) () -> @out Any {
|
|
bb0(%0 : $*Any):
|
|
%2 = function_ref @test_effect_attribute_no_barrier : $@convention(thin) () -> ()
|
|
apply %2() : $@convention(thin) () -> ()
|
|
%4 = tuple ()
|
|
return %4
|
|
}
|
|
|
|
// CHECK-LABEL: sil [readnone] @test_effect_attribute_call_barrier
|
|
// CHECK-NEXT: [global: deinit_barrier]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_call_barrier'
|
|
sil [readnone] @test_effect_attribute_call_barrier : $@convention(thin) () -> @out Any {
|
|
bb0(%0 : $*Any):
|
|
%2 = function_ref @test_effect_attribute_barrier : $@convention(thin) () -> ()
|
|
apply %2() : $@convention(thin) () -> ()
|
|
%4 = tuple ()
|
|
return %4
|
|
}
|
|
|
|
// The readnone attribute can not rule out reads from indirect arguments.
|
|
// CHECK-LABEL: sil [readnone] @test_effect_attribute_readnone_direct_argument
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_readnone_direct_argument'
|
|
sil [readnone] @test_effect_attribute_readnone_direct_argument : $@convention(thin) (Int) -> Int {
|
|
bb0(%0 : $Int):
|
|
return %0
|
|
}
|
|
|
|
// CHECK-LABEL: sil [readnone] @test_effect_attribute_readnone_indirect_argument
|
|
// CHECK-NEXT: [%0: read v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_readnone_indirect_argument'
|
|
sil [readnone] @test_effect_attribute_readnone_indirect_argument : $@convention(thin) (@in Int) -> Int {
|
|
bb0(%0 : $*Int):
|
|
%1 = load %0
|
|
return %1
|
|
}
|
|
|
|
// Base case: @retain_and_store. The indirect result has a write effect, which readnone & readonly can't rule out.
|
|
// CHECK-LABEL: sil [readnone] @test_effect_attribute_readnone_indirect_result
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_readnone_indirect_result'
|
|
sil [readnone] @test_effect_attribute_readnone_indirect_result : $@convention(thin) (@guaranteed X) -> @out X {
|
|
bb0(%0 : $*X, %1 : $X):
|
|
strong_retain %1 : $X
|
|
store %1 to %0 : $*X
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|
|
|
|
// CHECK-LABEL: sil [readonly] @test_effect_attribute_readonly_indirect_result
|
|
// CHECK-NEXT: [%0: write v**]
|
|
// CHECK-NEXT: [%1: copy v**]
|
|
// CHECK-NEXT: [global: ]
|
|
// CHECK-NEXT: {{^[^[]}}
|
|
// CHECK-LABEL: } // end sil function 'test_effect_attribute_readonly_indirect_result'
|
|
sil [readonly] @test_effect_attribute_readonly_indirect_result : $@convention(thin) (@guaranteed X) -> @out X {
|
|
bb0(%0 : $*X, %1 : $X):
|
|
strong_retain %1 : $X
|
|
store %1 to %0 : $*X
|
|
|
|
%r = tuple ()
|
|
return %r : $()
|
|
}
|