Files
swift-mirror/test/SILOptimizer/cowarray_opt.sil
Erik Eckstein 71a642e51b stdlib, SIL optimizer: use the SIL copy-on-write representation in the Array types.
Use the new builtins for COW representation in Array, ContiguousArray and ArraySlice.
The basic idea is to strictly separate code which mutates an array buffer from code which reads from an array.
The concept is explained in more detail in docs/SIL.rst, section "Copy-on-Write Representation".

The main change is to use beginCOWMutation() instead of isUniquelyReferenced() and insert endCOWMutation() at the end of all mutating functions. Also, reading from the array buffer must be done differently, depending on if the buffer is in a mutable or immutable state.

All the required invariants are enforced by runtime checks - but only in an assert-build of the library: a bit in the buffer object side-table indicates if the buffer is mutable or not.

Along with the library changes, also two optimizations needed to be updated: COWArrayOpt and ObjectOutliner.
2020-06-08 15:02:22 +02:00

843 lines
32 KiB
Plaintext

// RUN: %target-sil-opt -enforce-exclusivity=none -enable-sil-verify-all -cowarray-opt %s | %FileCheck %s
// Declare this SIL to be canonical because some tests break raw SIL
// conventions. e.g. address-type block args. -enforce-exclusivity=none is also
// required to allow address-type block args in canonical SIL.
sil_stage canonical
import Builtin
import Swift
/////////////
// Utility //
/////////////
struct ArrayIntBuffer {
var storage : Builtin.NativeObject
}
struct MyArray<T> {
var buffer : ArrayIntBuffer
}
struct MyStruct {
}
class MyArrayContainer<T> {
var array: MyArray<T>
init()
deinit
}
struct Container {
var array: MyArray<MyStruct>
}
struct ContainerContainer {
var container: Container
}
class MyArrayStorage {
@_hasStorage var header: Int
init()
deinit
}
sil [_semantics "array.make_mutable"] @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
sil [_semantics "array.end_mutation"] @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
sil [_semantics "array.get_count"] @guaranteed_array_get_count : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
sil [_semantics "array.get_capacity"] @guaranteed_array_get_capacity : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
sil [_semantics "array.mutate_unknown"] @array_unknown_mutate : $@convention(method) (@inout MyArray<MyStruct>) -> ()
// An unknown user
sil @unknown : $@convention(thin) () -> ()
///////////
// Tests //
///////////
// CHECK-LABEL: sil @simple_hoist
// CHECK: bb0([[ARRAY:%[0-9]+]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: } // end sil function 'simple_hoist'
sil @simple_hoist : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
debug_value_addr %0 : $*MyArray<MyStruct>
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_ignoring_paired_retain_release_and_hoist
// CHECK: bb0([[ARRAY:%[0-9]+]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: retain
// CHECK: release
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: cond_br {{.*}}, bb1
// CHECK: } // end sil function 'hoist_ignoring_paired_retain_release_and_hoist'
sil @hoist_ignoring_paired_retain_release_and_hoist : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
retain_value %2 : $MyArray<MyStruct>
%3 = load %1 : $*Builtin.Int1
%4 = load %0 : $*MyArray<MyStruct>
release_value %2 : $MyArray<MyStruct>
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br %3, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_blocked_by_unpaired_retain_release_1
// CHECK: bb0(
// CHECK-NOT: apply
// CHECK: bb1:
// CHECK: retain_value
// CHECK: [[MM:%.*]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]
// CHECK: cond_br {{.*}}, bb1
sil @hoist_blocked_by_unpaired_retain_release_1 : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
retain_value %2 : $MyArray<MyStruct>
%3 = load %1 : $*Builtin.Int1
%4 = load %0 : $*MyArray<MyStruct>
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br %3, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_blocked_by_unpaired_retain_release_2
// CHECK: bb0(
// CHECK-NOT: apply
// CHECK: bb1:
// CHECK: retain_value
// CHECK: [[MM:%.*]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]
// CHECK: cond_br {{.*}}, bb1
sil @hoist_blocked_by_unpaired_retain_release_2 : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
br bb1
bb1:
%10 = load %0 : $*MyArray<MyStruct>
%11 = load %0 : $*MyArray<MyStruct>
%12 = struct_extract %10 : $MyArray<MyStruct>, #MyArray.buffer
%13 = struct_extract %11 : $MyArray<MyStruct>, #MyArray.buffer
retain_value %12 : $ArrayIntBuffer
retain_value %13 : $ArrayIntBuffer
release_value %13 : $ArrayIntBuffer
%3 = load %1 : $*Builtin.Int1
%4 = load %0 : $*MyArray<MyStruct>
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br %3, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_not_blocked_by_unpaired_release
// CHECK: bb0([[ARRAY:%[0-9]+]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: load
// CHECK: load
// CHECK: release
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: } // end sil function 'hoist_not_blocked_by_unpaired_release'
sil @hoist_not_blocked_by_unpaired_release : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
%3 = load %1 : $*Builtin.Int1
%4 = load %0 : $*MyArray<MyStruct>
release_value %2 : $MyArray<MyStruct>
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br %3, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @dont_hoist_if_executed_conditionally
// CHECK: bb0({{.*}}):
// CHECK-NOT: apply
// CHECK: bb1({{.*}}):
// CHECK: bb2:
// CHECK: apply
// CHECK: bb3:
sil @dont_hoist_if_executed_conditionally : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> MyArray<MyStruct> {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
debug_value_addr %0 : $*MyArray<MyStruct>
%2 = load %0 : $*MyArray<MyStruct>
br bb1(%2 : $MyArray<MyStruct>)
bb1(%p1 : $MyArray<MyStruct>):
cond_br undef, bb2, bb3
bb2:
// If this block is never taken, then hoisting to bb0 would change the value of %p3.
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%9 = load %0 : $*MyArray<MyStruct>
br bb4(%9 : $MyArray<MyStruct>)
bb3:
br bb4(%p1 : $MyArray<MyStruct>)
bb4(%p2 : $MyArray<MyStruct>):
cond_br undef, bb1(%p2 : $MyArray<MyStruct>), bb5(%p2 : $MyArray<MyStruct>)
bb5(%p3 : $MyArray<MyStruct>):
return %p3 : $MyArray<MyStruct>
}
// CHECK-LABEL: sil @cow_should_ignore_mark_dependence_addrproj_use : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
// CHECK: bb0([[ARRAY:%[0-9]+]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: retain
// CHECK: load
// CHECK: load
// CHECK: release
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: mark_dependence
// CHECK: } // end sil function 'cow_should_ignore_mark_dependence_addrproj_use'
sil @cow_should_ignore_mark_dependence_addrproj_use : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
%999 = struct_element_addr %0 : $*MyArray<MyStruct>, #MyArray.buffer
%9999 = struct_element_addr %999 : $*ArrayIntBuffer, #ArrayIntBuffer.storage
%99999 = load %9999 : $*Builtin.NativeObject
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
retain_value %2 : $MyArray<MyStruct>
%3 = load %1 : $*Builtin.Int1
%4 = load %0 : $*MyArray<MyStruct>
release_value %2 : $MyArray<MyStruct>
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
mark_dependence %1 : $*Builtin.Int1 on %99999 : $Builtin.NativeObject
cond_br %3, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @cow_should_ignore_mark_dependence_value : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
// CHECK: bb0([[ARRAY:%[0-9]+]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: retain
// CHECK: load
// CHECK: load
// CHECK: release
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: mark_dependence
// CHECK: } // end sil function 'cow_should_ignore_mark_dependence_value'
sil @cow_should_ignore_mark_dependence_value : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
retain_value %2 : $MyArray<MyStruct>
%3 = load %1 : $*Builtin.Int1
%4 = load %0 : $*MyArray<MyStruct>
release_value %2 : $MyArray<MyStruct>
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
mark_dependence %1 : $*Builtin.Int1 on %2 : $MyArray<MyStruct>
cond_br %3, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @cow_should_ignore_enum : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
// CHECK: bb0([[ARRAY:%[0-9]+]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: retain
// CHECK: load
// CHECK: load
// CHECK: release
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: enum
// CHECK: mark_dependence
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: } // end sil function 'cow_should_ignore_enum'
sil @cow_should_ignore_enum : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
retain_value %2 : $MyArray<MyStruct>
%3 = load %1 : $*Builtin.Int1
%4 = load %0 : $*MyArray<MyStruct>
release_value %2 : $MyArray<MyStruct>
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%e = enum $Optional<MyArray<MyStruct>>, #Optional.some!enumelt, %2 : $MyArray<MyStruct>
mark_dependence %1 : $*Builtin.Int1 on %e : $Optional<MyArray<MyStruct>>
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br %3, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @cow_should_ignore_guaranteed_semantic_call_sequence : $@convention(thin) (@guaranteed MyArrayContainer<MyStruct>, Builtin.NativeObject) -> () {
// CHECK: bb0
// CHECK-DAG: [[MM:%[0-9]+]] = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
// CHECK-DAG: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[MM]](
// CHECK: apply [[EM]](
// CHECK: bb1:
// CHECK: } // end sil function 'cow_should_ignore_guaranteed_semantic_call_sequence'
sil @cow_should_ignore_guaranteed_semantic_call_sequence : $@convention(thin) (@guaranteed MyArrayContainer<MyStruct>, Builtin.NativeObject) -> () {
bb0(%0 : $MyArrayContainer<MyStruct>, %00 : $Builtin.NativeObject):
%1 = ref_element_addr %0 : $MyArrayContainer<MyStruct>, #MyArrayContainer.array
%2 = load %1 : $*MyArray<MyStruct>
%3 = function_ref @guaranteed_array_get_count : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
%4 = function_ref @guaranteed_array_get_capacity : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
%5 = function_ref @unknown : $@convention(thin) () -> ()
%6 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
br bb1
bb1:
// Simple case. This should hoist.
retain_value %2 : $MyArray<MyStruct>
apply %3(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
apply %4(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
release_value %2 : $MyArray<MyStruct>
apply %6(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %7(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
br bb3
bb3:
// Failure case b/c of use in between release and call.
retain_value %2 : $MyArray<MyStruct>
apply %3(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
apply %4(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
fix_lifetime %0 : $MyArrayContainer<MyStruct>
release_value %2 : $MyArray<MyStruct>
apply %6(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %7(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb4, bb3
bb4:
br bb5
bb5:
// Failure case b/c of use in between calls.
retain_value %2 : $MyArray<MyStruct>
apply %3(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
fix_lifetime %0 : $MyArrayContainer<MyStruct>
apply %4(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
release_value %2 : $MyArray<MyStruct>
apply %6(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %7(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb5, bb6
bb6:
br bb7
bb7:
// Failure b/c use is in between apply and retain.
retain_value %2 : $MyArray<MyStruct>
fix_lifetime %0 : $MyArrayContainer<MyStruct>
apply %3(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
apply %4(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
release_value %2 : $MyArray<MyStruct>
apply %6(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %7(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb7, bb8
bb8:
br bb9
bb9:
// Failure b/c of release_value
retain_value %00 : $Builtin.NativeObject
retain_value %2 : $MyArray<MyStruct>
apply %3(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
apply %4(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
release_value %00 : $Builtin.NativeObject
release_value %2 : $MyArray<MyStruct>
apply %6(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %7(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb9, bb10
bb10:
%r = tuple()
return %r : $()
}
// CHECK: sil @cow_handle_array_address_load
// CHECK: bb0([[ARRAY:%[0-9]+]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: load
// CHECK: retain
// CHECK: load
// CHECK: release
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: enum
// CHECK: mark_dependence
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: } // end sil function 'cow_handle_array_address_load'
sil @cow_handle_array_address_load : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Int1):
%2 = load %0 : $*MyArray<MyStruct>
%3 = struct_element_addr %0 : $*MyArray<MyStruct>, #MyArray.buffer
%4 = struct_element_addr %3 : $*ArrayIntBuffer, #ArrayIntBuffer.storage
br bb1
bb1:
%6 = load %4 : $*Builtin.NativeObject
strong_retain %6 : $Builtin.NativeObject
%l = load %1 : $*Builtin.Int1
strong_release %6 : $Builtin.NativeObject
%10 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%11 = apply %10(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%12 = enum $Optional<MyArray<MyStruct>>, #Optional.some!enumelt, %2 : $MyArray<MyStruct>
%13 = mark_dependence %1 : $*Builtin.Int1 on %12 : $Optional<MyArray<MyStruct>>
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br %l, bb1, bb2
bb2:
%15 = tuple ()
return %15 : $()
}
// CHECK-LABEL: sil @cow_type_based_hoisting_retain_release_matching : $@convention(thin) (@guaranteed MyArrayContainer<MyStruct>, Builtin.NativeObject) -> () {
// CHECK: bb0
// CHECK: [[F:%.*]] = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
// CHECK-NOT: apply [[F]](
// CHECK: bb1:
// CHECK: apply [[F]](
// CHECK: bb2:
// CHECK-NOT: apply [[F]](
// CHECK: bb3:
// CHECK: apply [[F]](
// CHECK: bb4:
sil @cow_type_based_hoisting_retain_release_matching : $@convention(thin) (@guaranteed MyArrayContainer<MyStruct>, Builtin.NativeObject) -> () {
bb0(%0 : $MyArrayContainer<MyStruct>, %00 : $Builtin.NativeObject):
%1 = ref_element_addr %0 : $MyArrayContainer<MyStruct>, #MyArrayContainer.array
%2 = load %1 : $*MyArray<MyStruct>
%3 = function_ref @guaranteed_array_get_count : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
%4 = function_ref @guaranteed_array_get_capacity : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
%5 = function_ref @unknown : $@convention(thin) () -> ()
%6 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_unknown_mutate : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%9 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
br bb1
bb1:
retain_value %2 : $MyArray<MyStruct>
retain_value %00 : $Builtin.NativeObject
release_value %00: $Builtin.NativeObject
apply %3(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
apply %4(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
release_value %2 : $MyArray<MyStruct>
apply %6(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %9(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
br bb3
bb3:
retain_value %2 : $MyArray<MyStruct>
apply %7(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %3(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
apply %4(%2) : $@convention(method) (@guaranteed MyArray<MyStruct>) -> Int
release_value %2 : $MyArray<MyStruct>
apply %6(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
apply %9(%1) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb3, bb4
bb4:
%8 = tuple()
return %8 : $()
}
struct _MyBridgeStorage {
var rawValue : Builtin.BridgeObject
}
struct _My2dArrayBuffer<T> {
var _storage : _MyBridgeStorage
}
struct My2dArray<T> {
var _buffer : _My2dArrayBuffer<T>
}
struct MyInt {
@_hasStorage var _value: Builtin.Int64
init(_ value: Int16)
}
// CHECK-LABEL: sil @hoist_projections
// CHECK: bb0
// CHECK: [[SE:%[0-9]+]] = struct_element_addr %0
// CHECK: [[ARRAY:%[0-9]+]] = struct_element_addr [[SE]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: bb2({{.*}}):
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: } // end sil function 'hoist_projections'
sil @hoist_projections : $@convention(thin) (@inout ContainerContainer, @inout Builtin.Int1) -> () {
bb0(%0 : $*ContainerContainer, %1 : $*Builtin.Int1):
br bb1
bb1:
%2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container
br bb3(%2 : $*Container)
bb3(%3: $*Container):
%4 = struct_element_addr %3 : $*Container, #Container.array
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%4) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%4) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_non_unary_projections
// CHECK: bb0
// CHECK: [[SE:%[0-9]+]] = struct_element_addr %0
// CHECK: [[IA:%[0-9]+]] = index_addr [[SE]]
// CHECK: [[ARRAY:%[0-9]+]] = struct_element_addr [[IA]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: bb2({{.*}}):
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: } // end sil function 'hoist_non_unary_projections'
sil @hoist_non_unary_projections : $@convention(thin) (@inout ContainerContainer, @inout Builtin.Int1) -> () {
bb0(%0 : $*ContainerContainer, %1 : $*Builtin.Int1):
%i = integer_literal $Builtin.Int32, 0
br bb1
bb1:
%2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container
br bb2(%2 : $*Container)
bb2(%3: $*Container):
%3i = index_addr %3 : $*Container, %i : $Builtin.Int32
%4 = struct_element_addr %3i : $*Container, #Container.array
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%4) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%4) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb3
bb3:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_projections2
// CHECK: bb0
// CHECK: [[SE:%[0-9]+]] = struct_element_addr %0
// CHECK: [[ARRAY:%[0-9]+]] = struct_element_addr [[SE]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: bb2({{.*}}):
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]
// CHECK: } // end sil function 'hoist_projections2'
sil @hoist_projections2 : $@convention(thin) (@inout ContainerContainer, @inout Builtin.Int1) -> () {
bb0(%0 : $*ContainerContainer, %1 : $*Builtin.Int1):
br bb1
bb1:
%2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container
%3 = struct_element_addr %2 : $*Container, #Container.array
br bb3(%3 : $*MyArray<MyStruct>)
bb3(%4 : $*MyArray<MyStruct>):
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%4) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%4) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_projections3
// CHECK: bb0
// CHECK: [[SE:%[0-9]+]] = struct_element_addr %0
// CHECK: [[ARRAY:%[0-9]+]] = struct_element_addr [[SE]]
// CHECK: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: bb1:
// CHECK: apply [[MM]]([[ARRAY]]
// CHECK: apply [[EM]]([[ARRAY]]
// CHECK: } // end sil function 'hoist_projections3'
sil @hoist_projections3 : $@convention(thin) (@inout ContainerContainer, @inout Builtin.Int1) -> () {
bb0(%0 : $*ContainerContainer, %1 : $*Builtin.Int1):
br bb1
bb1:
%2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container
%3 = struct_element_addr %2 : $*Container, #Container.array
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%3) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%8 = apply %7(%3) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @hoist_array2d
// CHECK: bb0
// CHECK-DAG: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK-DAG: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[MM]](%0)
// CHECK: apply [[EM]](%0)
// CHECK: [[L:%[0-9]+]] = load %0
// CHECK: [[SE1:%[0-9]+]] = struct_extract [[L]]
// CHECK: [[SE2:%[0-9]+]] = struct_extract [[SE1]]
// CHECK: [[CAST:%[0-9]+]] = unchecked_ref_cast [[SE2]]
// CHECK: [[TA:%[0-9]+]] = ref_tail_addr [[CAST]]
// CHECK: [[ARR2:%[0-9]+]] = index_addr [[TA]]
// CHECK: apply [[MM]]([[ARR2]]
// CHECK: apply [[EM]]([[ARR2]]
// CHECK: bb1:
// CHECK: apply [[MM]](%0)
// CHECK: apply [[MM]]([[ARR2]]
// CHECK: apply [[EM]]([[ARR2]]
// CHECK: apply [[EM]](%0)
// CHECK: } // end sil function 'hoist_array2d'
sil @hoist_array2d : $@convention(thin) (@inout MyArray<MyStruct>) -> () {
bb0(%0 : $*MyArray<MyStruct>):
%2 = load %0 : $*MyArray<MyStruct>
%3 = integer_literal $Builtin.Word, 1
br bb1
bb1:
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = load %0 : $*MyArray<MyStruct>
%8 = struct_extract %7 : $MyArray<MyStruct>, #MyArray.buffer
%9 = struct_extract %8 : $ArrayIntBuffer, #ArrayIntBuffer.storage
%10 = unchecked_ref_cast %9 : $Builtin.NativeObject to $MyArrayStorage
%11 = ref_tail_addr %10 : $MyArrayStorage, $MyArray<MyStruct>
%12 = index_addr %11 : $*MyArray<MyStruct>, %3 : $Builtin.Word
%13 = apply %5(%12) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%14 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%15 = apply %14(%12) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%16 = apply %14(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @dont_hoist_inner_mutating_outer
// CHECK: bb0
// CHECK-DAG: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]](%0)
// CHECK-DAG: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]](%0)
// CHECK: bb1:
// CHECK: apply [[MM]](%0)
// CHECK: [[L:%[0-9]+]] = load %0
// CHECK: [[SE1:%[0-9]+]] = struct_extract [[L]]
// CHECK: [[SE2:%[0-9]+]] = struct_extract [[SE1]]
// CHECK: [[CAST:%[0-9]+]] = unchecked_ref_cast [[SE2]]
// CHECK: [[TA:%[0-9]+]] = ref_tail_addr [[CAST]]
// CHECK: [[ARR2:%[0-9]+]] = index_addr [[TA]]
// CHECK: apply [[MM]]([[ARR2]]
// CHECK: apply [[EM]]([[ARR2]]
// CHECK: apply [[EM]](%0)
// CHECK: } // end sil function 'dont_hoist_inner_mutating_outer'
sil @dont_hoist_inner_mutating_outer : $@convention(thin) (@inout MyArray<MyStruct>) -> () {
bb0(%0 : $*MyArray<MyStruct>):
%2 = load %0 : $*MyArray<MyStruct>
%3 = integer_literal $Builtin.Word, 1
%4 = function_ref @array_unknown_mutate : $@convention(method) (@inout MyArray<MyStruct>) -> ()
br bb1
bb1:
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = load %0 : $*MyArray<MyStruct>
%8 = struct_extract %7 : $MyArray<MyStruct>, #MyArray.buffer
%9 = struct_extract %8 : $ArrayIntBuffer, #ArrayIntBuffer.storage
%10 = unchecked_ref_cast %9 : $Builtin.NativeObject to $MyArrayStorage
%11 = ref_tail_addr %10 : $MyArrayStorage, $MyArray<MyStruct>
%12 = index_addr %11 : $*MyArray<MyStruct>, %3 : $Builtin.Word
%13 = apply %5(%12) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%14 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%15 = apply %14(%12) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%16 = apply %4(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%17 = apply %14(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @dont_hoist_inner_variant_index
// CHECK: bb0
// CHECK-DAG: [[MM:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[MM]](%0)
// CHECK-DAG: [[EM:%[0-9]+]] = function_ref @array_end_mutation
// CHECK: apply [[EM]](%0)
// CHECK: bb1:
// CHECK: apply [[MM]](%0)
// CHECK: [[L:%[0-9]+]] = load %0
// CHECK: [[SE1:%[0-9]+]] = struct_extract [[L]]
// CHECK: [[SE2:%[0-9]+]] = struct_extract [[SE1]]
// CHECK: [[CAST:%[0-9]+]] = unchecked_ref_cast [[SE2]]
// CHECK: [[TA:%[0-9]+]] = ref_tail_addr [[CAST]]
// CHECK: [[ARR2:%[0-9]+]] = index_addr [[TA]]
// CHECK: apply [[MM]]([[ARR2]]
// CHECK: apply [[EM]]([[ARR2]]
// CHECK: apply [[EM]](%0)
// CHECK: } // end sil function 'dont_hoist_inner_variant_index'
sil @dont_hoist_inner_variant_index : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Word) -> () {
bb0(%0 : $*MyArray<MyStruct>, %1 : $*Builtin.Word):
%2 = load %0 : $*MyArray<MyStruct>
br bb1
bb1:
%4 = load %1 : $*Builtin.Word
%5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%6 = apply %5(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%7 = load %0 : $*MyArray<MyStruct>
%8 = struct_extract %7 : $MyArray<MyStruct>, #MyArray.buffer
%9 = struct_extract %8 : $ArrayIntBuffer, #ArrayIntBuffer.storage
%10 = unchecked_ref_cast %9 : $Builtin.NativeObject to $MyArrayStorage
%11 = ref_tail_addr %10 : $MyArrayStorage, $MyArray<MyStruct>
%12 = index_addr %11 : $*MyArray<MyStruct>, %4 : $Builtin.Word
%13 = apply %5(%12) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%14 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%15 = apply %14(%12) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
%17 = apply %14(%0) : $@convention(method) (@inout MyArray<MyStruct>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}