blob: b9daa50932832057832447bbc9622aa0e8d4382d [file] [log] [blame]
// 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.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: [[FUN:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[FUN]]([[ARRAY]]
// CHECK: bb1
// CHECK-NOT: array_make_mutable
// CHECK-NOT: apply [[FUN]]
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>) -> ()
cond_br undef, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @hoist_ignoring_paired_retain_release_and_hoist
// CHECK: bb0(
// CHECK-NOT: br bb
// CHECK: [[MM:%.*]] = function_ref @array_make_mutable
// CHECK-NOT: br bb
// CHECK: apply [[MM]]
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NOT: apply
// CHECK: cond_br {{.*}}, bb1
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>) -> ()
cond_br %3, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// 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>) -> ()
cond_br %3, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// 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>
%8 = struct_extract %10 : $MyArray<MyStruct>, #MyArray.buffer
%9 = struct_extract %11 : $MyArray<MyStruct>, #MyArray.buffer
retain_value %8 : $ArrayIntBuffer
retain_value %9 : $ArrayIntBuffer
release_value %9 : $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>) -> ()
cond_br %3, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @hoist_not_blocked_by_unpaired_release
// CHECK: bb0(
// CHECK-NOT: br bb
// CHECK: [[MM:%.*]] = function_ref @array_make_mutable
// CHECK-NOT: br bb
// CHECK: apply [[MM]]
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NOT: apply
// CHECK: cond_br {{.*}}, bb1
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>) -> ()
cond_br %3, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// 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 = load %0 : $*MyArray<MyStruct>
br bb4(%7 : $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(
// CHECK-NOT: br bb
// CHECK: [[MM:%.*]] = function_ref @array_make_mutable
// CHECK-NOT: br bb
// CHECK: apply [[MM]]
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NOT: apply
// CHECK: cond_br {{.*}}, bb1
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>) -> ()
mark_dependence %1 : $*Builtin.Int1 on %99999 : $Builtin.NativeObject
cond_br %3, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @cow_should_ignore_mark_dependence_value : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
// CHECK: bb0(
// CHECK-NOT: br bb
// CHECK: [[MM:%.*]] = function_ref @array_make_mutable
// CHECK-NOT: br bb
// CHECK: apply [[MM]]
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NOT: apply
// CHECK: cond_br {{.*}}, bb1
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>) -> ()
mark_dependence %1 : $*Builtin.Int1 on %2 : $MyArray<MyStruct>
cond_br %3, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @cow_should_ignore_enum : $@convention(thin) (@inout MyArray<MyStruct>, @inout Builtin.Int1) -> () {
// CHECK: bb0(
// CHECK-NOT: br bb
// CHECK: [[MM:%.*]] = function_ref @array_make_mutable
// CHECK-NOT: br bb
// CHECK: apply [[MM]]
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NOT: apply
// CHECK: cond_br {{.*}}, bb1
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>) -> ()
%8 = enum $Optional<MyArray<MyStruct>>, #Optional.some!enumelt.1, %2 : $MyArray<MyStruct>
mark_dependence %1 : $*Builtin.Int1 on %8 : $Optional<MyArray<MyStruct>>
cond_br %3, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @cow_should_ignore_guaranteed_semantic_call_sequence : $@convention(thin) (@guaranteed MyArrayContainer<MyStruct>, Builtin.NativeObject) -> () {
// CHECK: bb0
// CHECK: [[F:%.*]] = function_ref @array_make_mutable : $@convention(method) (@inout MyArray<MyStruct>) -> ()
// CHECK: apply [[F]](
// CHECK: bb1:
// CHECK: bb2:
// CHECK-NOT: apply [[F]](
// CHECK: bb3:
// CHECK: bb4:
// CHECK-NOT: apply [[F]](
// CHECK: bb5:
// CHECK: bb6:
// CHECK-NOT: apply [[F]](
// CHECK: bb7:
// CHECK: bb8:
// CHECK-NOT: apply [[F]](
// CHECK: bb9:
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>) -> ()
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>) -> ()
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>) -> ()
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>) -> ()
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>) -> ()
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>) -> ()
cond_br undef, bb9, bb10
bb10:
%7 = tuple()
return %7 : $()
}
// CHECK: sil @cow_handle_array_address_load
// CHECK: bb0({{.*}}):
// CHECK: apply
// CHECK: br bb1
// CHECK: bb1:
// CHECK-NOT: apply
// CHECK: bb2
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
%8 = 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.1, %2 : $MyArray<MyStruct>
%13 = mark_dependence %1 : $*Builtin.Int1 on %12 : $Optional<MyArray<MyStruct>>
cond_br %8, 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>) -> ()
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>) -> ()
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>) -> ()
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([[CONTAINER:%[0-9]+]]
// CHECK: [[CONTAINER2:%.*]] = struct_element_addr [[CONTAINER]] : $*ContainerContainer
// CHECK: [[ARRAY:%.*]] = struct_element_addr [[CONTAINER2]] : $*Container,
// CHECK: [[FUN:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[FUN]]([[ARRAY]]
// CHECK: bb1
// CHECK-NOT: array_make_mutable
// CHECK-NOT: apply [[FUN]]
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>) -> ()
cond_br undef, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @hoist_non_unary_projections
// CHECK: index_addr
// CHECK: struct_element_addr
// CHECK: bb1:
// CHECK-NOT: index_addr
// CHECK-NOT: struct_element_addr
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>) -> ()
cond_br undef, bb1, bb3
bb3:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @hoist_projections2
// CHECK: bb0([[CONTAINER:%[0-9]+]]
// CHECK: [[CONTAINER2:%.*]] = struct_element_addr [[CONTAINER]] : $*ContainerContainer
// CHECK: [[ARRAY:%.*]] = struct_element_addr [[CONTAINER2]] : $*Container,
// CHECK: [[FUN:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[FUN]]([[ARRAY]]
// CHECK: bb1
// CHECK-NOT: array_make_mutable
// CHECK-NOT: apply [[FUN]]
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>) -> ()
cond_br undef, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @hoist_projections3
// CHECK: bb0([[CONTAINER:%[0-9]+]]
// CHECK: [[CONTAINER2:%.*]] = struct_element_addr [[CONTAINER]] : $*ContainerContainer
// CHECK: [[ARRAY:%.*]] = struct_element_addr [[CONTAINER2]] : $*Container,
// CHECK: [[FUN:%[0-9]+]] = function_ref @array_make_mutable
// CHECK: apply [[FUN]]([[ARRAY]]
// CHECK: bb1
// CHECK-NOT: array_make_mutable
// CHECK-NOT: apply [[FUN]]
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>) -> ()
cond_br undef, bb1, bb2
bb2:
%7 = tuple()
return %7 : $()
}
// CHECK-LABEL: sil @hoist_array2d
// CHECK: bb0({{.*}}):
// CHECK: apply
// CHECK-NEXT: load
// CHECK-NEXT: struct_extract
// CHECK-NEXT: struct_extract
// CHECK-NEXT: unchecked_ref_cast
// CHECK-NEXT: ref_tail_addr
// CHECK-NEXT: index_addr
// CHECK-NEXT: apply
// CHECK-NEXT: br bb1
// CHECK: bb1:
// CHECK-NOT: apply
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>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}
// CHECK-LABEL: sil @dont_hoist_inner_mutating_outer
// CHECK: bb0({{.*}}):
// CHECK: apply
// CHECK-NOT: apply
// CHECK: bb1:
// CHECK: apply
// CHECK: apply
// CHECK-NOT: apply
// CHECK: return
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>) -> ()
apply %4(%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: apply
// CHECK-NOT: apply
// CHECK: bb1:
// CHECK: apply
// CHECK-NOT: apply
// CHECK: return
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>) -> ()
cond_br undef, bb1, bb2
bb2:
%r = tuple()
return %r : $()
}