mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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.
843 lines
32 KiB
Plaintext
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 : $()
|
|
}
|
|
|