Files
swift-mirror/test/SILOptimizer/mem-behavior.sil
Erik Eckstein 67ce72cebb MemBehavior: fix minor bugs for `begin_access and end_access`.
* ``begin_access [modify]`` returned MayWrite, but "modify" means, it can be a read as well.
Instead, return MayReadWrite. Only for ``begin_access [init]`` return MayWrite.
This is more or less cosmetic - probably this bug had no real impact on any optimization.

* ``begin_access [deinit]`` needs to return MayReadWrite for the same reason ``destroy_addr`` returns MayReadWrite (see SILInstruction::MemoryBehavior).
2021-03-24 12:16:07 +01:00

720 lines
27 KiB
Plaintext

// RUN: %target-sil-opt %s -aa-kind=basic-aa -mem-behavior-dump -o /dev/null | %FileCheck %s
// REQUIRES: asserts
import Builtin
import Swift
class X {
@_hasStorage var a: Int32
@_hasStorage var x: X
init()
}
class C {
@_hasStorage @_hasInitialValue final let prop: Builtin.Int32 { get }
}
class Parent {
@_hasStorage var child: C { get set }
}
sil @unknown_func : $@convention(thin) (Int32, @in Int32) -> ()
sil @single_indirect_arg : $@convention(thin) (@in 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 Int32, Builtin.RawPointer) -> Int32
sil @single_reference : $@convention(thin) (@guaranteed X) -> Int32
sil @nouser_func : $@convention(thin) () -> ()
sil @store_to_int : $@convention(thin) (Int32, @inout Int32) -> () {
bb0(%0 : $Int32, %1 : $*Int32):
store %0 to %1 : $*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 {
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 Int32) -> ()
// CHECK-NEXT: %1 = argument of bb0 : $*Int32{{.*}} // user: %4
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%0, %1) : $@convention(thin) (Int32, @in 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 Int32) -> ()
%4 = apply %3(%0, %1) : $@convention(thin) (Int32, @in 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{{.*}} // user: %4
// 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{{.*}} // user: %6
// 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 : $()
}
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{{.*}} // user: %5
// CHECK-NEXT: r=0,w=0
sil @allocstack_apply_no_side_effect : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = alloc_stack $Int32 // user: %5
%2 = function_ref @nouser_func : $@convention(thin) () -> () // user: %3
%3 = apply %2() : $@convention(thin) () -> ()
%4 = tuple () // user: %6
dealloc_stack %1 : $*Int32 // id: %5
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 // users: %3, %5
// function_ref store_to_int
%2 = function_ref @store_to_int : $@convention(thin) (Int32, @inout Int32) -> () // user: %3
%3 = apply %2(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
%4 = tuple () // user: %6
dealloc_stack %1 : $*Int32 // id: %5
return %4 : $() // id: %6
}
// CHECK-LABEL: @allocstack_apply_no_escaping
// CHECK: PAIR #0.
// CHECK-NEXT: %3 = apply %2() : $@convention(thin) () -> ()
// CHECK-NEXT: %1 = alloc_stack $Int32{{.*}} // users: %7, %5
// CHECK-NEXT: r=0,w=0
sil @allocstack_apply_no_escaping : $@convention(thin) (Int32) -> () {
bb0(%0 : $Int32):
%1 = alloc_stack $Int32 // users: %3, %5
%2 = function_ref @nouser_func : $@convention(thin) () -> () // user: %3
%3 = apply %2() : $@convention(thin) () -> ()
%4 = function_ref @store_to_int: $@convention(thin) (Int32, @inout Int32) -> () // user: %3
%5 = apply %4(%0, %1) : $@convention(thin) (Int32, @inout Int32) -> ()
%6 = tuple () // user: %6
dealloc_stack %1 : $*Int32 // id: %5
return %6 : $() // id: %6
}
// CHECK-LABEL: @allocstack_apply_read_only
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%1) : $@convention(thin) (@in X) -> ()
// CHECK-NEXT: %1 = alloc_stack $X{{.*}} // users: %5, %4, %2
// 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 X) -> ()
%4 = apply %3(%1) : $@convention(thin) (@in 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 Int32) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #3.
// CHECK-NEXT: %4 = apply %3(%0) : $@convention(thin) (@in 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 Int32) -> Int32
%4 = apply %3(%0) : $@convention(thin) (@in 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 Int32) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #3.
// CHECK-NEXT: %4 = apply %3(%0) : $@convention(thin) (@in 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 Int32) -> Int32
%4 = apply %3(%0) : $@convention(thin) (@in Int32) -> Int32
return %4 : $Int32
}
// CHECK-LABEL: @esacping_allocstack_and_copyaddr
// CHECK: PAIR #3.
// CHECK-NEXT: %5 = apply %4(%0, %3) : $@convention(thin) (@in Int32, Builtin.RawPointer) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #4.
// CHECK-NEXT: %5 = apply %4(%0, %3) : $@convention(thin) (@in Int32, Builtin.RawPointer) -> Int32
// CHECK-NEXT: %1 = alloc_stack $Int32
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #5.
// CHECK-NEXT: %5 = apply %4(%0, %3) : $@convention(thin) (@in Int32, Builtin.RawPointer) -> Int32
// CHECK-NEXT: %3 = address_to_pointer %1 : $*Int32 to $Builtin.RawPointer
// CHECK-NEXT: r=1,w=1
sil @esacping_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 Int32, Builtin.RawPointer) -> Int32
%5 = apply %4(%0, %3) : $@convention(thin) (@in Int32, Builtin.RawPointer) -> Int32
dealloc_stack %1 : $*Int32
return %5 : $Int32
}
// CHECK-LABEL: @escaping_allocstack_to_known_function
// CHECK: PAIR #2.
// CHECK-NEXT: %5 = apply %4(%3) : $@convention(thin) (Builtin.RawPointer) -> UInt8 // user: %7
// CHECK-NEXT: %1 = alloc_stack $UInt8 // users: %6, %3, %2
// 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 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 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
dealloc_stack %1 : $*Int32
return %4 : $Int32
bb2:
abort_apply %5
unreachable
}
// 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 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 Int32) -> Int32
%6 = apply %5(%1) : $@convention(thin) (@in Int32) -> Int32
dealloc_stack %1 : $*Int32
return %6 : $Int32
}
sil @load_from_in : $@convention(thin) (@in 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{{.*}} // users: %5, %2, %1
// CHECK-NEXT: r=1,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 Int32) -> Int32
// CHECK-NEXT: %0 = argument of bb0 : $*TwoInts
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: %4 = apply %3(%1) : $@convention(thin) (@in Int32) -> Int32
// CHECK-NEXT: %1 = struct_element_addr %0 : $*TwoInts, #TwoInts.i1
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #2.
// CHECK-NEXT: %4 = apply %3(%1) : $@convention(thin) (@in 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 Int32) -> Int32
%4 = apply %3(%1) : $@convention(thin) (@in Int32) -> Int32
return %4 : $Int32
}
sil @copy_ints : $@convention(thin) (@inout Int32, @inout Int32) -> () {
bb0(%0 : $*Int32, %1 : $*Int32):
%2 = load %0 : $*Int32
store %2 to %1 : $*Int32
%r = tuple()
return %r : $()
}
// 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_sink : $@convention(thin) (Int) -> ()
sil @test_in_guaranteed_only_fun_is_ro_callee : $@convention(thin) (@in_guaranteed Int) -> ()
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 #2.
// 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 #18.
// CHECK-NEXT: end_borrow %{{.*}} : $C
// CHECK-NEXT: ref_element_addr %{{.*}} : $C, #C.prop
// CHECK-NEXT: r=1,w=1
// CHECK: PAIR #30.
// 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: @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
}
// ===-----------------------------------------------------------------------===
// Test the effect of a [deinit] access on a global 'let'
//
// Test <rdar://60046018> Assert: (v->getType().isAddress()), getAccessedAddress
sil_global hidden [let] @globalC : $C
// CHECK-LABEL: @testDeinitInstVsNonAddressValue
// CHECK: PAIR #3.
// CHECK-NEXT: load %{{.*}} : $*C
// CHECK-NEXT: begin_access [deinit] [static] %{{.*}} : $*Builtin.Int32
// CHECK-NEXT: r=1,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: %1 = begin_access [modify] [static] %0 : $*Int64Wrapper // users: %7, %2
// CHECK: %3 = begin_access [read] [static] %2 : $*Int64 // users: %6, %4
// CHECK: r=1,w=1
// CHECK: PAIR #3.
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 [initialization] %0 : $*C
// CHECK-NEXT: %0 = argument of bb0 : $*C
// CHECK-NEXT: r=0,w=1
// CHECK: PAIR #1.
// CHECK-NEXT: copy_addr %1 to [initialization] %0 : $*C
// CHECK-NEXT: %1 = argument of bb0 : $*C
// CHECK-NEXT: r=1,w=0
// CHECK: PAIR #2.
// CHECK-NEXT: copy_addr %1 to [initialization] %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 [initialization] %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=1,w=1
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 [initialization] %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 [initialization] %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 [initialization] %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 [initialization] %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 : $()
}