| // RUN: %target-sil-opt %s -accessed-storage-dump -enable-sil-verify-all -o /dev/null | %FileCheck %s |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| // CHECK-LABEL: @readIdentifiedArg |
| // CHECK: [read] Argument index: 0 |
| sil @readIdentifiedArg : $@convention(thin) (@in Int) -> Int { |
| bb0(%0 : $*Int): |
| %5 = begin_access [read] [dynamic] %0 : $*Int |
| %6 = load %5 : $*Int |
| end_access %5 : $*Int |
| return %6 : $Int |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedArg |
| // CHECK: [modify] Argument index: 0 |
| sil @writeIdentifiedArg : $@convention(thin) (Int) -> (@out Int) { |
| bb0(%0 : $*Int, %1 : $Int): |
| %3 = begin_access [modify] [dynamic] %0 : $*Int |
| store %1 to %3 : $*Int |
| end_access %3 : $*Int |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedArg |
| // CHECK: [modify] Argument index: 0 |
| sil @readWriteIdentifiedArg : $@convention(thin) (Int) -> (@out Int, Int) { |
| bb0(%0 : $*Int, %1 : $Int): |
| %2 = function_ref @writeIdentifiedArg : $@convention(thin) (Int) -> (@out Int) |
| %3 = apply %2(%0, %1) : $@convention(thin) (Int) -> (@out Int) |
| %5 = begin_access [modify] [dynamic] %0 : $*Int |
| %6 = load %5 : $*Int |
| end_access %5 : $*Int |
| return %6 : $Int |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedStack |
| // CHECK: [modify] Stack %1 = alloc_stack $Int |
| sil @writeIdentifiedStack : $@convention(thin) (Int) -> () { |
| bb0(%0 : $Int): |
| %1 = alloc_stack $Int |
| %3 = begin_access [modify] [dynamic] %1 : $*Int |
| store %0 to %3 : $*Int |
| end_access %3 : $*Int |
| dealloc_stack %1 : $*Int |
| %6 = tuple () |
| return %6 : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedStack |
| // CHECK: [modify] Stack %1 = alloc_stack $Int |
| sil @readWriteIdentifiedStack : $@convention(thin) (Int) -> Int { |
| bb0(%0 : $Int): |
| %1 = alloc_stack $Int |
| %2 = function_ref @writeIdentifiedArg : $@convention(thin) (Int) -> (@out Int) |
| %3 = apply %2(%1, %0) : $@convention(thin) (Int) -> (@out Int) |
| %5 = begin_access [modify] [dynamic] %1 : $*Int |
| %6 = load %5 : $*Int |
| end_access %5 : $*Int |
| dealloc_stack %1 : $*Int |
| return %6 : $Int |
| } |
| |
| // CHECK-LABEL: @readIdentifiedBoxArg |
| // CHECK: [read] Argument index: 0 |
| sil @readIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }) -> Int { |
| bb0(%0 : ${ var Int }): |
| %1 = project_box %0 : ${ var Int }, 0 |
| %5 = begin_access [read] [dynamic] %1 : $*Int |
| %6 = load %5 : $*Int |
| end_access %5 : $*Int |
| return %6 : $Int |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedBoxArg |
| // CHECK: [modify] Argument index: 0 |
| sil @writeIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }, Int) -> () { |
| bb0(%0 : ${ var Int }, %1 : $Int): |
| %2 = project_box %0 : ${ var Int }, 0 |
| %3 = begin_access [modify] [dynamic] %2 : $*Int |
| store %1 to %3 : $*Int |
| end_access %3 : $*Int |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedBoxArg |
| // CHECK: [modify] Argument index: 0 |
| sil @readWriteIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }, Int) -> Int { |
| bb0(%0 : ${ var Int }, %1 : $Int): |
| %2 = function_ref @writeIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }, Int) -> () |
| %3 = apply %2(%0, %1) : $@convention(thin) (@guaranteed { var Int }, Int) -> () |
| %4 = project_box %0 : ${ var Int }, 0 |
| %5 = begin_access [modify] [dynamic] %4 : $*Int |
| %6 = load %5 : $*Int |
| end_access %5 : $*Int |
| return %6 : $Int |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedBox |
| // CHECK: [read] Box %1 = alloc_box ${ var Int } |
| sil @writeIdentifiedBox : $@convention(thin) (Int) -> () { |
| bb0(%0 : $Int): |
| %1 = alloc_box ${ var Int } |
| %2 = project_box %1 : ${ var Int }, 0 |
| %3 = begin_access [read] [dynamic] %2 : $*Int |
| store %0 to %3 : $*Int |
| end_access %3 : $*Int |
| %6 = tuple () |
| return %6 : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedBox |
| // CHECK: [modify] Box %1 = alloc_box ${ var Int } |
| sil @readWriteIdentifiedBox : $@convention(thin) (Int) -> Int { |
| bb0(%0 : $Int): |
| %1 = alloc_box ${ var Int } |
| %2 = function_ref @writeIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }, Int) -> () |
| %3 = apply %2(%1, %0) : $@convention(thin) (@guaranteed { var Int }, Int) -> () |
| %4 = project_box %1 : ${ var Int }, 0 |
| %5 = begin_access [modify] [dynamic] %4 : $*Int |
| %6 = load %5 : $*Int |
| end_access %5 : $*Int |
| return %6 : $Int |
| } |
| |
| public var defined_global: Int64 |
| |
| // defined_global definition and initializer. |
| // |
| // A global defined in the current module must have a Swift declaration. |
| // The variable name is derived from the mangled SIL name. |
| sil_global @$s25accessed_storage_analysis14defined_globalSivp : $Int64 |
| |
| sil_global private @globalinit_33_45D320C25F1882286C6F155330EA3839_token0 : $Builtin.Word |
| |
| sil private @globalinit_33_45D320C25F1882286C6F155330EA3839_func0 : $@convention(c) () -> () { |
| bb0: |
| alloc_global @$s25accessed_storage_analysis14defined_globalSivp |
| %1 = global_addr @$s25accessed_storage_analysis14defined_globalSivp : $*Int64 |
| %2 = integer_literal $Builtin.Int64, 0 |
| %3 = struct $Int64 (%2 : $Builtin.Int64) |
| store %3 to %1 : $*Int64 |
| %5 = tuple () |
| return %5 : $() |
| } |
| |
| // defined_global.unsafeMutableAddressor |
| sil hidden [global_init] @$s25accessed_storage_analysis14defined_globalSivau : $@convention(thin) () -> Builtin.RawPointer { |
| bb0: |
| %0 = global_addr @globalinit_33_45D320C25F1882286C6F155330EA3839_token0 : $*Builtin.Word |
| %1 = address_to_pointer %0 : $*Builtin.Word to $Builtin.RawPointer |
| %2 = function_ref @globalinit_33_45D320C25F1882286C6F155330EA3839_func0 : $@convention(c) () -> () |
| %3 = builtin "once"(%1 : $Builtin.RawPointer, %2 : $@convention(c) () -> ()) : $() |
| %4 = global_addr @$s25accessed_storage_analysis14defined_globalSivp : $*Int64 |
| %5 = address_to_pointer %4 : $*Int64 to $Builtin.RawPointer |
| return %5 : $Builtin.RawPointer |
| } |
| |
| // CHECK-LABEL: @readIdentifiedDefinedGlobal |
| // CHECK: [read] Global // defined_global |
| // CHECK: sil_global @$s25accessed_storage_analysis14defined_globalSivp : $Int64 |
| sil @readIdentifiedDefinedGlobal : $@convention(thin) () -> Int64 { |
| bb0: |
| %1 = global_addr @$s25accessed_storage_analysis14defined_globalSivp : $*Int64 |
| %2 = begin_access [read] [dynamic] %1 : $*Int64 |
| %3 = load %2 : $*Int64 |
| end_access %2 : $*Int64 |
| return %3 : $Int64 |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedDefinedGlobal |
| // CHECK: [modify] Global // defined_global |
| // CHECK: sil_global @$s25accessed_storage_analysis14defined_globalSivp : $Int64 |
| sil @writeIdentifiedDefinedGlobal : $@convention(thin) (Int64) -> () { |
| bb0(%0 : $Int64): |
| %1 = global_addr @$s25accessed_storage_analysis14defined_globalSivp : $*Int64 |
| %2 = begin_access [modify] [dynamic] %1 : $*Int64 |
| store %0 to %2 : $*Int64 |
| end_access %2 : $*Int64 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedDefinedGlobal |
| // CHECK: [modify] Global // defined_global |
| // CHECK: sil_global @$s25accessed_storage_analysis14defined_globalSivp : $Int64 |
| sil @readWriteIdentifiedDefinedGlobal : $@convention(thin) (Int64) -> (Int64) { |
| bb0(%0 : $Int64): |
| %1 = function_ref @writeIdentifiedDefinedGlobal : $@convention(thin) (Int64) -> () |
| %2 = apply %1(%0) : $@convention(thin) (Int64) -> () |
| %3 = global_addr @$s25accessed_storage_analysis14defined_globalSivp : $*Int64 |
| %4 = begin_access [read] [dynamic] %3 : $*Int64 |
| %5 = load %4 : $*Int64 |
| end_access %4 : $*Int64 |
| return %5 : $Int64 |
| } |
| |
| // CHECK-LABEL: @readIdentifiedAddressedGlobal |
| // CHECK: [read] Global // defined_global |
| // CHECK: sil_global @$s25accessed_storage_analysis14defined_globalSivp : $Int64 |
| sil @readIdentifiedAddressedGlobal : $@convention(thin) () -> Int64 { |
| bb0: |
| // function_ref myGlobal.unsafeMutableAddressor |
| %0 = function_ref @$s25accessed_storage_analysis14defined_globalSivau : $@convention(thin) () -> Builtin.RawPointer |
| %1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer |
| %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64 |
| %3 = begin_access [read] [dynamic] %2 : $*Int64 |
| %4 = load %3 : $*Int64 |
| end_access %3 : $*Int64 |
| return %4 : $Int64 |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedAddressedGlobal |
| // CHECK: [modify] Global // defined_global |
| // CHECK: sil_global @$s25accessed_storage_analysis14defined_globalSivp : $Int64 |
| sil @writeIdentifiedAddressedGlobal : $@convention(thin) (Int64) -> () { |
| bb0(%0 : $Int64): |
| // function_ref myGlobal.unsafeMutableAddressor |
| %1 = function_ref @$s25accessed_storage_analysis14defined_globalSivau : $@convention(thin) () -> Builtin.RawPointer |
| %2 = apply %1() : $@convention(thin) () -> Builtin.RawPointer |
| %3 = pointer_to_address %2 : $Builtin.RawPointer to [strict] $*Int64 |
| %4 = begin_access [modify] [dynamic] %3 : $*Int64 |
| store %0 to %4 : $*Int64 |
| end_access %4 : $*Int64 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedAddressedGlobal |
| // CHECK: [modify] Global // defined_global |
| // CHECK: sil_global @$s25accessed_storage_analysis14defined_globalSivp : $Int64 |
| sil @readWriteIdentifiedAddressedGlobal : $@convention(thin) (Int64) -> (Int64) { |
| bb0(%0 : $Int64): |
| %1 = function_ref @writeIdentifiedAddressedGlobal : $@convention(thin) (Int64) -> () |
| %2 = apply %1(%0) : $@convention(thin) (Int64) -> () |
| // function_ref myGlobal.unsafeMutableAddressor |
| %3 = function_ref @$s25accessed_storage_analysis14defined_globalSivau : $@convention(thin) () -> Builtin.RawPointer |
| %4 = apply %3() : $@convention(thin) () -> Builtin.RawPointer |
| %5 = pointer_to_address %4 : $Builtin.RawPointer to [strict] $*Int64 |
| %6 = begin_access [modify] [dynamic] %5 : $*Int64 |
| %7 = load %6 : $*Int64 |
| end_access %6 : $*Int64 |
| return %7 : $Int64 |
| } |
| |
| public var static_global: Int64 |
| |
| // static_global definition and static initializer. |
| // |
| // A global defined in the current module must have a Swift declaration. |
| // The variable name is derived from the mangled SIL name. |
| sil_global @$s25accessed_storage_analysis13static_globalSivp : $Int64 = { |
| %0 = integer_literal $Builtin.Int64, 0 |
| %initval = struct $Int64 (%0 : $Builtin.Int64) |
| } |
| |
| // static_global.unsafeMutableAddressor |
| sil hidden [global_init] @$s25accessed_storage_analysis13static_globalSivau : $@convention(thin) () -> Builtin.RawPointer { |
| bb0: |
| %0 = global_addr @$s25accessed_storage_analysis14defined_globalSivp : $*Int64 |
| %1 = address_to_pointer %0 : $*Int64 to $Builtin.RawPointer |
| return %1 : $Builtin.RawPointer |
| } |
| |
| // A sil_global such as this without a corresponding Swift declaration must be |
| // defined in another module. Such a global can only be identified when accessed |
| // via global_addr instruction (as happens with C imports). Any access via an |
| // addessor (as with Swift imports) will be Unidentified. For the purpose of |
| // access analysis, a global is considered "external" based on the availabitiy |
| // of a Swift declaraion. We only consider an global to be a disjoint access |
| // location if its declaration is available. |
| sil_global @external_global : $Int64 |
| |
| sil hidden_external [global_init] @globalAddressor : $@convention(thin) () -> Builtin.RawPointer |
| |
| // CHECK-LABEL: @readIdentifiedExternalGlobal |
| // CHECK: [read] Global // external_global |
| // CHECK: sil_global @external_global : $Int64 |
| sil @readIdentifiedExternalGlobal : $@convention(thin) () -> Int64 { |
| bb0: |
| %1 = global_addr @external_global : $*Int64 |
| %2 = begin_access [read] [dynamic] %1 : $*Int64 |
| %3 = load %2 : $*Int64 |
| end_access %2 : $*Int64 |
| return %3 : $Int64 |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedExternalGlobal |
| // CHECK: [modify] Global // external_global |
| // CHECK: sil_global @external_global : $Int64 |
| sil @writeIdentifiedExternalGlobal : $@convention(thin) (Int64) -> () { |
| bb0(%0 : $Int64): |
| %1 = global_addr @external_global : $*Int64 |
| %2 = begin_access [modify] [dynamic] %1 : $*Int64 |
| store %0 to %2 : $*Int64 |
| end_access %2 : $*Int64 |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedExternalGlobal |
| // CHECK: [modify] Global // external_global |
| // CHECK: sil_global @external_global : $Int64 |
| sil @readWriteIdentifiedExternalGlobal : $@convention(thin) (Int64) -> (Int64) { |
| bb0(%0 : $Int64): |
| %1 = function_ref @writeIdentifiedExternalGlobal : $@convention(thin) (Int64) -> () |
| %2 = apply %1(%0) : $@convention(thin) (Int64) -> () |
| %3 = global_addr @external_global : $*Int64 |
| %4 = begin_access [read] [dynamic] %3 : $*Int64 |
| %5 = load %4 : $*Int64 |
| end_access %4 : $*Int64 |
| return %5 : $Int64 |
| } |
| |
| // CHECK-LABEL: @readUnidentifiedExternalGlobal |
| // CHECK-NOT: Global |
| // CHECK: unidentified accesses: modify |
| sil @readUnidentifiedExternalGlobal : $@convention(thin) () -> Int64 { |
| bb0: |
| %0 = function_ref @globalAddressor : $@convention(thin) () -> Builtin.RawPointer |
| %1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer |
| %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*Int64 |
| %3 = begin_access [read] [dynamic] %2 : $*Int64 |
| %4 = load %3 : $*Int64 |
| end_access %3 : $*Int64 |
| return %4 : $Int64 |
| } |
| |
| class C { |
| @_hasStorage var property: Int |
| deinit |
| init() |
| } |
| |
| // CHECK-LABEL: @readIdentifiedClass |
| // CHECK: [read] Class %0 = argument of bb0 : $C |
| // CHECK: Field: var property: Int |
| sil @readIdentifiedClass : $@convention(thin) (@guaranteed C) -> Int { |
| bb0(%0 : $C): |
| %1 = ref_element_addr %0 : $C, #C.property |
| %2 = begin_access [read] [dynamic] %1 : $*Int |
| %3 = load %2 : $*Int |
| end_access %2 : $*Int |
| return %3 : $Int |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedClass |
| // CHECK: [modify] Class %0 = argument of bb0 : $C |
| // CHECK: Field: var property: Int |
| sil @writeIdentifiedClass : $@convention(thin) (@guaranteed C, Int) -> () { |
| bb0(%0 : $C, %1 : $Int): |
| %2 = ref_element_addr %0 : $C, #C.property |
| %3 = begin_access [modify] [dynamic] %2 : $*Int |
| store %1 to %3 : $*Int |
| end_access %3 : $*Int |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedClass |
| // CHECK: [modify] Class %1 = alloc_ref $C |
| // CHECK: Field: var property: Int |
| sil @readWriteIdentifiedClass : $@convention(thin) (Int) -> (Int) { |
| bb0(%0 : $Int): |
| %1 = alloc_ref $C |
| %2 = function_ref @writeIdentifiedClass : $@convention(thin) (@guaranteed C, Int) -> () |
| %3 = apply %2(%1, %0) : $@convention(thin) (@guaranteed C, Int) -> () |
| %4 = ref_element_addr %1 : $C, #C.property |
| %5 = begin_access [read] [dynamic] %4 : $*Int |
| %6 = load %5 : $*Int |
| end_access %5 : $*Int |
| return %6 : $Int |
| } |
| |
| // CHECK-LABEL: @readIdentifiedNestedClass |
| // CHECK: [read] Class %0 = argument of bb0 : $C |
| // CHECK: Field: var property: Int |
| sil @readIdentifiedNestedClass : $@convention(thin) (@guaranteed C) -> Int { |
| bb0(%0 : $C): |
| %1 = ref_element_addr %0 : $C, #C.property |
| %2 = begin_access [read] [dynamic] %1 : $*Int |
| %3 = begin_access [read] [dynamic] %2 : $*Int |
| %4 = load %3 : $*Int |
| end_access %2 : $*Int |
| end_access %3 : $*Int |
| return %4 : $Int |
| } |
| |
| // CHECK-LABEL: @writeIdentifiedNestedClass |
| // CHECK: [modify] Class %0 = argument of bb0 : $C |
| // CHECK: Field: var property: Int |
| sil @writeIdentifiedNestedClass : $@convention(thin) (@guaranteed C, Int) -> () { |
| bb0(%0 : $C, %1 : $Int): |
| %2 = ref_element_addr %0 : $C, #C.property |
| %3 = begin_access [read] [dynamic] %2 : $*Int |
| %4 = begin_access [modify] [dynamic] %3 : $*Int |
| store %1 to %4 : $*Int |
| end_access %4 : $*Int |
| end_access %3 : $*Int |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @readWriteIdentifiedNestedClass |
| // CHECK: [modify] Class %1 = alloc_ref $C |
| // CHECK: Field: var property: Int |
| sil @readWriteIdentifiedNestedClass : $@convention(thin) (Int) -> (Int) { |
| bb0(%0 : $Int): |
| %1 = alloc_ref $C |
| %2 = function_ref @writeIdentifiedNestedClass : $@convention(thin) (@guaranteed C, Int) -> () |
| %3 = apply %2(%1, %0) : $@convention(thin) (@guaranteed C, Int) -> () |
| %4 = ref_element_addr %1 : $C, #C.property |
| %5 = begin_access [read] [dynamic] %4 : $*Int |
| %6 = begin_access [read] [dynamic] %5 : $*Int |
| %7 = load %6 : $*Int |
| end_access %5 : $*Int |
| end_access %6 : $*Int |
| return %7 : $Int |
| } |
| |
| enum TreeB<T> { |
| case Nil |
| case Leaf(T) |
| indirect case Branch(left: TreeB<T>, right: TreeB<T>) |
| } |
| |
| // CHECK-LABEL: @readIndirectEnum |
| // CHECK: [read] Argument index: 1 |
| sil @readIndirectEnum : $@convention(thin) <T> (@in TreeB<T>) -> (@out TreeB<T>) { |
| bb0(%0 : $*TreeB<T>, %1 : $*TreeB<T>): |
| %enumAddr = unchecked_take_enum_data_addr %1 : $*TreeB<T>, #TreeB.Branch!enumelt.1 |
| %box = load %enumAddr : $*<Ï„_0_0> { var (left: TreeB<Ï„_0_0>, right: TreeB<Ï„_0_0>) } <T> |
| %boxAddr = project_box %box : $<Ï„_0_0> { var (left: TreeB<Ï„_0_0>, right: TreeB<Ï„_0_0>) } <T>, 0 |
| %boxAccess = begin_access [read] [dynamic] %boxAddr : $*(left: TreeB<T>, right: TreeB<T>) |
| %leftAddr = tuple_element_addr %boxAccess : $*(left: TreeB<T>, right: TreeB<T>), 0 |
| copy_addr %leftAddr to [initialization] %0 : $*TreeB<T> |
| end_access %boxAccess : $*(left: TreeB<T>, right: TreeB<T>) |
| %v = tuple () |
| return %v : $() |
| } |
| |
| struct SomeError: Error {} |
| |
| // CHECK-LABEL: @writeIdentifiedArgReadUnidentifiedVarious |
| // CHECK: [modify] Argument index: 0 |
| // CHECK: unidentified accesses: read |
| sil @writeIdentifiedArgReadUnidentifiedVarious : $@convention(thin) (Int, Error) -> (@out Int) { |
| bb0(%out : $*Int, %i : $Int, %e : $Error): |
| %argAccess = begin_access [modify] [dynamic] %out : $*Int |
| store %i to %argAccess : $*Int |
| end_access %argAccess : $*Int |
| |
| %peb = project_existential_box $SomeError in %e : $Error |
| %pebAccess = begin_access [read] [dynamic] %peb : $*SomeError |
| %eload = load %pebAccess : $*SomeError |
| end_access %pebAccess : $*SomeError |
| |
| %oeb = open_existential_box %e : $Error to $*@opened("01234567-89AB-CDEF-0123-333333333333") Error |
| %oebAccess = begin_access [read] [dynamic] %oeb : $*@opened("01234567-89AB-CDEF-0123-333333333333") Error |
| end_access %oebAccess : $*@opened("01234567-89AB-CDEF-0123-333333333333") Error |
| |
| %v = tuple () |
| return %v : $() |
| } |
| |
| protocol P {} |
| |
| class CP : P { |
| var property: Int |
| init() |
| deinit |
| } |
| |
| // None of these address producers are normally used for formal |
| // access. i.e. They should not feed into a begin_access |
| // operand. Eventually, we may want to verify that SIL passes never |
| // result in such patterns. Until then we gracefully treat them as |
| // unidentified access. |
| // CHECK-LABEL: @readUnexpected |
| // CHECK: unidentified accesses: read |
| sil @readUnexpected : $@convention(thin) (@inout Int, @inout Int?, @inout Builtin.UnsafeValueBuffer) -> () { |
| bb0(%inout : $*Int, %oi : $*Optional<Int>, %b : $*Builtin.UnsafeValueBuffer): |
| %ea = init_enum_data_addr %oi : $*Optional<Int>, #Optional.some!enumelt.1 |
| %eaAccess = begin_access [read] [dynamic] %ea : $*Int |
| %eaload = load %eaAccess : $*Int |
| end_access %eaAccess : $*Int |
| |
| %pvb = project_value_buffer $Int in %b : $*Builtin.UnsafeValueBuffer |
| %pvbAccess = begin_access [read] [dynamic] %pvb : $*Int |
| %bload = load %pvbAccess : $*Int |
| end_access %pvbAccess : $*Int |
| |
| %p = alloc_stack $P |
| %iea = init_existential_addr %p : $*P, $CP |
| %propAccess = begin_access [read] [dynamic] %iea : $*CP |
| end_access %propAccess : $*CP |
| dealloc_stack %p : $*P |
| |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK-LABEL: @testDirectlyAppliedNoEscape |
| // CHECK: [read] Stack %3 = alloc_stack $Int |
| sil @testDirectlyAppliedNoEscape : $@convention(thin) (Int) -> () { |
| bb0(%0 : $Int): |
| %s1 = alloc_stack $Int |
| store %0 to %s1 : $*Int |
| %s2 = alloc_stack $Int |
| store %0 to %s2 : $*Int |
| %f = function_ref @testDirectlyAppliedClosure : $@convention(thin) (@inout Int, @inout_aliasable Int) -> () |
| %pa = partial_apply [callee_guaranteed] %f(%s2) : $@convention(thin) (@inout Int, @inout_aliasable Int) -> () |
| %npa = convert_escape_to_noescape %pa : $@callee_guaranteed (@inout Int) -> () to $@noescape @callee_guaranteed (@inout Int) -> () |
| %access = begin_access [modify] [dynamic] %s1 : $*Int |
| %call = apply %npa(%access) : $@noescape @callee_guaranteed (@inout Int) -> () |
| end_access %access : $*Int |
| strong_release %pa : $@callee_guaranteed (@inout Int) -> () |
| dealloc_stack %s2 : $*Int |
| dealloc_stack %s1 : $*Int |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // CHECK: @testDirectlyAppliedClosure |
| // CHECK: [read] Argument index: 1 |
| sil private @testDirectlyAppliedClosure : $@convention(thin) (@inout Int, @inout_aliasable Int) -> () { |
| bb0(%0 : $*Int, %1 : $*Int): |
| %access = begin_access [read] [dynamic] %1 : $*Int |
| %l = load %access : $*Int |
| end_access %access : $*Int |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // Test directly recursive argument access. |
| // CHECK-LABEL: @readRecursiveArgument |
| // CHECK: [read] Class %0 = argument of bb0 : $C |
| // CHECK: Field: var property: Int |
| sil @readRecursiveArgument : $@convention(thin) (@guaranteed C, Int) -> Int { |
| bb0(%0 : $C, %1 : $Int): |
| %propaddr = ref_element_addr %0 : $C, #C.property |
| %access = begin_access [read] [dynamic] %propaddr : $*Int |
| %val = load %access : $*Int |
| end_access %access : $*Int |
| %f = function_ref @readRecursiveArgument : $@convention(thin) (@guaranteed C, Int) -> Int |
| %call = apply %f(%0, %val) : $@convention(thin) (@guaranteed C, Int) -> Int |
| return %call : $Int |
| } |
| |
| // Test a class argument access from an optional caller value. |
| // CHECK-LABEL: @readOptionalArgumentInCallee |
| // CHECK: [read] Class %1 = unchecked_enum_data %0 : $Optional<C>, #Optional.some!enumelt.1 |
| // CHECK: Field: var property: Int |
| sil @readOptionalArgumentInCallee : $@convention(thin) (@guaranteed Optional<C>) -> Int { |
| bb0(%0 : $Optional<C>): |
| %c = unchecked_enum_data %0 : $Optional<C>, #Optional.some!enumelt.1 |
| %f = function_ref @readOptionalArgumentInCalleeHelper : $@convention(thin) (@guaranteed C) -> Int |
| %call = apply %f(%c) : $@convention(thin) (@guaranteed C) -> Int |
| return %call : $Int |
| } |
| |
| // CHECK-LABEL: @readOptionalArgumentInCalleeHelper |
| // CHECK: [read] Class %0 = argument of bb0 : $C |
| // CHECK: Field: var property: Int |
| sil private @readOptionalArgumentInCalleeHelper : $@convention(thin) (@guaranteed C) -> Int { |
| bb0(%0 : $C): |
| %propaddr = ref_element_addr %0 : $C, #C.property |
| %access = begin_access [read] [dynamic] %propaddr : $*Int |
| %val = load %access : $*Int |
| end_access %access : $*Int |
| return %val : $Int |
| } |
| |
| // Test a mutually recursive function that requires argument |
| // translation. This could cause iterator invalidation in the |
| // AccessedStorage map if we're not careful. |
| sil @readRecursiveOptionalArgument : $@convention(thin) (@guaranteed Optional<C>, @guaranteed C) -> Int { |
| bb0(%0 : $Optional<C>, %1 : $C): |
| %propaddr = ref_element_addr %1 : $C, #C.property |
| %access = begin_access [read] [dynamic] %propaddr : $*Int |
| %val = load %access : $*Int |
| end_access %access : $*Int |
| %c = unchecked_enum_data %0 : $Optional<C>, #Optional.some!enumelt.1 |
| %f = function_ref @readRecursiveOptionalArgument : $@convention(thin) (@guaranteed Optional<C>, @guaranteed C) -> Int |
| %call = apply %f(%0, %c) : $@convention(thin) (@guaranteed Optional<C>, @guaranteed C) -> Int |
| return %call : $Int |
| } |
| |
| // CHECK-LABEL: @readIdentifiedArgCaller |
| // CHECK: [read] Stack %1 = alloc_stack $Int // users: %5, %4, %2 |
| sil @readIdentifiedArgCaller : $@convention(thin) (Int) -> Int { |
| bb0(%0 : $Int): |
| %stack = alloc_stack $Int |
| store %0 to %stack : $*Int |
| %f = function_ref @readIdentifiedArg : $@convention(thin) (@in Int) -> Int |
| %call = apply %f(%stack) : $@convention(thin) (@in Int) -> Int |
| dealloc_stack %stack : $*Int |
| return %call : $Int |
| } |
| |
| enum IndirectEnum { |
| indirect case V(Int) |
| } |
| |
| // CHECK-LABEL: @readUnidentifiedArgCaller |
| // CHECK: unidentified accesses: read |
| sil @readUnidentifiedArgCaller : $@convention(thin) (@guaranteed IndirectEnum, Int) -> Int { |
| bb0(%0 : $IndirectEnum, %1 : $Int): |
| switch_enum %0 : $IndirectEnum, case #IndirectEnum.V!enumelt.1: bb2, default bb1 |
| |
| bb1: |
| br bb3(%1 : $Int) |
| |
| bb2(%7 : ${ var Int }): |
| %8 = project_box %7 : ${ var Int }, 0 |
| %f = function_ref @readIdentifiedArg : $@convention(thin) (@in Int) -> Int |
| %call = apply %f(%8) : $@convention(thin) (@in Int) -> Int |
| br bb3(%call : $Int) |
| |
| bb3(%result : $Int): |
| return %result : $Int |
| } |
| |
| // Make sure findAccessedStorage returns a valid storage object for an address-phi |
| // that feeds ref_element_addr instructions. The ref_element_addr's need to have the |
| // same base object and same field id. |
| // <rdar://problem/46114512> SIL verification failed: Unknown formal access pattern: storage |
| class BaseClass { |
| var f: Float = 0.0 |
| } |
| |
| class SubClass : BaseClass {} |
| |
| // CHECK-LABEL: @testElementAddressPhiAccess |
| // CHECK: [read] [no_nested_conflict] Class %{{.*}} = upcast %0 : $SubClass to $BaseClass |
| // CHECK: Field: @_hasInitialValue var f: Float |
| sil @testElementAddressPhiAccess : $@convention(thin) (@guaranteed SubClass) -> () { |
| bb0(%0 : $SubClass): |
| %base = upcast %0 : $SubClass to $BaseClass |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %ref1 = ref_element_addr %base : $BaseClass, #BaseClass.f |
| br bb3(%ref1 : $*Float) |
| |
| bb2: |
| %ref2 = ref_element_addr %base : $BaseClass, #BaseClass.f |
| br bb3(%ref2 : $*Float) |
| |
| bb3(%phi : $*Float): |
| %access = begin_access [read] [dynamic] [no_nested_conflict] %phi : $*Float |
| %addr = struct_element_addr %access : $*Float, #Float._value |
| %val = load %addr : $*Builtin.FPIEEE32 |
| end_access %access : $*Float |
| %v = tuple () |
| return %v : $() |
| } |
| |
| // Test an inlined global variable addressor after simplify-cfg has |
| // cloned the call to the addressor. |
| // <rdar://problem/47555992> SIL verification failed: Unknown formal access pattern |
| // CHECK-LABEL: @testClonedGlobalAddressor |
| // CHECK: [read] [no_nested_conflict] Global // gvar |
| // CHECK: sil_global hidden @gvar |
| var gvar: Int64 |
| |
| public func foo() -> Int64 |
| |
| sil_global hidden @gvar : $Int64 = { |
| %0 = integer_literal $Builtin.Int64, 0 |
| %initval = struct $Int (%0 : $Builtin.Int64) |
| } |
| |
| sil @testClonedGlobalAddressor : $@convention(thin) () -> Int64 { |
| bb0: |
| cond_br undef, bb1, bb2 |
| |
| bb1: |
| %1 = global_addr @gvar : $*Int64 |
| %2 = address_to_pointer %1 : $*Int64 to $Builtin.RawPointer |
| br bb3(%2 : $Builtin.RawPointer) |
| |
| bb2: |
| %4 = global_addr @gvar : $*Int64 |
| %5 = address_to_pointer %4 : $*Int64 to $Builtin.RawPointer |
| br bb3(%5 : $Builtin.RawPointer) |
| |
| // %7 |
| bb3(%7 : $Builtin.RawPointer): |
| %8 = pointer_to_address %7 : $Builtin.RawPointer to [strict] $*Int64 |
| %9 = begin_access [read] [dynamic] [no_nested_conflict] %8 : $*Int64 |
| %10 = load %9 : $*Int64 |
| end_access %9 : $*Int64 |
| return %10 : $Int64 |
| } |