mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
executing unknown code This means we have to claw back some performance by recognizing harmless releases. Such as releases on types we known don't call a deinit with unknown side-effects. rdar://143497196 rdar://143141695
799 lines
32 KiB
Plaintext
799 lines
32 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 @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 %0 = argument of bb0 : $*Int
|
|
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 %0 = argument of bb0 : $*Int
|
|
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] Box %0 = argument of bb0 : ${ var Int }
|
|
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] Box %0 = argument of bb0 : ${ var Int }
|
|
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] Box %0 = argument of bb0 : ${ var Int }
|
|
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 @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
|
|
sil_global private @globalinit_33_45D320C25F1882286C6F155330EA3839_token0 : $Builtin.Word
|
|
|
|
sil private @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 %1 : $*Int64
|
|
%5 = tuple ()
|
|
return %5 : $()
|
|
}
|
|
|
|
// defined_global.unsafeMutableAddressor
|
|
sil hidden [global_init] @$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 @readIdentifiedDefinedGlobal : $@convention(thin) () -> Int64 {
|
|
bb0:
|
|
%1 = global_addr @$s23access_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 @$s23access_storage_analysis14defined_globalSivp : $Int64
|
|
sil @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 %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 @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 %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 @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 %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 @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 %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 @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 %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] @$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 @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 %1 = argument of bb0 : $*TreeB<T>
|
|
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
|
|
%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 [init] %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 %0 = argument of bb0 : $*Int
|
|
// 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) 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
|
|
|
|
%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 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 %eaAccess : $*Int
|
|
end_access %eaAccess : $*Int
|
|
|
|
%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-LABEL: @testCopiedNoEscape
|
|
// CHECK: [read] Stack %3 = alloc_stack $Int
|
|
sil [ossa] @testCopiedNoEscape : $@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) -> ()
|
|
%copy = copy_value %pa : $@callee_guaranteed (@inout Int) -> ()
|
|
%borrow = begin_borrow %copy : $@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 %copy : $@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 @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
|
|
// 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
|
|
%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
|
|
// AccessStorage 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
|
|
%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: Box %{{.*}} = argument of bb2 : ${ var Int }
|
|
sil @readUnidentifiedArgCaller : $@convention(thin) (@guaranteed IndirectEnum, Int) -> Int {
|
|
bb0(%0 : $IndirectEnum, %1 : $Int):
|
|
switch_enum %0 : $IndirectEnum, case #IndirectEnum.V!enumelt: 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// Test storage for SIL global variable declarations.
|
|
|
|
sil_global hidden @testGlobal : $Builtin.Int64
|
|
|
|
sil hidden [global_init] @testAddressor : $@convention(thin) () -> Builtin.RawPointer {
|
|
bb0:
|
|
%4 = global_addr @testGlobal : $*Builtin.Int64
|
|
%5 = address_to_pointer %4 : $*Builtin.Int64 to $Builtin.RawPointer
|
|
return %5 : $Builtin.RawPointer
|
|
}
|
|
|
|
sil hidden [transparent] @testGetter : $@convention(thin) () -> Builtin.Int64 {
|
|
bb0:
|
|
%2 = function_ref @testAddressor : $@convention(thin) () -> Builtin.RawPointer
|
|
%3 = apply %2() : $@convention(thin) () -> Builtin.RawPointer
|
|
%4 = pointer_to_address %3 : $Builtin.RawPointer to [strict] $*Builtin.Int64
|
|
%5 = begin_access [read] [dynamic] %4 : $*Builtin.Int64
|
|
%6 = load %5 : $*Builtin.Int64
|
|
end_access %5 : $*Builtin.Int64
|
|
return %6 : $Builtin.Int64
|
|
}
|
|
|
|
// CHECK: @test_harmless_regardless_of_type_pod
|
|
// CHECK-NEXT: @test_harmless_regardless_of_type_ref
|
|
// CHECK-NEXT: @test_harmless_typedependent
|
|
// CHECK-NEXT: @test_not_harmless_typedependent
|
|
// CHECK-NEXT: unidentified accesses: modify
|
|
// CHECK-NEXT: @test_not_harmless_typedependent_2
|
|
// CHECK-NEXT: unidentified accesses: modify
|
|
// CHECK-NEXT: @test_not_harmless_typedependent_3
|
|
// CHECK-NEXT: unidentified accesses: modify
|
|
// CHECK-NEXT: @test_not_harmless_typedependent_4
|
|
// CHECK-NEXT: unidentified accesses: modify
|
|
// CHECK-NEXT: @test_not_harmless_typedependent_5
|
|
// CHECK-NEXT: unidentified accesses: modify
|
|
|
|
sil hidden [transparent] @test_harmless_regardless_of_type_pod : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin UInt8.Type
|
|
%4 = builtin "copyArray"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%5 = builtin "takeArrayFrontToBack"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%6 = builtin "takeArrayBackToFront"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%7 = builtin "takeArrayNoAlias"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|
|
|
|
sil hidden [transparent] @test_harmless_regardless_of_type_ref : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin C.Type
|
|
%4 = builtin "copyArray"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%5 = builtin "takeArrayFrontToBack"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%6 = builtin "takeArrayBackToFront"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%7 = builtin "takeArrayNoAlias"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|
|
|
|
sil hidden [transparent] @test_harmless_typedependent : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin UInt8.Type
|
|
%8 = builtin "assignCopyArrayNoAlias"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%9 = builtin "assignCopyArrayFrontToBack"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%10 = builtin "assignCopyArrayBackToFront"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%11 = builtin "assignTakeArray"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%12 = builtin "destroyArray"<UInt8>(%3 : $@thin UInt8.Type, %0 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|
|
|
|
sil hidden [transparent] @test_not_harmless_typedependent : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin C.Type
|
|
%8 = builtin "assignCopyArrayNoAlias"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|
|
|
|
sil hidden [transparent] @test_not_harmless_typedependent_2 : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin C.Type
|
|
%9 = builtin "assignCopyArrayFrontToBack"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|
|
sil hidden [transparent] @test_not_harmless_typedependent_3 : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin C.Type
|
|
%10 = builtin "assignCopyArrayBackToFront"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|
|
sil hidden [transparent] @test_not_harmless_typedependent_4 : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin C.Type
|
|
%11 = builtin "assignTakeArray"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|
|
sil hidden [transparent] @test_not_harmless_typedependent_5 : $@convention(thin) (Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () {
|
|
bb0(%0 : $Builtin.RawPointer, %1: $Builtin.RawPointer, %2: $Builtin.Word):
|
|
%3 = metatype $@thin C.Type
|
|
%12 = builtin "destroyArray"<C>(%3 : $@thin C.Type, %0 : $Builtin.RawPointer, %2 : $Builtin.Word) : $()
|
|
%t = tuple()
|
|
return %t: $()
|
|
}
|