mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Assertion failed: (accessedAddress == getAccessedAddress(accessedAddress) && "caller must find the address root"), function isLetAddress, file /Users/rjmccall/dev/swift/swift/lib/SIL/Utils/MemAccessUtils.cpp, line 63. Teach the getAccessedAddress utility to iterate through nested access markers with projections interposed. Fixes <rdar://problem/61464370> Crash in SILOptimizer/access_marker_verify.swift
171 lines
6.4 KiB
Plaintext
171 lines
6.4 KiB
Plaintext
// 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,se=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,se=1
|
|
// CHECK: PAIR #103.
|
|
// CHECK-NEXT: destroy_value %0 : $Parent
|
|
// CHECK-NEXT: ref_element_addr %{{.*}} : $C, #C.prop
|
|
// CHECK-NEXT: r=1,w=1,se=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,se=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,se=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,se=0
|
|
// CHECK: PAIR #8.
|
|
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
|
|
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
|
|
// CHECK-NEXT: r=1,w=0,se=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,se=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,se=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,se=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,se=1
|
|
// CHECK: PAIR #22.
|
|
// CHECK-NEXT: end_access %{{.*}} : $*Builtin.Int32
|
|
// CHECK-NEXT: %0 = argument of bb0 : $*Builtin.Int32
|
|
// CHECK-NEXT: r=0,w=1,se=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,se=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,se=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
|
|
}
|
|
|
|
// ===-----------------------------------------------------------------------===
|
|
// 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,se=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,se=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,se=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 : $()
|
|
}
|