| // 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 @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 : $() |
| } |
| |