Files
swift-mirror/test/SILOptimizer/mem-behavior.sil
Erik Eckstein f9b524b1cb AliasAnalysis: a complete overhaul of alias- and memory-behavior analysis
The main changes are:

*) Rewrite everything in swift. So far, parts of memory-behavior analysis were already implemented in swift. Now everything is done in swift and lives in `AliasAnalysis.swift`. This is a big code simplification.

*) Support many more instructions in the memory-behavior analysis - especially OSSA instructions, like `begin_borrow`, `end_borrow`, `store_borrow`, `load_borrow`. The computation of end_borrow effects is now much more precise. Also, partial_apply is now handled more precisely.

*) Simplify and reduce type-based alias analysis (TBAA). The complexity of the old TBAA comes from old days where the language and SIL didn't have strict aliasing and exclusivity rules (e.g. for inout arguments). Now TBAA is only needed for code using unsafe pointers. The new TBAA handles this - and not more. Note that TBAA for classes is already done in `AccessBase.isDistinct`.

*) Handle aliasing in `begin_access [modify]` scopes. We already supported truly immutable scopes like `begin_access [read]` or `ref_element_addr [immutable]`. For `begin_access [modify]` we know that there are no other reads or writes to the access-address within the scope.

*) Don't cache memory-behavior results. It turned out that the hit-miss rate was pretty bad (~ 1:7). The overhead of the cache lookup took as long as recomputing the memory behavior.
2024-07-29 17:33:46 +02:00

1500 lines
53 KiB
Plaintext

