// RUN: %target-sil-opt %s -aa-kind=basic-aa -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 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) -> () { [%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 Int32) -> () // CHECK-NEXT: %1 = argument of bb0 : $*Int32{{.*}} // user: %4 // CHECK-NEXT: r=1,w=0 // 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 : $() } // 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{{.*}} // 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=0 // 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=0 // 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: @escaping_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=0 // 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 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 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 any Error), normal bb1, error bb2 // CHECK-NEXT: %0 = argument of bb0 : $*Int32 // CHECK-NEXT: r=1,w=0 // 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=0 // 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=0 // 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=0 // 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 // 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 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 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 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) -> () { [%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 #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: @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=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 = tuple () return %8 : $() } // 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, #Optional.none!enumelt switch_enum %26 : $Optional, case #Optional.none!enumelt: bb1, case #Optional.some!enumelt: bb2 bb1: br bb3 bb2: %68 = unchecked_enum_data %26 : $Optional, #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 } // ===-----------------------------------------------------------------------=== // Test the effect of a [deinit] access on a global 'let' // // Test 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-NEXT: %1 = begin_access [modify] [static] %0 : $*Int64Wrapper // users: %7, %2 // CHECK-NEXT: %3 = begin_access [read] [static] %2 : $*Int64 // users: %6, %4 // 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=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 [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=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 store %2 to [assign] %0 : $*C %r = tuple () return %r : $() }