| // RUN: %target-sil-opt %s -aa-kind=basic-aa -mem-behavior-dump -enable-mem-behavior-dump-all -o /dev/null | %FileCheck %s |
| |
| // REQUIRES: asserts |
| |
| import Builtin |
| import Swift |
| |
| class C { |
| @_hasStorage @_hasInitialValue final let prop: Builtin.Int32 { get } |
| } |
| |
| class Parent { |
| @_hasStorage var child: C { get set } |
| } |
| |
| // 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 #25. |
| // 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 #83. |
| // CHECK-NEXT: end_borrow %{{.*}} : $C |
| // CHECK-NEXT: ref_element_addr %{{.*}} : $C, #C.prop |
| // CHECK-NEXT: r=1,w=1 |
| // CHECK: PAIR #103. |
| // 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: load [trivial] %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: r=1,w=0 |
| // CHECK: PAIR #3. |
| // 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 #8. |
| // CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=1,w=0 |
| // CHECK: PAIR #9. |
| // CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=1,w=0 |
| // CHECK: PAIR #12. |
| // CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=1,w=0 |
| // CHECK: PAIR #13. |
| // CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32 |
| // CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=0,w=1 |
| // CHECK: PAIR #14. |
| // CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32 |
| // CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=0,w=1 |
| // CHECK: PAIR #22. |
| // CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=0,w=1 |
| // CHECK: PAIR #23. |
| // CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: %{{.*}} = begin_access [read] [static] %0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=0,w=1 |
| // CHECK: PAIR #26. |
| // CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: %{{.*}} = begin_access [modify] [static] %0 : $*Builtin.Int32 |
| // CHECK-NEXT: r=0,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: @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 #5. |
| // CHECK-NEXT: load %{{.*}} : $*C |
| // CHECK-NEXT: begin_access [deinit] [static] %{{.*}} : $*Builtin.Int32 |
| // CHECK-NEXT: r=1,w=0 |
| // CHECK: PAIR #16. |
| // CHECK-NEXT: %6 = begin_access [deinit] [static] %5 : $*Builtin.Int32 // user: %7 |
| // CHECK-NEXT: %2 = load %1 : $*C // user: %3 |
| // 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=0,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 #2. |
| // CHECK-NEXT: destroy_value %1 : $C |
| // CHECK-NEXT: %0 = argument of bb0 : $*C |
| // CHECK-NEXT: r=0,w=0 |
| // CHECK: PAIR #3. |
| // CHECK-NEXT: destroy_value %1 : $C |
| // CHECK-NEXT: %1 = load [copy] %0 : $*C |
| // CHECK-NEXT: r=1,w=1 |
| 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 #3. |
| // CHECK-NEXT: %2 = copy_value %1 : $C |
| // CHECK-NEXT: %0 = argument of bb0 : $*C |
| // CHECK-NEXT: r=0,w=0 |
| // CHECK: PAIR #4. |
| // CHECK-NEXT: %2 = copy_value %1 : $C |
| // CHECK-NEXT: %1 = load [copy] %0 : $*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 : $() |
| } |
| |