mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This will e.g. catch violations like ``` %1 = begin_access [read] %0 store %2 to %0 end_access %1 ``` Also, fix all the sil tests which violate that.
704 lines
26 KiB
Plaintext
704 lines
26 KiB
Plaintext
// RUN: %target-sil-opt %s -access-storage-analysis-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 %0 = argument of bb0 : $*Int
|
|
sil [ossa] @readIdentifiedArg : $@convention(thin) (@in Int) -> Int {
|
|
bb0(%0 : $*Int):
|
|
%5 = begin_access [read] [dynamic] %0 : $*Int
|
|
%6 = load [trivial] %5 : $*Int
|
|
end_access %5 : $*Int
|
|
return %6 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedArg
|
|
// CHECK: [modify] Argument %0 = argument of bb0 : $*Int
|
|
sil [ossa] @writeIdentifiedArg : $@convention(thin) (Int) -> (@out Int) {
|
|
bb0(%0 : $*Int, %1 : $Int):
|
|
%3 = begin_access [modify] [dynamic] %0 : $*Int
|
|
store %1 to [trivial] %3 : $*Int
|
|
end_access %3 : $*Int
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-LABEL: @readWriteIdentifiedArg
|
|
// CHECK: [modify] Argument %0 = argument of bb0 : $*Int
|
|
sil [ossa] @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 [trivial] %5 : $*Int
|
|
end_access %5 : $*Int
|
|
return %6 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedStack
|
|
// CHECK: [modify] Stack %1 = alloc_stack $Int
|
|
sil [ossa] @writeIdentifiedStack : $@convention(thin) (Int) -> () {
|
|
bb0(%0 : $Int):
|
|
%1 = alloc_stack $Int
|
|
%3 = begin_access [modify] [dynamic] %1 : $*Int
|
|
store %0 to [trivial] %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 [ossa] @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 [trivial] %5 : $*Int
|
|
end_access %5 : $*Int
|
|
dealloc_stack %1 : $*Int
|
|
return %6 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @readIdentifiedBoxArg
|
|
// CHECK: [read] Box %0 = argument of bb0 : ${ var Int }
|
|
sil [ossa] @readIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }) -> Int {
|
|
bb0(%0 : @guaranteed ${ var Int }):
|
|
%1 = project_box %0 : ${ var Int }, 0
|
|
%5 = begin_access [read] [dynamic] %1 : $*Int
|
|
%6 = load [trivial] %5 : $*Int
|
|
end_access %5 : $*Int
|
|
return %6 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedBoxArg
|
|
// CHECK: [modify] Box %0 = argument of bb0 : ${ var Int }
|
|
sil [ossa] @writeIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }, Int) -> () {
|
|
bb0(%0 : @guaranteed ${ var Int }, %1 : $Int):
|
|
%2 = project_box %0 : ${ var Int }, 0
|
|
%3 = begin_access [modify] [dynamic] %2 : $*Int
|
|
store %1 to [trivial] %3 : $*Int
|
|
end_access %3 : $*Int
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-LABEL: @readWriteIdentifiedBoxArg
|
|
// CHECK: [modify] Box %0 = argument of bb0 : ${ var Int }
|
|
sil [ossa] @readWriteIdentifiedBoxArg : $@convention(thin) (@guaranteed { var Int }, Int) -> Int {
|
|
bb0(%0 : @guaranteed ${ 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 [trivial] %5 : $*Int
|
|
end_access %5 : $*Int
|
|
return %6 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedBox
|
|
// CHECK: [modify] Box %1 = alloc_box ${ var Int }
|
|
sil [ossa] @writeIdentifiedBox : $@convention(thin) (Int) -> () {
|
|
bb0(%0 : $Int):
|
|
%1 = alloc_box ${ var Int }
|
|
%2 = project_box %1 : ${ var Int }, 0
|
|
%3 = begin_access [modify] [dynamic] %2 : $*Int
|
|
store %0 to [trivial] %3 : $*Int
|
|
end_access %3 : $*Int
|
|
destroy_value %1 : ${ var Int }
|
|
%6 = tuple ()
|
|
return %6 : $()
|
|
}
|
|
|
|
// CHECK-LABEL: @readWriteIdentifiedBox
|
|
// CHECK: [modify] Box %1 = alloc_box ${ var Int }
|
|
sil [ossa] @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 [trivial] %5 : $*Int
|
|
end_access %5 : $*Int
|
|
destroy_value %1 : ${ var 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 @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
|
|
sil_global private @globalinit_33_45D320C25F1882286C6F155330EA3839_token0 : $Builtin.Word
|
|
|
|
sil private [ossa] @globalinit_33_45D320C25F1882286C6F155330EA3839_func0 : $@convention(c) () -> () {
|
|
bb0:
|
|
alloc_global @$s23access_storage_analysis14defined_globalSivp
|
|
%1 = global_addr @$s23access_storage_analysis14defined_globalSivp : $*Int64
|
|
%2 = integer_literal $Builtin.Int64, 0
|
|
%3 = struct $Int64 (%2 : $Builtin.Int64)
|
|
store %3 to [trivial] %1 : $*Int64
|
|
%5 = tuple ()
|
|
return %5 : $()
|
|
}
|
|
|
|
// defined_global.unsafeMutableAddressor
|
|
sil hidden [global_init] [ossa] @$s23access_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 @$s23access_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 @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
sil [ossa] @readIdentifiedDefinedGlobal : $@convention(thin) () -> Int64 {
|
|
bb0:
|
|
%1 = global_addr @$s23access_storage_analysis14defined_globalSivp : $*Int64
|
|
%2 = begin_access [read] [dynamic] %1 : $*Int64
|
|
%3 = load [trivial] %2 : $*Int64
|
|
end_access %2 : $*Int64
|
|
return %3 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedDefinedGlobal
|
|
// CHECK: [modify] Global // defined_global
|
|
// CHECK: sil_global @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
sil [ossa] @writeIdentifiedDefinedGlobal : $@convention(thin) (Int64) -> () {
|
|
bb0(%0 : $Int64):
|
|
%1 = global_addr @$s23access_storage_analysis14defined_globalSivp : $*Int64
|
|
%2 = begin_access [modify] [dynamic] %1 : $*Int64
|
|
store %0 to [trivial] %2 : $*Int64
|
|
end_access %2 : $*Int64
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-LABEL: @readWriteIdentifiedDefinedGlobal
|
|
// CHECK: [modify] Global // defined_global
|
|
// CHECK: sil_global @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
sil [ossa] @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 @$s23access_storage_analysis14defined_globalSivp : $*Int64
|
|
%4 = begin_access [read] [dynamic] %3 : $*Int64
|
|
%5 = load [trivial] %4 : $*Int64
|
|
end_access %4 : $*Int64
|
|
return %5 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: @readIdentifiedAddressedGlobal
|
|
// CHECK: [read] Global // defined_global
|
|
// CHECK: sil_global @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
sil [ossa] @readIdentifiedAddressedGlobal : $@convention(thin) () -> Int64 {
|
|
bb0:
|
|
// function_ref myGlobal.unsafeMutableAddressor
|
|
%0 = function_ref @$s23access_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 [trivial] %3 : $*Int64
|
|
end_access %3 : $*Int64
|
|
return %4 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedAddressedGlobal
|
|
// CHECK: [modify] Global // defined_global
|
|
// CHECK: sil_global @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
sil [ossa] @writeIdentifiedAddressedGlobal : $@convention(thin) (Int64) -> () {
|
|
bb0(%0 : $Int64):
|
|
// function_ref myGlobal.unsafeMutableAddressor
|
|
%1 = function_ref @$s23access_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 [trivial] %4 : $*Int64
|
|
end_access %4 : $*Int64
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-LABEL: @readWriteIdentifiedAddressedGlobal
|
|
// CHECK: [modify] Global // defined_global
|
|
// CHECK: sil_global @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
sil [ossa] @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 @$s23access_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 [trivial] %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 @$s23access_storage_analysis13static_globalSivp : $Int64 = {
|
|
%0 = integer_literal $Builtin.Int64, 0
|
|
%initval = struct $Int64 (%0 : $Builtin.Int64)
|
|
}
|
|
|
|
// static_global.unsafeMutableAddressor
|
|
sil hidden [global_init] [ossa] @$s23access_storage_analysis13static_globalSivau : $@convention(thin) () -> Builtin.RawPointer {
|
|
bb0:
|
|
%0 = global_addr @$s23access_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
|
|
// accessor (as with Swift imports) will be Unidentified. For the purpose of
|
|
// access analysis, a global is considered "external" based on the availability
|
|
// of a Swift declaration. 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 [ossa] @readIdentifiedExternalGlobal : $@convention(thin) () -> Int64 {
|
|
bb0:
|
|
%1 = global_addr @external_global : $*Int64
|
|
%2 = begin_access [read] [dynamic] %1 : $*Int64
|
|
%3 = load [trivial] %2 : $*Int64
|
|
end_access %2 : $*Int64
|
|
return %3 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedExternalGlobal
|
|
// CHECK: [modify] Global // external_global
|
|
// CHECK: sil_global @external_global : $Int64
|
|
sil [ossa] @writeIdentifiedExternalGlobal : $@convention(thin) (Int64) -> () {
|
|
bb0(%0 : $Int64):
|
|
%1 = global_addr @external_global : $*Int64
|
|
%2 = begin_access [modify] [dynamic] %1 : $*Int64
|
|
store %0 to [trivial] %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 [ossa] @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 [trivial] %4 : $*Int64
|
|
end_access %4 : $*Int64
|
|
return %5 : $Int64
|
|
}
|
|
|
|
// CHECK-LABEL: @readUnidentifiedExternalGlobal
|
|
// CHECK-NOT: Global
|
|
// CHECK: unidentified accesses: modify
|
|
sil [ossa] @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 [trivial] %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 [ossa] @readIdentifiedClass : $@convention(thin) (@guaranteed C) -> Int {
|
|
bb0(%0 : @guaranteed $C):
|
|
%borrow = begin_borrow %0 : $C
|
|
%1 = ref_element_addr %borrow : $C, #C.property
|
|
%2 = begin_access [read] [dynamic] %1 : $*Int
|
|
%3 = load [trivial] %2 : $*Int
|
|
end_access %2 : $*Int
|
|
end_borrow %borrow : $C
|
|
return %3 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedClass
|
|
// CHECK: [modify] Class %0 = argument of bb0 : $C
|
|
// CHECK: Field: var property: Int
|
|
sil [ossa] @writeIdentifiedClass : $@convention(thin) (@guaranteed C, Int) -> () {
|
|
bb0(%0 : @guaranteed $C, %1 : $Int):
|
|
%borrow = begin_borrow %0 : $C
|
|
%2 = ref_element_addr %borrow : $C, #C.property
|
|
%3 = begin_access [modify] [dynamic] %2 : $*Int
|
|
store %1 to [trivial] %3 : $*Int
|
|
end_access %3 : $*Int
|
|
end_borrow %borrow : $C
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-LABEL: @readWriteIdentifiedClass
|
|
// CHECK: [modify] Class %1 = alloc_ref $C
|
|
// CHECK: Field: var property: Int
|
|
sil [ossa] @readWriteIdentifiedClass : $@convention(thin) (Int) -> @owned C {
|
|
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) -> ()
|
|
%borrow = begin_borrow %1 : $C
|
|
%4 = ref_element_addr %borrow : $C, #C.property
|
|
%5 = begin_access [read] [dynamic] %4 : $*Int
|
|
%6 = load [trivial] %5 : $*Int
|
|
end_access %5 : $*Int
|
|
end_borrow %borrow : $C
|
|
return %1 : $C
|
|
}
|
|
|
|
// CHECK-LABEL: @readIdentifiedNestedClass
|
|
// CHECK: [read] Class %0 = argument of bb0 : $C
|
|
// CHECK: Field: var property: Int
|
|
sil [ossa] @readIdentifiedNestedClass : $@convention(thin) (@guaranteed C) -> Int {
|
|
bb0(%0 : @guaranteed $C):
|
|
%borrow = begin_borrow %0 : $C
|
|
%1 = ref_element_addr %borrow : $C, #C.property
|
|
%2 = begin_access [read] [dynamic] %1 : $*Int
|
|
%3 = begin_access [read] [dynamic] %2 : $*Int
|
|
%4 = load [trivial] %3 : $*Int
|
|
end_access %2 : $*Int
|
|
end_access %3 : $*Int
|
|
end_borrow %borrow : $C
|
|
return %4 : $Int
|
|
}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedNestedClass
|
|
// CHECK: [modify] Class %0 = argument of bb0 : $C
|
|
// CHECK: Field: var property: Int
|
|
sil [ossa] @writeIdentifiedNestedClass : $@convention(thin) (@guaranteed C, Int) -> () {
|
|
bb0(%0 : @guaranteed $C, %1 : $Int):
|
|
%borrow = begin_borrow %0 : $C
|
|
%2 = ref_element_addr %borrow : $C, #C.property
|
|
%3 = begin_access [modify] [dynamic] %2 : $*Int
|
|
%4 = begin_access [modify] [dynamic] %3 : $*Int
|
|
store %1 to [trivial] %4 : $*Int
|
|
end_access %4 : $*Int
|
|
end_access %3 : $*Int
|
|
end_borrow %borrow : $C
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK-LABEL: @readWriteIdentifiedNestedClass
|
|
// CHECK: [modify] Class %1 = alloc_ref $C
|
|
// CHECK: Field: var property: Int
|
|
sil [ossa] @readWriteIdentifiedNestedClass : $@convention(thin) (Int) -> @owned C {
|
|
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) -> ()
|
|
%borrow = begin_borrow %1 : $C
|
|
%4 = ref_element_addr %borrow : $C, #C.property
|
|
%5 = begin_access [read] [dynamic] %4 : $*Int
|
|
%6 = begin_access [read] [dynamic] %5 : $*Int
|
|
%7 = load [trivial] %6 : $*Int
|
|
end_access %5 : $*Int
|
|
end_access %6 : $*Int
|
|
end_borrow %borrow : $C
|
|
return %1 : $C
|
|
}
|
|
|
|
enum TreeB<T> {
|
|
case Nil
|
|
case Leaf(T)
|
|
indirect case Branch(left: TreeB<T>, right: TreeB<T>)
|
|
}
|
|
|
|
// CHECK-LABEL: @readIndirectEnum
|
|
// CHECK: unidentified accesses: modify
|
|
sil [ossa] @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
|
|
%box = load [take] %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 [init] %0 : $*TreeB<T>
|
|
end_access %boxAccess : $*(left: TreeB<T>, right: TreeB<T>)
|
|
destroy_value %box : $<τ_0_0> { var (left: TreeB<τ_0_0>, right: TreeB<τ_0_0>) } <T>
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
struct SomeError: Error {}
|
|
|
|
// CHECK-LABEL: @writeIdentifiedArgReadUnidentifiedVarious
|
|
// CHECK: unidentified accesses: modify
|
|
sil [ossa] @writeIdentifiedArgReadUnidentifiedVarious : $@convention(thin) (Int, @owned Error) -> (@out Int) {
|
|
bb0(%out : $*Int, %i : $Int, %e : @owned $Error):
|
|
%argAccess = begin_access [modify] [dynamic] %out : $*Int
|
|
store %i to [trivial] %argAccess : $*Int
|
|
end_access %argAccess : $*Int
|
|
|
|
%peb = project_existential_box $SomeError in %e : $Error
|
|
%pebAccess = begin_access [read] [dynamic] %peb : $*SomeError
|
|
%eload = load [trivial] %pebAccess : $*SomeError
|
|
end_access %pebAccess : $*SomeError
|
|
|
|
%borrow = begin_borrow %e : $Error
|
|
%oeb = open_existential_box %borrow : $Error to $*@opened("01234567-89AB-CDEF-0123-333333333333", Error) Self
|
|
%oebAccess = begin_access [read] [dynamic] %oeb : $*@opened("01234567-89AB-CDEF-0123-333333333333", Error) Self
|
|
end_access %oebAccess : $*@opened("01234567-89AB-CDEF-0123-333333333333", Error) Self
|
|
end_borrow %borrow : $Error
|
|
|
|
destroy_value %e : $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 [ossa] @readUnexpected : $@convention(thin) (@inout Int, @inout Int?, @inout Int) -> () {
|
|
bb0(%inout : $*Int, %oi : $*Optional<Int>, %pvb : $*Int):
|
|
%ea = init_enum_data_addr %oi : $*Optional<Int>, #Optional.some!enumelt
|
|
%eaAccess = begin_access [read] [dynamic] %ea : $*Int
|
|
%eaload = load [trivial] %eaAccess : $*Int
|
|
end_access %eaAccess : $*Int
|
|
|
|
%pvbAccess = begin_access [read] [dynamic] %pvb : $*Int
|
|
%bload = load [trivial] %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 [ossa] @testDirectlyAppliedNoEscape : $@convention(thin) (Int) -> () {
|
|
bb0(%0 : $Int):
|
|
%s1 = alloc_stack $Int
|
|
store %0 to [trivial] %s1 : $*Int
|
|
%s2 = alloc_stack $Int
|
|
store %0 to [trivial] %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) -> ()
|
|
%borrow = begin_borrow %pa : $@callee_guaranteed (@inout Int) -> ()
|
|
%npa = convert_escape_to_noescape %borrow : $@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
|
|
destroy_value %npa : $@noescape @callee_guaranteed (@inout Int) -> ()
|
|
end_borrow %borrow : $@callee_guaranteed (@inout Int) -> ()
|
|
destroy_value %pa : $@callee_guaranteed (@inout Int) -> ()
|
|
dealloc_stack %s2 : $*Int
|
|
dealloc_stack %s1 : $*Int
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// CHECK: @testDirectlyAppliedClosure
|
|
// CHECK: [read] Argument %1 = argument of bb0 : $*Int
|
|
sil private [ossa] @testDirectlyAppliedClosure : $@convention(thin) (@inout Int, @inout_aliasable Int) -> () {
|
|
bb0(%0 : $*Int, %1 : $*Int):
|
|
%access = begin_access [read] [dynamic] %1 : $*Int
|
|
%l = load [trivial] %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 [ossa] @readRecursiveArgument : $@convention(thin) (@guaranteed C, Int) -> Int {
|
|
bb0(%0 : @guaranteed $C, %1 : $Int):
|
|
%borrow = begin_borrow %0 : $C
|
|
%propaddr = ref_element_addr %borrow : $C, #C.property
|
|
%access = begin_access [read] [dynamic] %propaddr : $*Int
|
|
%val = load [trivial] %access : $*Int
|
|
end_access %access : $*Int
|
|
end_borrow %borrow : $C
|
|
%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
|
|
// CHECK: Field: var property: Int
|
|
sil [ossa] @readOptionalArgumentInCallee : $@convention(thin) (@guaranteed Optional<C>) -> Int {
|
|
bb0(%0 : @guaranteed $Optional<C>):
|
|
%c = unchecked_enum_data %0 : $Optional<C>, #Optional.some!enumelt
|
|
%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 [ossa] @readOptionalArgumentInCalleeHelper : $@convention(thin) (@guaranteed C) -> Int {
|
|
bb0(%0 : @guaranteed $C):
|
|
%borrow = begin_borrow %0 : $C
|
|
%propaddr = ref_element_addr %borrow : $C, #C.property
|
|
%access = begin_access [read] [dynamic] %propaddr : $*Int
|
|
%val = load [trivial] %access : $*Int
|
|
end_access %access : $*Int
|
|
end_borrow %borrow : $C
|
|
return %val : $Int
|
|
}
|
|
|
|
// Test a mutually recursive function that requires argument
|
|
// translation. This could cause iterator invalidation in the
|
|
// AccessStorage map if we're not careful.
|
|
sil [ossa] @readRecursiveOptionalArgument : $@convention(thin) (@guaranteed Optional<C>, @guaranteed C) -> Int {
|
|
bb0(%0 : @guaranteed $Optional<C>, %1 : @guaranteed $C):
|
|
%borrow = begin_borrow %1 : $C
|
|
%propaddr = ref_element_addr %borrow : $C, #C.property
|
|
%access = begin_access [read] [dynamic] %propaddr : $*Int
|
|
%val = load [trivial] %access : $*Int
|
|
end_access %access : $*Int
|
|
end_borrow %borrow : $C
|
|
%c = unchecked_enum_data %0 : $Optional<C>, #Optional.some!enumelt
|
|
%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 [ossa] @readIdentifiedArgCaller : $@convention(thin) (Int) -> Int {
|
|
bb0(%0 : $Int):
|
|
%stack = alloc_stack $Int
|
|
store %0 to [trivial] %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)
|
|
case None
|
|
}
|
|
|
|
// CHECK-LABEL: @readUnidentifiedArgCaller
|
|
// CHECK: [read] Box %{{.*}} = argument of bb2 : ${ var Int }
|
|
sil [ossa] @readUnidentifiedArgCaller : $@convention(thin) (@guaranteed IndirectEnum, Int) -> Int {
|
|
bb0(%0 : @guaranteed $IndirectEnum, %1 : $Int):
|
|
switch_enum %0 : $IndirectEnum, case #IndirectEnum.V!enumelt: bb2, default bb1
|
|
|
|
bb1:
|
|
br bb3(%1 : $Int)
|
|
|
|
bb2(%7 : @guaranteed ${ 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 identifyFormalAccess 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 {}
|
|
|
|
// 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 [ossa] @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 [trivial] %9 : $*Int64
|
|
end_access %9 : $*Int64
|
|
return %10 : $Int64
|
|
}
|