// RUN: %target-sil-opt %s -dump-mem-behavior -o /dev/null | %FileCheck %s
// REQUIRES: asserts
// REQUIRES: swift_in_compiler
import Builtin
import Swift
class X {
@_hasStorage var a: Int32
@_hasStorage var x: X
init()
}
class Derived : X { }
class C {
@_hasStorage @_hasInitialValue final var prop: Builtin.Int32 { get }
}
class Parent {
@_hasStorage var child: C { get set }
}
sil @unknown_func : $@convention(thin) (Int32, @in_guaranteed Int32) -> ()
sil @single_indirect_arg : $@convention(thin) (@in_guaranteed Int32) -> Int32
sil @single_indirect_arg_and_error : $@convention(thin) (@in Int32) -> (Int32, @error Error)
sil @single_indirect_arg_coroutine : $@yield_once @convention(thin) (@in Int32) -> @yields Int32
sil @indirect_arg_and_ptr : $@convention(thin) (@in_guaranteed Int32, Builtin.RawPointer) -> Int32
sil @single_reference : $@convention(thin) (@guaranteed X) -> Int32
sil @indirect_yield_coroutine : $@yield_once @convention(thin) (@inout Int32) -> @yields @inout Int32
sil @nouser_func : $@convention(thin) () -> ()
sil @in_ptr : $@convention(thin) (@in Builtin.RawPointer) -> ()
sil @init_C : $@convention(thin) () -> @out C
sil @read_C : $@convention(thin) (@in_guaranteed C) -> ()
sil @store_to_int : $@convention(thin) (Int32, @inout Int32) -> () {
[%1: write v**]
[global: ]
bb0(%0 : $Int32, %1 : $*Int32):
store %0 to %1 : $*Int32
%r = tuple ()
return %r : $()
}
sil @store_to_x_a : $@convention(thin) (Int32, @guaranteed X) -> () {
[%1: noescape **, write **]
[global: ]
bb0(%0 : $Int32, %1 : $X):
%2 = ref_element_addr %1 : $X, #X.a
store %0 to %2 : $*Int32
%r = tuple ()
return %r : $()
}
sil @only_retain : $@convention(thin) (@guaranteed X) -> () {
bb0(%0 : $X):
strong_retain %0 : $X
%r = tuple ()
return %r : $()
}
sil @read_from_raw_pointer : $@convention(thin) (Builtin.RawPointer) -> UInt8 {
[%0: read v**]
[global: ]
bb0(%0 : $Builtin.RawPointer):
%1 = pointer_to_address %0 : $Builtin.RawPointer to [strict] $*UInt8
%2 = load %1 : $*UInt8
return %2 : $UInt8
}
// CHECK-LABEL: @call_unknown_func
// CHECK: PAIR #0.
// CHECK-NEXT: %4 = apply %3(%0, %1) : $@convention(thin) (Int32, @in_guaranteed Int32) -> ()
// CHECK-NEXT: %1 = argument of bb0 : $*Int32{{.*}}
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%0, %1) : $@convention(thin) (Int32, @in_guaranteed Int32) -> ()
// CHECK-NEXT: %2 = argument of bb0 : $*Int32
// CHECK-NEXT: r=0,w=0
sil @call_unknown_func : $@convention(thin) (Int32, @in Int32, @in Int32) -> () {
bb0(%0 : $Int32, %1 : $*Int32, %2 : $*Int32):
%3 = function_ref @unknown_func : $@convention(thin) (Int32, @in_guaranteed Int32) -> ()
%4 = apply %3(%0, %1) : $@convention(thin) (Int32, @in_guaranteed Int32) -> ()
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @call_store_to_int_not_aliased
// CHECK: PAIR #0.
// CHECK-NEXT: %4 = apply %3(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
// CHECK-NEXT: %1 = argument of bb0 : $*Int32{{.*}}
// CHECK-NEXT: r=0,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
// CHECK-NEXT: %2 = argument of bb0 : $*Int32
// CHECK-NEXT: r=0,w=0
sil @call_store_to_int_not_aliased : $@convention(thin) (Int32, @inout Int32, @in Int32) -> () {
bb0(%0 : $Int32, %1 : $*Int32, %2 : $*Int32):
%3 = function_ref @store_to_int : $@convention(thin) (Int32, @inout Int32) -> ()
%4 = apply %3(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @call_store_to_int_aliased
// CHECK: PAIR #0.
// CHECK-NEXT: %6 = apply %5(%0, %3) : $@convention(thin) (Int32, @inout Int32) -> ()
// CHECK-NEXT: %3 = ref_element_addr %1 : $X, #X.a{{.*}}
// CHECK-NEXT: r=0,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %6 = apply %5(%0, %3) : $@convention(thin) (Int32, @inout Int32) -> ()
// CHECK-NEXT: %4 = ref_element_addr %2 : $X, #X.a
// CHECK-NEXT: r=0,w=1
sil @call_store_to_int_aliased : $@convention(thin) (Int32, @guaranteed X, @guaranteed X) -> () {
bb0(%0 : $Int32, %1 : $X, %2 : $X):
%3 = ref_element_addr %1 : $X, #X.a
%4 = ref_element_addr %2 : $X, #X.a
%5 = function_ref @store_to_int : $@convention(thin) (Int32, @inout Int32) -> ()
%6 = apply %5(%0, %3) : $@convention(thin) (Int32, @inout Int32) -> ()
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @alias_class_member
// CHECK: PAIR #0.
// CHECK-NEXT: %5 = apply %4(%0, %1) : $@convention(thin) (Int32, @guaranteed X) -> ()
// CHECK-NEXT: %2 = ref_element_addr %1 : $X, #X.a
// CHECK-NEXT: r=0,w=1
sil @alias_class_member : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = alloc_ref $X
%2 = ref_element_addr %1 : $X, #X.a
fix_lifetime %2 : $*Int32
%4 = function_ref @store_to_x_a : $@convention(thin) (Int32, @guaranteed X) -> ()
%5 = apply %4(%0, %1) : $@convention(thin) (Int32, @guaranteed X) -> ()
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @alias_unknown_class_member
// CHECK: PAIR #0.
// CHECK-NEXT: %6 = apply %5(%0, %2) : $@convention(thin) (Int32, @guaranteed X) -> ()
// CHECK-NEXT: %3 = ref_element_addr %1 : $X, #X.a
// CHECK-NEXT: r=0,w=1
sil @alias_unknown_class_member : $@convention(thin) (Int32, @guaranteed X, @guaranteed X) -> () {
bb0(%0 : $Int32, %1 : $X, %2 : $X):
%3 = ref_element_addr %1 : $X, #X.a
fix_lifetime %3 : $*Int32
%5 = function_ref @store_to_x_a : $@convention(thin) (Int32, @guaranteed X) -> ()
%6 = apply %5(%0, %2) : $@convention(thin) (Int32, @guaranteed X) -> ()
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @no_alias_to_unknown_class
// CHECK: PAIR #0.
// CHECK-NEXT: %6 = apply %5(%0, %1) : $@convention(thin) (Int32, @guaranteed X) -> ()
// CHECK-NEXT: %3 = ref_element_addr %2 : $X, #X.a
// CHECK-NEXT: r=0,w=0
sil @no_alias_to_unknown_class : $@convention(thin) (Int32, @guaranteed X) -> () {
bb0(%0 : $Int32, %1 : $X):
%2 = alloc_ref $X
%3 = ref_element_addr %2 : $X, #X.a
fix_lifetime %3 : $*Int32
%5 = function_ref @store_to_x_a : $@convention(thin) (Int32, @guaranteed X) -> ()
%6 = apply %5(%0, %1) : $@convention(thin) (Int32, @guaranteed X) -> ()
%r = tuple ()
return %r : $()
}
sil @call_only_retain : $@convention(thin) (@guaranteed X, @guaranteed X) -> () {
bb0(%0 : $X, %1 : $X):
%2 = function_ref @only_retain : $@convention(thin) (@guaranteed X) -> ()
%3 = apply %2(%0) : $@convention(thin) (@guaranteed X) -> ()
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @allocstack_apply_no_side_effect
// CHECK: PAIR #0
// CHECK-NEXT: %3 = apply %2() : $@convention(thin) () -> ()
// CHECK-NEXT: %1 = alloc_stack $Int32{{.*}}
// CHECK-NEXT: r=0,w=0
sil @allocstack_apply_no_side_effect : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = alloc_stack $Int32
%2 = function_ref @nouser_func : $@convention(thin) () -> ()
%3 = apply %2() : $@convention(thin) () -> ()
%4 = tuple ()
dealloc_stack %1 : $*Int32
return %4 : $()
}
// CHECK-LABEL: @allocstack_apply_side_effect
// CHECK: PAIR #0.
// CHECK-NEXT: %3 = apply %2(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=0,w=1
sil @allocstack_apply_side_effect : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = alloc_stack $Int32
// function_ref store_to_int
%2 = function_ref @store_to_int : $@convention(thin) (Int32, @inout Int32) -> ()
%3 = apply %2(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
%4 = tuple ()
dealloc_stack %1 : $*Int32
return %4 : $()
}
// CHECK-LABEL: @allocstack_apply_no_escaping
// CHECK: PAIR #0.
// CHECK-NEXT: %3 = apply %2() : $@convention(thin) () -> ()
// CHECK-NEXT: %1 = alloc_stack $Int32{{.*}}
// CHECK-NEXT: r=0,w=0
sil @allocstack_apply_no_escaping : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = alloc_stack $Int32
%2 = function_ref @nouser_func : $@convention(thin) () -> ()
%3 = apply %2() : $@convention(thin) () -> ()
%4 = function_ref @store_to_int: $@convention(thin) (Int32, @inout Int32) -> ()
%5 = apply %4(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
%6 = tuple ()
dealloc_stack %1 : $*Int32
return %6 : $()
}
// CHECK-LABEL: @allocstack_apply_read_only
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%1) : $@convention(thin) (@in_guaranteed X) -> ()
// CHECK-NEXT: %1 = alloc_stack $X{{.*}}
// CHECK-NEXT: r=1,w=0
sil @allocstack_apply_read_only : $@convention(thin) (X) -> () {
bb0(%0 : $X):
%1 = alloc_stack $X
store %0 to %1 : $*X
%3 = function_ref @load_from_in : $@convention(thin) (@in_guaranteed X) -> ()
%4 = apply %3(%1) : $@convention(thin) (@in_guaranteed X) -> ()
dealloc_stack %1 : $*X
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: @allocstack_and_copyaddr
// CHECK: PAIR #2.
// CHECK-NEXT: %4 = apply %3(%0) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #3.
// CHECK-NEXT: %4 = apply %3(%0) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=0,w=0
sil @allocstack_and_copyaddr : $@convention(thin) (@in Int32) -> Int32 {
bb0(%0 : $*Int32):
%1 = alloc_stack $Int32
copy_addr %0 to %1 : $*Int32
%3 = function_ref @single_indirect_arg : $@convention(thin) (@in_guaranteed Int32) -> Int32
%4 = apply %3(%0) : $@convention(thin) (@in_guaranteed Int32) -> Int32
dealloc_stack %1 : $*Int32
return %4 : $Int32
}
// CHECK-LABEL: @inout_and_copyaddr
// CHECK: PAIR #2.
// CHECK-NEXT: %4 = apply %3(%0) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #3.
// CHECK-NEXT: %4 = apply %3(%0) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %1 = argument of bb0 : $*Int32
// CHECK-NEXT: r=0,w=0
sil @inout_and_copyaddr : $@convention(thin) (@in Int32, @inout Int32) -> Int32 {
bb0(%0 : $*Int32, %1 : $*Int32):
copy_addr %0 to %1 : $*Int32
%3 = function_ref @single_indirect_arg : $@convention(thin) (@in_guaranteed Int32) -> Int32
%4 = apply %3(%0) : $@convention(thin) (@in_guaranteed Int32) -> Int32
return %4 : $Int32
}
// CHECK-LABEL: @escaping_allocstack_and_copyaddr
// CHECK: PAIR #2.
// CHECK-NEXT: %5 = apply %4(%0, %3) : $@convention(thin) (@in_guaranteed Int32, Builtin.RawPointer) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #3.
// CHECK-NEXT: %5 = apply %4(%0, %3) : $@convention(thin) (@in_guaranteed Int32, Builtin.RawPointer) -> Int32
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=1,w=1
sil @escaping_allocstack_and_copyaddr : $@convention(thin) (@in Int32) -> Int32 {
bb0(%0 : $*Int32):
%1 = alloc_stack $Int32
copy_addr %0 to %1 : $*Int32
%3 = address_to_pointer %1 : $*Int32 to $Builtin.RawPointer
%4 = function_ref @indirect_arg_and_ptr : $@convention(thin) (@in_guaranteed Int32, Builtin.RawPointer) -> Int32
%5 = apply %4(%0, %3) : $@convention(thin) (@in_guaranteed Int32, Builtin.RawPointer) -> Int32
dealloc_stack %1 : $*Int32
return %5 : $Int32
}
// CHECK-LABEL: @escaping_allocstack_to_known_function
// CHECK: PAIR #1.
// CHECK-NEXT: %5 = apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> UInt8
// CHECK-NEXT: %1 = alloc_stack $UInt8
// CHECK-NEXT: r=1,w=0
sil @escaping_allocstack_to_known_function : $@convention(thin) (UInt8) -> UInt8 {
bb0(%0 : $UInt8):
%1 = alloc_stack $UInt8
store %0 to %1 : $*UInt8
%3 = address_to_pointer %1 : $*UInt8 to $Builtin.RawPointer
%4 = function_ref @read_from_raw_pointer : $@convention(thin) (Builtin.RawPointer) -> UInt8
%5 = apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> UInt8
dealloc_stack %1 : $*UInt8
return %5 : $UInt8
}
// CHECK-LABEL: @tryapply_allocstack_and_copyaddr
// CHECK: PAIR #2.
// CHECK-NEXT: try_apply %3(%0) : $@convention(thin) (@in Int32) -> (Int32, @error any Error), normal bb1, error bb2
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #3.
// CHECK-NEXT: try_apply %3(%0) : $@convention(thin) (@in Int32) -> (Int32, @error any Error), normal bb1, error bb2
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=0,w=0
sil @tryapply_allocstack_and_copyaddr : $@convention(thin) (@in Int32) -> Int32 {
bb0(%0 : $*Int32):
%1 = alloc_stack $Int32
copy_addr %0 to %1 : $*Int32
%3 = function_ref @single_indirect_arg_and_error : $@convention(thin) (@in Int32) -> (Int32, @error Error)
try_apply %3(%0) : $@convention(thin) (@in Int32) -> (Int32, @error Error), normal bb1, error bb2
bb1(%5 : $Int32):
dealloc_stack %1 : $*Int32
return %5 : $Int32
bb2(%8 : $Error):
unreachable
}
// CHECK-LABEL: @beginapply_allocstack_and_copyaddr
// CHECK: PAIR #2.
// CHECK-NEXT: (%4, %5) = begin_apply %3(%0) : $@yield_once @convention(thin) (@in Int32) -> @yields Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #3.
// CHECK-NEXT: (%4, %5) = begin_apply %3(%0) : $@yield_once @convention(thin) (@in Int32) -> @yields Int32
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #4.
// CHECK-NEXT: end_apply %5
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #5.
// CHECK-NEXT: end_apply %5
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #6.
// CHECK-NEXT: abort_apply %5
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #7.
// CHECK-NEXT: abort_apply %5
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=0,w=0
sil @beginapply_allocstack_and_copyaddr : $@convention(thin) (@in Int32) -> Int32 {
bb0(%0 : $*Int32):
%1 = alloc_stack $Int32
copy_addr %0 to %1 : $*Int32
%3 = function_ref @single_indirect_arg_coroutine : $@yield_once @convention(thin) (@in Int32) -> @yields Int32
(%4, %5) = begin_apply %3(%0) : $@yield_once @convention(thin) (@in Int32) -> @yields Int32
cond_br undef, bb1, bb2
bb1:
end_apply %5 as $()
dealloc_stack %1 : $*Int32
return %4 : $Int32
bb2:
abort_apply %5
unreachable
}
// CHECK-LABEL: @test_indirect_yield
// CHECK: PAIR #3.
// CHECK-NEXT: store %0 to %4 : $*Int32
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=0,w=1
sil @test_indirect_yield : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = alloc_stack $Int32
store %0 to %1 : $*Int32
%3 = function_ref @indirect_yield_coroutine : $@yield_once @convention(thin) (@inout Int32) -> @yields @inout Int32
(%4, %5) = begin_apply %3(%1) : $@yield_once @convention(thin) (@inout Int32) -> @yields @inout Int32
store %0 to %4 : $*Int32
end_apply %5 as $()
dealloc_stack %1 : $*Int32
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: @refelementaddr_and_reference
// CHECK: PAIR #0.
// CHECK-NEXT: %3 = apply %2(%0) : $@convention(thin) (@guaranteed X) -> Int32
// CHECK-NEXT: %1 = ref_element_addr %0 : $X, #X.a
// CHECK-NEXT: r=1,w=1
sil @refelementaddr_and_reference : $@convention(thin) (@guaranteed X) -> Int32 {
bb0(%0 : $X):
%1 = ref_element_addr %0 : $X, #X.a
%2 = function_ref @single_reference : $@convention(thin) (@guaranteed X) -> Int32
%3 = apply %2(%0) : $@convention(thin) (@guaranteed X) -> Int32
return %3 : $Int32
}
// CHECK-LABEL: @apply_and_begin_access
// CHECK: PAIR #8.
// CHECK-NEXT: %6 = apply %5(%1) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=0,w=0
sil @apply_and_begin_access : $@convention(thin) (@in Int32) -> Int32 {
bb0(%0 : $*Int32):
%1 = alloc_stack $Int32
%2 = begin_access [read] [static] %0 : $*Int32
copy_addr %2 to %1 : $*Int32
end_access %2 : $*Int32
%5 = function_ref @single_indirect_arg : $@convention(thin) (@in_guaranteed Int32) -> Int32
%6 = apply %5(%1) : $@convention(thin) (@in_guaranteed Int32) -> Int32
dealloc_stack %1 : $*Int32
return %6 : $Int32
}
sil @load_from_in : $@convention(thin) (@in_guaranteed X) -> () {
bb0(%0 : $*X):
%1 = load %0 : $*X
%2 = tuple ()
return %2 : $()
}
struct TwoInts {
var i1 : Int32
var i2 : Int32
}
// CHECK-LABEL: @combination_of_read_and_write_effects
// CHECK: PAIR #0.
// CHECK-NEXT: %4 = apply %3(%1, %2) : $@convention(thin) (@inout Int32, @inout Int32) -> ()
// CHECK-NEXT: %0 = alloc_stack $TwoInts
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%1, %2) : $@convention(thin) (@inout Int32, @inout Int32) -> ()
// CHECK-NEXT: %1 = struct_element_addr %0 : $*TwoInts, #TwoInts.i1
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #2.
// CHECK-NEXT: %4 = apply %3(%1, %2) : $@convention(thin) (@inout Int32, @inout Int32) -> ()
// CHECK-NEXT: %2 = struct_element_addr %0 : $*TwoInts, #TwoInts.i2
// CHECK-NEXT: r=0,w=1
sil @combination_of_read_and_write_effects : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $TwoInts
%1 = struct_element_addr %0 : $*TwoInts, #TwoInts.i1
%2 = struct_element_addr %0 : $*TwoInts, #TwoInts.i2
%3 = function_ref @copy_ints : $@convention(thin) (@inout Int32, @inout Int32) -> ()
apply %3 (%1, %2) : $@convention(thin) (@inout Int32, @inout Int32) -> ()
dealloc_stack %0 : $*TwoInts
%r = tuple()
return %r : $()
}
// CHECK-LABEL: @non_overlapping_struct_fields
// CHECK: PAIR #0.
// CHECK-NEXT: %4 = apply %3(%1) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*TwoInts
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%1) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %1 = struct_element_addr %0 : $*TwoInts, #TwoInts.i1
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #2.
// CHECK-NEXT: %4 = apply %3(%1) : $@convention(thin) (@in_guaranteed Int32) -> Int32
// CHECK-NEXT: %2 = struct_element_addr %0 : $*TwoInts, #TwoInts.i2
// CHECK-NEXT: r=0,w=0
sil @non_overlapping_struct_fields : $@convention(thin) (@in TwoInts) -> Int32 {
bb0(%0 : $*TwoInts):
%1 = struct_element_addr %0 : $*TwoInts, #TwoInts.i1
%2 = struct_element_addr %0 : $*TwoInts, #TwoInts.i2
%3 = function_ref @single_indirect_arg : $@convention(thin) (@in_guaranteed Int32) -> Int32
%4 = apply %3(%1) : $@convention(thin) (@in_guaranteed Int32) -> Int32
return %4 : $Int32
}
sil @copy_ints : $@convention(thin) (@inout Int32, @inout Int32) -> () {
[%0: read v**]
[%1: write v**]
[global: ]
bb0(%0 : $*Int32, %1 : $*Int32):
%2 = load %0 : $*Int32
store %2 to %1 : $*Int32
%r = tuple()
return %r : $()
}
sil @test_in_guaranteed_only_fun_is_ro_callee : $@convention(thin) (@in_guaranteed Int) -> ()
// CHECK-LABEL: @test_in_guaranteed_only_fun_is_ro_entry
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = apply %1(%0) : $@convention(thin) (@in_guaranteed Int) -> ()
// CHECK-NEXT: %0 = argument of bb0 : $*Int
// CHECK-NEXT: r=1,w=0
sil @test_in_guaranteed_only_fun_is_ro_entry : $@convention(thin) (@in Int) -> () {
bb0(%0 : $*Int):
%f_callee = function_ref @test_in_guaranteed_only_fun_is_ro_callee : $@convention(thin) (@in_guaranteed Int) -> ()
%r1 = apply %f_callee(%0) : $@convention(thin) (@in_guaranteed Int) -> ()
%3 = tuple()
return %3 : $()
}
// Check the memory behavior of a read-only load relative to an
// unknown instruction with side effects.
//
// CHECK-LABEL: @testLetSideEffects
//
// The store does not affect the let-load (ref_element_addr).
// CHECK: PAIR #6.
// CHECK-NEXT: %6 = begin_access [modify] [static] %1 : $*Builtin.Int32
// CHECK-NEXT: %10 = ref_element_addr %9 : $C, #C.prop
// CHECK-NEXT: r=0,w=0
//
// Any unknown instructions with side effects does affect the let-load.
// CHECK: PAIR #22.
// CHECK-NEXT: end_borrow %{{.*}} : $C
// CHECK-NEXT: ref_element_addr %{{.*}} : $C, #C.prop
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #34.
// CHECK-NEXT: destroy_value %0 : $Parent
// CHECK-NEXT: ref_element_addr %{{.*}} : $C, #C.prop
// CHECK-NEXT: r=1,w=1
sil [ossa] @testLetSideEffects : $@convention(thin) (@owned Parent, @inout Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : @owned $Parent, %1 : $*Builtin.Int32):
%borrow1 = begin_borrow %0 : $Parent
%childAdr = ref_element_addr %borrow1 : $Parent, #Parent.child
%child = load_borrow %childAdr : $*C
%three = integer_literal $Builtin.Int32, 3
%access = begin_access [modify] [static] %1 : $*Builtin.Int32
store %three to [trivial] %access : $*Builtin.Int32
end_access %access : $*Builtin.Int32
%borrow2 = begin_borrow %child : $C
%propAdr = ref_element_addr %borrow2 : $C, #C.prop
%val = load [trivial] %propAdr : $*Builtin.Int32
end_borrow %borrow2 : $C
end_borrow %child : $C
end_borrow %borrow1 : $Parent
destroy_value %0 : $Parent
return %val : $Builtin.Int32
}
// Check the memory behavior of access markers.
//
// CHECK-LABEL: @testReadWriteAccess
// CHECK: PAIR #0.
// CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #5.
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #6.
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #7.
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #8.
// CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #9.
// CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #13.
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #14.
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #15.
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=1
sil [ossa] @testReadWriteAccess : $@convention(thin) (@inout Builtin.Int32) -> Builtin.Int32 {
bb0(%0 : $*Builtin.Int32):
%read = begin_access [read] [static] %0 : $*Builtin.Int32
%val = load [trivial] %read : $*Builtin.Int32
end_access %read : $*Builtin.Int32
%three = integer_literal $Builtin.Int32, 3
%write = begin_access [modify] [static] %0 : $*Builtin.Int32
store %three to [trivial] %write : $*Builtin.Int32
end_access %write : $*Builtin.Int32
return %val : $Builtin.Int32
}
// CHECK-LABEL: @testDeinitAccess
// CHECK: PAIR #0.
// CHECK-NEXT: %1 = begin_access [deinit] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: end_access %1 : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=1,w=1
sil [ossa] @testDeinitAccess : $@convention(thin) (@in Builtin.Int32) -> () {
bb0(%0 : $*Builtin.Int32):
%1 = begin_access [deinit] [static] %0 : $*Builtin.Int32
end_access %1 : $*Builtin.Int32
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @testInitAccess
// CHECK: PAIR #0.
// CHECK-NEXT: %{{.*}} = begin_access [init] [static] %0 : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=0,w=1
// CHECK: PAIR #3.
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
// CHECK-NEXT: r=0,w=1
sil [ossa] @testInitAccess : $@convention(thin) (Builtin.Int32) -> @out Builtin.Int32 {
bb0(%0 : $*Builtin.Int32, %1 : $Builtin.Int32):
%init = begin_access [init] [static] %0 : $*Builtin.Int32
store %1 to [trivial] %init : $*Builtin.Int32
end_access %init : $*Builtin.Int32
%val = load [trivial] %0 : $*Builtin.Int32
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @testReadAccessOfClassProperty
// CHECK: PAIR #3.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> ()
// CHECK-NEXT: %1 = ref_element_addr %0 : $X, #X.a
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #4.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> ()
// CHECK-NEXT: %2 = begin_access [read] [dynamic] %1 : $*Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #8.
// CHECK-NEXT: %7 = apply %4() : $@convention(thin) () -> ()
// CHECK-NEXT: %2 = begin_access [read] [dynamic] %1 : $*Int32
// CHECK-NEXT: r=1,w=1
sil [ossa] @testReadAccessOfClassProperty : $@convention(thin) (@guaranteed X) -> Int32 {
bb0(%0 : @guaranteed $X):
%1 = ref_element_addr %0 : $X, #X.a
%2 = begin_access [read] [dynamic] %1 : $*Int32
%3 = load [trivial] %2 : $*Int32
%4 = function_ref @nouser_func : $@convention(thin) () -> ()
%5 = apply %4() : $@convention(thin) () -> ()
end_access %2 : $*Int32
%7 = apply %4() : $@convention(thin) () -> ()
return %3 : $Int32
}
// CHECK-LABEL: @testModifyAccessOfClassProperty
// CHECK: PAIR #3.
// CHECK-NEXT: %6 = apply %5() : $@convention(thin) () -> ()
// CHECK-NEXT: %2 = ref_element_addr %0 : $X, #X.a
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #4.
// CHECK-NEXT: %6 = apply %5() : $@convention(thin) () -> ()
// CHECK-NEXT: %3 = begin_access [modify] [dynamic] %2 : $*Int32
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #8.
// CHECK-NEXT: %8 = apply %5() : $@convention(thin) () -> ()
// CHECK-NEXT: %3 = begin_access [modify] [dynamic] %2 : $*Int32
// CHECK-NEXT: r=1,w=1
sil [ossa] @testModifyAccessOfClassProperty : $@convention(thin) (@guaranteed X, Int32) -> () {
bb0(%0 : @guaranteed $X, %1 : $Int32):
%2 = ref_element_addr %0 : $X, #X.a
%3 = begin_access [modify] [dynamic] %2 : $*Int32
store %1 to [trivial] %3 : $*Int32
%5 = function_ref @nouser_func : $@convention(thin) () -> ()
%6 = apply %5() : $@convention(thin) () -> ()
end_access %3 : $*Int32
%8 = apply %5() : $@convention(thin) () -> ()
%9 = tuple ()
return %9 : $()
}
// CHECK-LABEL: @testImmutableRefWithGuaranteedParam
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3() : $@convention(thin) () -> ()
// CHECK-NEXT: %1 = ref_element_addr [immutable] %0 : $X, #X.a
// CHECK-NEXT: r=1,w=0
sil [ossa] @testImmutableRefWithGuaranteedParam : $@convention(thin) (@guaranteed X) -> Int32 {
bb0(%0 : @guaranteed $X):
%1 = ref_element_addr [immutable] %0 : $X, #X.a
%3 = load [trivial] %1 : $*Int32
%5 = function_ref @nouser_func : $@convention(thin) () -> ()
%6 = apply %5() : $@convention(thin) () -> ()
return %3 : $Int32
}
// CHECK-LABEL: @testNonOSSAImmutableRefWithGuaranteedParam
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3() : $@convention(thin) () -> ()
// CHECK-NEXT: %1 = ref_element_addr [immutable] %0 : $X, #X.a
// CHECK-NEXT: r=1,w=0
sil @testNonOSSAImmutableRefWithGuaranteedParam : $@convention(thin) (@guaranteed X) -> Int32 {
bb0(%0 : $X):
%1 = ref_element_addr [immutable] %0 : $X, #X.a
%3 = load %1 : $*Int32
%5 = function_ref @nouser_func : $@convention(thin) () -> ()
%6 = apply %5() : $@convention(thin) () -> ()
return %3 : $Int32
}
// CHECK-LABEL: @testImmutableRefWithBorrow
// CHECK: PAIR #1.
// CHECK-NEXT: %5 = apply %4() : $@convention(thin) () -> ()
// CHECK-NEXT: %2 = ref_element_addr [immutable] %1 : $X, #X.a
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #3.
// CHECK-NEXT: %7 = apply %4() : $@convention(thin) () -> ()
// CHECK-NEXT: %2 = ref_element_addr [immutable] %1 : $X, #X.a
// CHECK-NEXT: r=1,w=1
sil [ossa] @testImmutableRefWithBorrow : $@convention(thin) (@owned X) -> Int32 {
bb0(%0 : @owned $X):
%1 = begin_borrow %0 : $X
%2 = ref_element_addr [immutable] %1 : $X, #X.a
%3 = load [trivial] %2 : $*Int32
%4 = function_ref @nouser_func : $@convention(thin) () -> ()
%5 = apply %4() : $@convention(thin) () -> ()
end_borrow %1 : $X
%7 = apply %4() : $@convention(thin) () -> ()
destroy_value %0 : $X
return %3 : $Int32
}
// CHECK-LABEL: @testImmutableRefWithControlFlow
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = apply %1() : $@convention(thin) () -> ()
// CHECK-NEXT: %4 = ref_element_addr [immutable] %3 : $X, #X.a
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #2.
// CHECK-NEXT: %6 = apply %1() : $@convention(thin) () -> ()
// CHECK-NEXT: %4 = ref_element_addr [immutable] %3 : $X, #X.a
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #4.
// CHECK-NEXT: %9 = apply %1() : $@convention(thin) () -> ()
// CHECK-NEXT: %4 = ref_element_addr [immutable] %3 : $X, #X.a
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #5.
// CHECK-NEXT: %11 = apply %1() : $@convention(thin) () -> ()
// CHECK-NEXT: %4 = ref_element_addr [immutable] %3 : $X, #X.a
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #7.
// CHECK-NEXT: %14 = apply %1() : $@convention(thin) () -> ()
// CHECK-NEXT: %4 = ref_element_addr [immutable] %3 : $X, #X.a
// CHECK-NEXT: r=1,w=1
sil [ossa] @testImmutableRefWithControlFlow : $@convention(thin) (@owned X) -> Int32 {
bb0(%0 : @owned $X):
%1 = function_ref @nouser_func : $@convention(thin) () -> ()
%2 = apply %1() : $@convention(thin) () -> ()
%3 = begin_borrow %0 : $X
%4 = ref_element_addr [immutable] %3 : $X, #X.a
%5 = load [trivial] %4 : $*Int32
%6 = apply %1() : $@convention(thin) () -> ()
cond_br undef, bb1, bb2
bb1:
end_borrow %3 : $X
%9 = apply %1() : $@convention(thin) () -> ()
br bb4
bb2:
%11 = apply %1() : $@convention(thin) () -> ()
br bb3
bb3:
end_borrow %3 : $X
%14 = apply %1() : $@convention(thin) () -> ()
br bb4
bb4:
destroy_value %0 : $X
return %5 : $Int32
}
// CHECK-LABEL: @dontCrashWithOptionalNone
// CHECK: PAIR #0.
// CHECK-NEXT: %6 = apply %5() : $@convention(thin) () -> ()
// CHECK-NEXT: %4 = ref_element_addr [immutable] %3 : $X, #X.a
// CHECK-NEXT: r=0,w=0
sil @dontCrashWithOptionalNone : $@convention(thin) () -> () {
bb0:
%26 = enum $Optional<X>, #Optional.none!enumelt
switch_enum %26 : $Optional<X>, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2
bb1:
br bb3
bb2:
%68 = unchecked_enum_data %26 : $Optional<X>, #Optional.some!enumelt
%1 = ref_element_addr [immutable] %68 : $X, #X.a
%5 = function_ref @nouser_func : $@convention(thin) () -> ()
%6 = apply %5() : $@convention(thin) () -> ()
br bb3
bb3:
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @testLoadTake
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = load [take] %0 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = load [take] %0 : $*C
// CHECK-NEXT: %1 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=0
sil [ossa] @testLoadTake : $@convention(thin) (@in C, @in_guaranteed C) -> @owned C {
bb0(%0 : $*C, %1 : $*C):
%2 = load [take] %0 : $*C
return %2 : $C
}
sil_global hidden [let] @globalC : $C
sil_global hidden @globalCVar : $C
// CHECK-LABEL: @testGlobalLet
// CHECK: PAIR #1.
// CHECK-NEXT: %3 = apply %2() : $@convention(thin) () -> ()
// CHECK-NEXT: %0 = global_addr @globalC : $*C
// CHECK-NEXT: r=1,w=0
sil hidden @testGlobalLet : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalC : $*C
%1 = load %0 : $*C
%2 = function_ref @nouser_func : $@convention(thin) () -> ()
%3 = apply %2() : $@convention(thin) () -> ()
%4 = function_ref @read_C : $@convention(thin) (@in_guaranteed C) -> ()
%5 = apply %4(%0) : $@convention(thin) (@in_guaranteed C) -> ()
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: @testInitGlobalLet
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = apply %1(%0) : $@convention(thin) () -> @out C
// CHECK-NEXT: %0 = global_addr @globalC : $*C
// CHECK-NEXT: r=1,w=1
sil hidden @testInitGlobalLet : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalC : $*C
%1 = function_ref @init_C : $@convention(thin) () -> @out C
%2 = apply %1(%0) : $@convention(thin) () -> @out C
%3 = load %0 : $*C
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: @testGlobalVar
// CHECK: PAIR #1.
// CHECK-NEXT: %3 = apply %2() : $@convention(thin) () -> ()
// CHECK-NEXT: %0 = global_addr @globalCVar : $*C
// CHECK-NEXT: r=1,w=1
sil hidden @testGlobalVar : $@convention(thin) () -> () {
bb0:
%0 = global_addr @globalCVar : $*C
%1 = load %0 : $*C
%2 = function_ref @nouser_func : $@convention(thin) () -> ()
%3 = apply %2() : $@convention(thin) () -> ()
%8 = tuple ()
return %8 : $()
}
// ===-----------------------------------------------------------------------===
// Test the effect of a [deinit] access on a global 'let'
//
// Test <rdar://60046018> Assert: (v->getType().isAddress()), getAccessedAddress
// CHECK-LABEL: @testDeinitInstVsNonAddressValue
// CHECK: PAIR #3.
// CHECK-NEXT: load %{{.*}} : $*C
// CHECK-NEXT: begin_access [deinit] [static] %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: r=0,w=0
sil hidden @testDeinitInstVsNonAddressValue : $@convention(thin) (@guaranteed C) -> () {
bb0(%0 : $C):
%1 = global_addr @globalC : $*C
%2 = load %1 : $*C
%3 = ref_element_addr %2 : $C, #C.prop
%4 = load %3 : $*Builtin.Int32
%5 = ref_element_addr %0 : $C, #C.prop
%6 = begin_access [deinit] [static] %5 : $*Builtin.Int32
end_access %6 : $*Builtin.Int32
%8 = tuple ()
return %8 : $()
}
// ===-----------------------------------------------------------------------===
// Test that isLetAccess does not assert on nested access markers with
// interprosed projections.
struct Int64Wrapper {
var val : Int64
}
// CHECK-LABEL: @testNestedAccessWithInterposedProjection
// CHECK: PAIR #2.
// CHECK-NEXT: %1 = begin_access [modify] [static] %0 : $*Int64Wrapper
// CHECK-NEXT: %3 = begin_access [read] [static] %2 : $*Int64
// CHECK-NEXT: r=1,w=1
sil @testNestedAccessWithInterposedProjection : $@convention(thin) (@inout Int64Wrapper) -> () {
bb0(%0 : $*Int64Wrapper):
%1 = begin_access [modify] [static] %0 : $*Int64Wrapper
%2 = struct_element_addr %1 : $*Int64Wrapper, #Int64Wrapper.val
%3 = begin_access [read] [static] %2 : $*Int64
%4 = struct_element_addr %3 : $*Int64, #Int64._value
%5 = load %4 : $*Builtin.Int64
end_access %3 : $*Int64
end_access %1 : $*Int64Wrapper
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: @test_copy_addr_initialize
// CHECK: PAIR #0.
// CHECK-NEXT: copy_addr %1 to [init] %0 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: copy_addr %1 to [init] %0 : $*C
// CHECK-NEXT: %1 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #2.
// CHECK-NEXT: copy_addr %1 to [init] %0 : $*C
// CHECK-NEXT: %2 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=0
sil @test_copy_addr_initialize : $@convention(thin) (@inout C, @inout C) -> @out C {
bb0(%0 : $*C, %1 : $*C, %2: $*C):
copy_addr %1 to [init] %0 : $*C
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: @test_copy_addr_assign
// CHECK: PAIR #0.
// CHECK-NEXT: copy_addr %1 to %0 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: copy_addr %1 to %0 : $*C
// CHECK-NEXT: %1 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #2.
// CHECK-NEXT: copy_addr %1 to %0 : $*C
// CHECK-NEXT: %2 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=0
sil @test_copy_addr_assign : $@convention(thin) (@inout C, @inout C, @inout C) -> () {
bb0(%0 : $*C, %1 : $*C, %2: $*C):
copy_addr %1 to %0 : $*C
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: @test_copy_addr_take
// CHECK: PAIR #0.
// CHECK-NEXT: copy_addr [take] %1 to [init] %0 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: copy_addr [take] %1 to [init] %0 : $*C
// CHECK-NEXT: %1 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #2.
// CHECK-NEXT: copy_addr [take] %1 to [init] %0 : $*C
// CHECK-NEXT: %2 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=0
sil @test_copy_addr_take : $@convention(thin) (@in C, @inout C) -> @out C {
bb0(%0 : $*C, %1 : $*C, %2: $*C):
copy_addr [take] %1 to [init] %0 : $*C
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: @test_destroy_value
// CHECK: PAIR #0.
// CHECK-NEXT: %1 = load [copy] %0 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: destroy_value %1 : $C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=0
sil [ossa] @test_destroy_value : $@convention(thin) (@in C) -> () {
bb0 (%0 : $*C):
%1 = load [copy] %0 : $*C
destroy_value %1 : $C
destroy_addr %0 : $*C
%2 = tuple()
return %2 : $()
}
// CHECK-LABEL: @test_copy_value
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = copy_value %1 : $C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=0
sil [ossa] @test_copy_value : $@convention(thin) (@in C) -> () {
bb0 (%0 : $*C):
%1 = load [copy] %0 : $*C
%2 = copy_value %1 : $C
destroy_value %1 : $C
destroy_value %2 : $C
destroy_addr %0 : $*C
%3 = tuple()
return %3 : $()
}
sil @do_store : $@convention(thin) (@guaranteed Parent) -> () {
[%0: noescape **, read c0.v**]
[global: write]
}
// CHECK-LABEL: @test_double_class_indirection
// CHECK: PAIR #4.
// CHECK-NEXT: %8 = apply %7(%1) : $@convention(thin) (@guaranteed Parent) -> ()
// CHECK-NEXT: %3 = ref_element_addr %1 : $Parent, #Parent.child
// CHECK-NEXT: r=1,w=0
// CHECK-NEXT: PAIR #5.
// CHECK-NEXT: %8 = apply %7(%1) : $@convention(thin) (@guaranteed Parent) -> ()
// CHECK-NEXT: %5 = ref_element_addr %2 : $C, #C.prop
// CHECK-NEXT: r=1,w=1
sil @test_double_class_indirection : $@convention(thin) (Builtin.Int32) -> () {
bb0(%0 : $Builtin.Int32):
%1 = alloc_ref $Parent
%2 = alloc_ref $C
%3 = ref_element_addr %1 : $Parent, #Parent.child
store %2 to %3 : $*C
%5 = ref_element_addr %2 : $C, #C.prop
store %0 to %5 : $*Builtin.Int32
%f = function_ref @do_store : $@convention(thin) (@guaranteed Parent) -> ()
%a = apply %f(%1) : $@convention(thin) (@guaranteed Parent) -> ()
%r = tuple ()
return %r : $()
}
sil_global @gi : $Int
sil @g_init : $@convention(c) () -> ()
// CHECK-LABEL: @test_builtin_once
// CHECK: PAIR #0.
// CHECK-NEXT: %4 = builtin "once"(%0 : $Builtin.RawPointer, %3 : $@convention(c) () -> ()) : $()
// CHECK-NEXT: %1 = global_addr @gi : $*Int
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = builtin "once"(%0 : $Builtin.RawPointer, %3 : $@convention(c) () -> ()) : $()
// CHECK-NEXT: %2 = alloc_stack $Int
// CHECK-NEXT: r=0,w=0
sil @test_builtin_once : $@convention(thin) (Builtin.RawPointer) -> () {
bb0(%0 : $Builtin.RawPointer):
%1 = global_addr @gi : $*Int
%2 = alloc_stack $Int
%3 = function_ref @g_init : $@convention(c) () -> ()
%4 = builtin "once"(%0 : $Builtin.RawPointer, %3 : $@convention(c) () -> ()) : $()
dealloc_stack %2 : $*Int
%6 = tuple ()
return %6 : $()
}
// CHECK-LABEL: @test_debug_value
// CHECK: PAIR #0.
// CHECK-NEXT: debug_value %0 : $*Int, let, name "x"
// CHECK-NEXT: %0 = alloc_stack $Int
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: debug_value %0 : $*Int, let, name "x"
// CHECK-NEXT: %1 = alloc_stack $Int
// CHECK-NEXT: r=0,w=0
sil @test_debug_value : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Int
%1 = alloc_stack $Int
debug_value %0 : $*Int, let, name "x"
dealloc_stack %1 : $*Int
dealloc_stack %0 : $*Int
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @test_store_assign
// CHECK: PAIR #0.
// CHECK-NEXT: store %2 to [assign] %0 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: store %2 to [assign] %0 : $*C
// CHECK-NEXT: %1 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #2.
// CHECK-NEXT: store %2 to [assign] %0 : $*C
// CHECK-NEXT: %3 = global_addr @globalC : $*C
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #3.
// CHECK-NEXT: store %2 to [assign] %0 : $*C
// CHECK-NEXT: %4 = global_addr @globalCVar : $*C
// CHECK-NEXT: r=1,w=1
sil [ossa] @test_store_assign : $@convention(thin) (@inout C, @inout C, @owned C) -> () {
bb0(%0 : $*C, %1 : $*C, %2 : @owned $C):
%3 = global_addr @globalC : $*C
%4 = global_addr @globalCVar : $*C
store %2 to [assign] %0 : $*C
%r = tuple ()
return %r : $()
}
// CHECK-LABEL: @test_builtin_zeroInitializer
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %0 = alloc_stack
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %1 = alloc_stack
// CHECK-NEXT: r=0,w=1
sil @test_builtin_zeroInitializer : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $C
%1 = alloc_stack $C
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
copy_addr [take] %1 to [init] %0 : $*C
dealloc_stack %1 : $*C
destroy_addr %0 : $*C
dealloc_stack %0 : $*C
%4 = tuple ()
return %4 : $()
}
// CHECK-LABEL: @test_builtin_zeroInitializer_atomicload
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %0 = alloc_stack
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %1 = alloc_stack
// CHECK-NEXT: r=0,w=1
sil @test_builtin_zeroInitializer_atomicload : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = alloc_stack $C
%1 = alloc_stack $C
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
copy_addr [take] %1 to [init] %0 : $*C
dealloc_stack %1 : $*C
%4 = address_to_pointer %0 : $*C to $Builtin.RawPointer
%5 = builtin "atomicload_monotonic_Int64"(%4 : $Builtin.RawPointer) : $Builtin.Int64
destroy_addr %0 : $*C
dealloc_stack %0 : $*C
return %5 : $Builtin.Int64
}
// CHECK-LABEL: @test_builtin_zeroInitializer_atomicstore
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %0 = alloc_stack
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %1 = alloc_stack
// CHECK-NEXT: r=0,w=1
sil @test_builtin_zeroInitializer_atomicstore : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $C
%1 = alloc_stack $C
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
copy_addr [take] %1 to [init] %0 : $*C
dealloc_stack %1 : $*C
%4 = address_to_pointer %0 : $*C to $Builtin.RawPointer
%5 = integer_literal $Builtin.Int64, 1
%6 = builtin "atomicstore_monotonic_Int64"(%4 : $Builtin.RawPointer, %5 : $Builtin.Int64) : $()
destroy_addr %0 : $*C
dealloc_stack %0 : $*C
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @test_builtin_zeroInitializer_atomicrmw
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %0 = alloc_stack
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %1 = alloc_stack
// CHECK-NEXT: r=0,w=1
sil @test_builtin_zeroInitializer_atomicrmw : $@convention(thin) () -> (Builtin.Int64, Builtin.Int64) {
bb0:
%0 = alloc_stack $C
%1 = alloc_stack $C
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
copy_addr [take] %1 to [init] %0 : $*C
dealloc_stack %1 : $*C
%4 = address_to_pointer %0 : $*C to $Builtin.RawPointer
%5 = integer_literal $Builtin.Int64, 1
%6 = builtin "atomicrmw_xchg_monotonic_Int64"(%4 : $Builtin.RawPointer, %5 : $Builtin.Int64) : $Builtin.Int64
%7 = builtin "atomicrmw_add_monotonic_Int64"(%4 : $Builtin.RawPointer, %5 : $Builtin.Int64) : $Builtin.Int64
destroy_addr %0 : $*C
dealloc_stack %0 : $*C
%8 = tuple (%6 : $Builtin.Int64, %7 : $Builtin.Int64)
return %8 : $(Builtin.Int64, Builtin.Int64)
}
// CHECK-LABEL: @test_builtin_zeroInitializer_cmpxchg
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %0 = alloc_stack
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %1 = alloc_stack
// CHECK-NEXT: r=0,w=1
sil @test_builtin_zeroInitializer_cmpxchg : $@convention(thin) () -> (Builtin.Int64, Builtin.Int1) {
bb0:
%0 = alloc_stack $C
%1 = alloc_stack $C
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
copy_addr [take] %1 to [init] %0 : $*C
dealloc_stack %1 : $*C
%4 = address_to_pointer %0 : $*C to $Builtin.RawPointer
%5 = integer_literal $Builtin.Int64, 1
%6 = builtin "cmpxchg_monotonic_monotonic_Int64"(%4 : $Builtin.RawPointer, %5 : $Builtin.Int64) : $(Builtin.Int64, Builtin.Int1)
destroy_addr %0 : $*C
dealloc_stack %0 : $*C
return %6 : $(Builtin.Int64, Builtin.Int1)
}
// CHECK-LABEL: @test_builtin_zeroInitializer_fence
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %0 = alloc_stack
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = builtin "zeroInitializer"<C>(%1 : $*C)
// CHECK-NEXT: %1 = alloc_stack
// CHECK-NEXT: r=0,w=1
sil @test_builtin_zeroInitializer_fence : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $C
%1 = alloc_stack $C
%2 = builtin "zeroInitializer"<C>(%1 : $*C) : $()
%3 = apply undef<C>(%1) : $@convention(thin) <C> () -> @out C
copy_addr [take] %1 to [init] %0 : $*C
dealloc_stack %1 : $*C
%5 = builtin "fence_release"() : $()
destroy_addr %0 : $*C
dealloc_stack %0 : $*C
return %5 : $()
}
// CHECK-LABEL: @test_stored_pointer
// CHECK: PAIR #2.
// CHECK-NEXT: %5 = apply %4(%2) : $@convention(thin) (@in Builtin.RawPointer) -> ()
// CHECK-NEXT: %0 = alloc_stack $Int
// CHECK-NEXT: r=1,w=1
sil @test_stored_pointer : $@convention(thin) () -> () {
bb0:
%0 = alloc_stack $Int
%1 = address_to_pointer %0 : $*Int to $Builtin.RawPointer
%2 = alloc_stack $Builtin.RawPointer
store %1 to %2 : $*Builtin.RawPointer
%4 = function_ref @in_ptr : $@convention(thin) (@in Builtin.RawPointer) -> ()
%5 = apply %4(%2) : $@convention(thin) (@in Builtin.RawPointer) -> ()
dealloc_stack %2 : $*Builtin.RawPointer
dealloc_stack %0 : $*Int
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: @test_store_borrow
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = store_borrow %0 to %1 : $*X
// CHECK-NEXT: %1 = alloc_stack $X
// CHECK-NEXT: r=0,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: end_borrow %2 : $*X
// CHECK-NEXT: %1 = alloc_stack $X
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #2.
// CHECK-NEXT: end_borrow %2 : $*X
// CHECK-NEXT: %2 = store_borrow %0 to %1 : $*X
// CHECK-NEXT: r=1,w=1
sil [ossa] @test_store_borrow : $@convention(thin) (@guaranteed X) -> () {
bb0(%0 : @guaranteed $X):
%1 = alloc_stack $X
%2 = store_borrow %0 to %1 : $*X
end_borrow %2 : $*X
dealloc_stack %1 : $*X
%7 = tuple ()
return %7 : $()
}
// CHECK-LABEL: @test_end_borrow1
// CHECK: PAIR #0.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %2 = alloc_stack $X
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %4 = ref_element_addr %1 : $X, #X.a
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #2.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %6 = pointer_to_address %5 : $Builtin.RawPointer to $*Int32
// CHECK-NEXT: r=1,w=1
sil [ossa] @test_end_borrow1 : $@convention(thin) (@owned X) -> @owned X {
bb0(%0 : @owned $X):
%1 = begin_borrow %0 : $X
%2 = alloc_stack $X
dealloc_stack %2 : $*X
%4 = ref_element_addr %1 : $X, #X.a
%5 = address_to_pointer %4 : $*Int32 to $Builtin.RawPointer
%6 = pointer_to_address %5 : $Builtin.RawPointer to $*Int32
end_borrow %1 : $X
return %0 : $X
}
// CHECK-LABEL: @test_end_borrow2
// CHECK: PAIR #2.
// CHECK-NEXT: end_borrow %3 : $X
// CHECK-NEXT: %1 = ref_element_addr %0 : $X, #X.x
// CHECK-NEXT: r=0,w=0
sil [ossa] @test_end_borrow2 : $@convention(thin) (@guaranteed X) -> Int32 {
bb0(%0 : @guaranteed $X):
%1 = ref_element_addr %0 : $X, #X.x
%2 = load [copy] %1 : $*X
%3 = begin_borrow %2 : $X
%4 = function_ref @single_reference : $@convention(thin) (@guaranteed X) -> Int32
%5 = apply %4(%3) : $@convention(thin) (@guaranteed X) -> Int32
end_borrow %3 : $X
destroy_value %2 : $X
return %5 : $Int32
}
// CHECK-LABEL: @test_load_borrow
// CHECK: PAIR #0.
// CHECK-NEXT: %1 = load_borrow %0 : $*X
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: %1 = load_borrow %0 : $*X
// CHECK-NEXT: %2 = alloc_stack $X
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #4.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #5.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %2 = alloc_stack $X
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #6.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %4 = ref_element_addr %1 : $X, #X.a
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #7.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %6 = pointer_to_address %5 : $Builtin.RawPointer to $*Int32
// CHECK-NEXT: r=1,w=1
sil [ossa] @test_load_borrow : $@convention(thin) (@inout X) -> () {
bb0(%0 : $*X):
%1 = load_borrow %0 : $*X
%2 = alloc_stack $X
dealloc_stack %2 : $*X
%4 = ref_element_addr %1 : $X, #X.a
%5 = address_to_pointer %4 : $*Int32 to $Builtin.RawPointer
%6 = pointer_to_address %5 : $Builtin.RawPointer to $*Int32
end_borrow %1 : $X
%8 = tuple ()
return %8 : $()
}
// CHECK-LABEL: @test_immutable_end_borrow
// CHECK: PAIR #0.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %2 = alloc_stack $X
// CHECK-NEXT: r=0,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %4 = ref_element_addr [immutable] %1 : $X, #X.a
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #2.
// CHECK-NEXT: end_borrow %1 : $X
// CHECK-NEXT: %6 = pointer_to_address %5 : $Builtin.RawPointer to $*Int32
// CHECK-NEXT: r=1,w=1
sil [ossa] @test_immutable_end_borrow : $@convention(thin) (@owned X) -> @owned X {
bb0(%0 : @owned $X):
%1 = begin_borrow %0 : $X
%2 = alloc_stack $X
dealloc_stack %2 : $*X
%4 = ref_element_addr [immutable] %1 : $X, #X.a
%5 = address_to_pointer %4 : $*Int32 to $Builtin.RawPointer
%6 = pointer_to_address %5 : $Builtin.RawPointer to $*Int32
end_borrow %1 : $X
%8 = tuple ()
return %0 : $X
}
sil @indirect_X : $@convention(thin) (@in_guaranteed X) -> ()
// CHECK-LABEL: @test_escaping_partial_apply
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = partial_apply %1(%0) : $@convention(thin) (@in_guaranteed X) -> ()
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=1
sil [ossa] @test_escaping_partial_apply : $@convention(thin) (@in X) -> () {
bb0(%0 : $*X):
%1 = function_ref @indirect_X : $@convention(thin) (@in_guaranteed X) -> ()
%2 = partial_apply %1(%0) : $@convention(thin) (@in_guaranteed X) -> ()
destroy_value %2 : $@callee_owned () -> ()
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: @test_non_escaping_partial_apply
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = partial_apply [on_stack] %1(%0) : $@convention(thin) (@in_guaranteed X) -> ()
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #1.
// CHECK-NEXT: destroy_value %2 : $@noescape @callee_owned () -> ()
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=0,w=0
sil [ossa] @test_non_escaping_partial_apply : $@convention(thin) (@in X) -> () {
bb0(%0 : $*X):
%1 = function_ref @indirect_X : $@convention(thin) (@in_guaranteed X) -> ()
%2 = partial_apply [on_stack] %1(%0) : $@convention(thin) (@in_guaranteed X) -> ()
destroy_value %2 : $@noescape @callee_owned () -> ()
destroy_addr %0 : $*X
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: @test_is_unique
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = is_unique %0 : $*X
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %2 = is_unique %0 : $*X
// CHECK-NEXT: %1 = argument of bb0 : $*X
// CHECK-NEXT: r=0,w=0
sil [ossa] @test_is_unique : $@convention(thin) (@in X, @in X) -> () {
bb0(%0 : $*X, %1 : $*X):
%2 = is_unique %0 : $*X
destroy_addr %0 : $*X
destroy_addr %1 : $*X
%3 = tuple ()
return %3 : $()
}
// CHECK-LABEL: @test_unchecked_addr_cast
// CHECK: PAIR #0.
// CHECK-NEXT: %2 = load [copy] %1 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #2.
// CHECK-NEXT: %3 = is_unique %1 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #4.
// CHECK-NEXT: %4 = load_borrow %1 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*X
// CHECK-NEXT: r=1,w=0
sil [ossa] @test_unchecked_addr_cast : $@convention(thin) (@in_guaranteed X) -> @owned C {
bb0(%0 : $*X):
%1 = unchecked_addr_cast %0 : $*X to $*C
%2 = load [copy] %1 : $*C
%3 = is_unique %1 : $*C
%4 = load_borrow %1 : $*C
end_borrow %4 : $C
return %2 : $C
}