// 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 { var buffer : ArrayIntBuffer } struct MyStruct { } class MyArrayContainer { var array: MyArray init() deinit } struct Container { var array: MyArray } 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) -> () sil [_semantics "array.end_mutation"] @array_end_mutation : $@convention(method) (@inout MyArray) -> () sil [_semantics "array.get_count"] @guaranteed_array_get_count : $@convention(method) (@guaranteed MyArray) -> Int sil [_semantics "array.get_capacity"] @guaranteed_array_get_capacity : $@convention(method) (@guaranteed MyArray) -> Int sil [_semantics "array.mutate_unknown"] @array_unknown_mutate : $@convention(method) (@inout MyArray) -> () // 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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): debug_value %0 : $*MyArray, expr op_deref %2 = load %0 : $*MyArray br bb1 bb1: %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () 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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %2 = load %0 : $*MyArray br bb1 bb1: retain_value %2 : $MyArray %3 = load %1 : $*Builtin.Int1 %4 = load %0 : $*MyArray release_value %2 : $MyArray %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () 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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %2 = load %0 : $*MyArray br bb1 bb1: retain_value %2 : $MyArray %3 = load %1 : $*Builtin.Int1 %4 = load %0 : $*MyArray %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () 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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): br bb1 bb1: %10 = load %0 : $*MyArray %11 = load %0 : $*MyArray %12 = struct_extract %10 : $MyArray, #MyArray.buffer %13 = struct_extract %11 : $MyArray, #MyArray.buffer retain_value %12 : $ArrayIntBuffer retain_value %13 : $ArrayIntBuffer release_value %13 : $ArrayIntBuffer %3 = load %1 : $*Builtin.Int1 %4 = load %0 : $*MyArray %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () 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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %2 = load %0 : $*MyArray br bb1 bb1: %3 = load %1 : $*Builtin.Int1 %4 = load %0 : $*MyArray release_value %2 : $MyArray %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () 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, @inout Builtin.Int1) -> MyArray { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): debug_value %0 : $*MyArray, expr op_deref %2 = load %0 : $*MyArray br bb1(%2 : $MyArray) bb1(%p1 : $MyArray): 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) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () %9 = load %0 : $*MyArray br bb4(%9 : $MyArray) bb3: br bb4(%p1 : $MyArray) bb4(%p2 : $MyArray): cond_br undef, bb1(%p2 : $MyArray), bb5(%p2 : $MyArray) bb5(%p3 : $MyArray): return %p3 : $MyArray } // CHECK-LABEL: sil @cow_should_ignore_mark_dependence_addrproj_use : $@convention(thin) (@inout MyArray, @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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %999 = struct_element_addr %0 : $*MyArray, #MyArray.buffer %9999 = struct_element_addr %999 : $*ArrayIntBuffer, #ArrayIntBuffer.storage %99999 = load %9999 : $*Builtin.NativeObject %2 = load %0 : $*MyArray br bb1 bb1: retain_value %2 : $MyArray %3 = load %1 : $*Builtin.Int1 %4 = load %0 : $*MyArray release_value %2 : $MyArray %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () 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, @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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %2 = load %0 : $*MyArray br bb1 bb1: retain_value %2 : $MyArray %3 = load %1 : $*Builtin.Int1 %4 = load %0 : $*MyArray release_value %2 : $MyArray %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () mark_dependence %1 : $*Builtin.Int1 on %2 : $MyArray cond_br %3, bb1, bb2 bb2: %r = tuple() return %r : $() } // CHECK-LABEL: sil @cow_should_ignore_enum : $@convention(thin) (@inout MyArray, @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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %2 = load %0 : $*MyArray br bb1 bb1: retain_value %2 : $MyArray %3 = load %1 : $*Builtin.Int1 %4 = load %0 : $*MyArray release_value %2 : $MyArray %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %e = enum $Optional>, #Optional.some!enumelt, %2 : $MyArray mark_dependence %1 : $*Builtin.Int1 on %e : $Optional> %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () cond_br %3, bb1, bb2 bb2: %r = tuple() return %r : $() } // CHECK-LABEL: sil @cow_should_ignore_guaranteed_semantic_call_sequence : $@convention(thin) (@guaranteed MyArrayContainer, Builtin.NativeObject) -> () { // CHECK: bb0 // CHECK-DAG: [[MM:%[0-9]+]] = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () // 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, Builtin.NativeObject) -> () { bb0(%0 : $MyArrayContainer, %00 : $Builtin.NativeObject): %1 = ref_element_addr %0 : $MyArrayContainer, #MyArrayContainer.array %2 = load %1 : $*MyArray %3 = function_ref @guaranteed_array_get_count : $@convention(method) (@guaranteed MyArray) -> Int %4 = function_ref @guaranteed_array_get_capacity : $@convention(method) (@guaranteed MyArray) -> Int %5 = function_ref @unknown : $@convention(thin) () -> () %6 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () br bb1 bb1: // Simple case. This should hoist. retain_value %2 : $MyArray apply %3(%2) : $@convention(method) (@guaranteed MyArray) -> Int apply %4(%2) : $@convention(method) (@guaranteed MyArray) -> Int release_value %2 : $MyArray apply %6(%1) : $@convention(method) (@inout MyArray) -> () apply %7(%1) : $@convention(method) (@inout MyArray) -> () cond_br undef, bb1, bb2 bb2: br bb3 bb3: // Failure case b/c of use in between release and call. retain_value %2 : $MyArray apply %3(%2) : $@convention(method) (@guaranteed MyArray) -> Int apply %4(%2) : $@convention(method) (@guaranteed MyArray) -> Int fix_lifetime %0 : $MyArrayContainer release_value %2 : $MyArray apply %6(%1) : $@convention(method) (@inout MyArray) -> () apply %7(%1) : $@convention(method) (@inout MyArray) -> () cond_br undef, bb4, bb3 bb4: br bb5 bb5: // Failure case b/c of use in between calls. retain_value %2 : $MyArray apply %3(%2) : $@convention(method) (@guaranteed MyArray) -> Int fix_lifetime %0 : $MyArrayContainer apply %4(%2) : $@convention(method) (@guaranteed MyArray) -> Int release_value %2 : $MyArray apply %6(%1) : $@convention(method) (@inout MyArray) -> () apply %7(%1) : $@convention(method) (@inout MyArray) -> () cond_br undef, bb5, bb6 bb6: br bb7 bb7: // Failure b/c use is in between apply and retain. retain_value %2 : $MyArray fix_lifetime %0 : $MyArrayContainer apply %3(%2) : $@convention(method) (@guaranteed MyArray) -> Int apply %4(%2) : $@convention(method) (@guaranteed MyArray) -> Int release_value %2 : $MyArray apply %6(%1) : $@convention(method) (@inout MyArray) -> () apply %7(%1) : $@convention(method) (@inout MyArray) -> () cond_br undef, bb7, bb8 bb8: br bb9 bb9: // Failure b/c of release_value retain_value %00 : $Builtin.NativeObject retain_value %2 : $MyArray apply %3(%2) : $@convention(method) (@guaranteed MyArray) -> Int apply %4(%2) : $@convention(method) (@guaranteed MyArray) -> Int release_value %00 : $Builtin.NativeObject release_value %2 : $MyArray apply %6(%1) : $@convention(method) (@inout MyArray) -> () apply %7(%1) : $@convention(method) (@inout MyArray) -> () 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, @inout Builtin.Int1) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %2 = load %0 : $*MyArray %3 = struct_element_addr %0 : $*MyArray, #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) -> () %11 = apply %10(%0) : $@convention(method) (@inout MyArray) -> () %12 = enum $Optional>, #Optional.some!enumelt, %2 : $MyArray %13 = mark_dependence %1 : $*Builtin.Int1 on %12 : $Optional> %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%0) : $@convention(method) (@inout MyArray) -> () cond_br %l, bb1, bb2 bb2: %15 = tuple () return %15 : $() } // CHECK-LABEL: sil @cow_type_based_hoisting_retain_release_matching : $@convention(thin) (@guaranteed MyArrayContainer, Builtin.NativeObject) -> () { // CHECK: bb0 // CHECK: [[F:%.*]] = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () // 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, Builtin.NativeObject) -> () { bb0(%0 : $MyArrayContainer, %00 : $Builtin.NativeObject): %1 = ref_element_addr %0 : $MyArrayContainer, #MyArrayContainer.array %2 = load %1 : $*MyArray %3 = function_ref @guaranteed_array_get_count : $@convention(method) (@guaranteed MyArray) -> Int %4 = function_ref @guaranteed_array_get_capacity : $@convention(method) (@guaranteed MyArray) -> Int %5 = function_ref @unknown : $@convention(thin) () -> () %6 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_unknown_mutate : $@convention(method) (@inout MyArray) -> () %9 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () br bb1 bb1: retain_value %2 : $MyArray retain_value %00 : $Builtin.NativeObject release_value %00: $Builtin.NativeObject apply %3(%2) : $@convention(method) (@guaranteed MyArray) -> Int apply %4(%2) : $@convention(method) (@guaranteed MyArray) -> Int release_value %2 : $MyArray apply %6(%1) : $@convention(method) (@inout MyArray) -> () apply %9(%1) : $@convention(method) (@inout MyArray) -> () cond_br undef, bb1, bb2 bb2: br bb3 bb3: retain_value %2 : $MyArray apply %7(%1) : $@convention(method) (@inout MyArray) -> () apply %3(%2) : $@convention(method) (@guaranteed MyArray) -> Int apply %4(%2) : $@convention(method) (@guaranteed MyArray) -> Int release_value %2 : $MyArray apply %6(%1) : $@convention(method) (@inout MyArray) -> () apply %9(%1) : $@convention(method) (@inout MyArray) -> () cond_br undef, bb3, bb4 bb4: %8 = tuple() return %8 : $() } struct _MyBridgeStorage { var rawValue : Builtin.BridgeObject } struct _My2dArrayBuffer { var _storage : _MyBridgeStorage } struct My2dArray { var _buffer : _My2dArrayBuffer } 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: br bb3 bb3: %3 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container %4 = struct_element_addr %3 : $*Container, #Container.array %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%4) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%4) : $@convention(method) (@inout MyArray) -> () 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: br bb2 bb2: %3 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.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) -> () %6 = apply %5(%4) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%4) : $@convention(method) (@inout MyArray) -> () 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: br bb3 bb3: %2 = struct_element_addr %0 : $*ContainerContainer, #ContainerContainer.container %4 = struct_element_addr %2 : $*Container, #Container.array %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%4) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%4) : $@convention(method) (@inout MyArray) -> () 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) -> () %6 = apply %5(%3) : $@convention(method) (@inout MyArray) -> () %7 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %8 = apply %7(%3) : $@convention(method) (@inout MyArray) -> () 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) -> () { bb0(%0 : $*MyArray): %2 = load %0 : $*MyArray %3 = integer_literal $Builtin.Word, 1 br bb1 bb1: %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = load %0 : $*MyArray %8 = struct_extract %7 : $MyArray, #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 %12 = index_addr %11 : $*MyArray, %3 : $Builtin.Word %13 = apply %5(%12) : $@convention(method) (@inout MyArray) -> () %14 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %15 = apply %14(%12) : $@convention(method) (@inout MyArray) -> () %16 = apply %14(%0) : $@convention(method) (@inout MyArray) -> () 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) -> () { bb0(%0 : $*MyArray): %2 = load %0 : $*MyArray %3 = integer_literal $Builtin.Word, 1 %4 = function_ref @array_unknown_mutate : $@convention(method) (@inout MyArray) -> () br bb1 bb1: %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = load %0 : $*MyArray %8 = struct_extract %7 : $MyArray, #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 %12 = index_addr %11 : $*MyArray, %3 : $Builtin.Word %13 = apply %5(%12) : $@convention(method) (@inout MyArray) -> () %14 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %15 = apply %14(%12) : $@convention(method) (@inout MyArray) -> () %16 = apply %4(%0) : $@convention(method) (@inout MyArray) -> () %17 = apply %14(%0) : $@convention(method) (@inout MyArray) -> () 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, @inout Builtin.Word) -> () { bb0(%0 : $*MyArray, %1 : $*Builtin.Word): %2 = load %0 : $*MyArray br bb1 bb1: %4 = load %1 : $*Builtin.Word %5 = function_ref @array_make_mutable : $@convention(method) (@inout MyArray) -> () %6 = apply %5(%0) : $@convention(method) (@inout MyArray) -> () %7 = load %0 : $*MyArray %8 = struct_extract %7 : $MyArray, #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 %12 = index_addr %11 : $*MyArray, %4 : $Builtin.Word %13 = apply %5(%12) : $@convention(method) (@inout MyArray) -> () %14 = function_ref @array_end_mutation : $@convention(method) (@inout MyArray) -> () %15 = apply %14(%12) : $@convention(method) (@inout MyArray) -> () %17 = apply %14(%0) : $@convention(method) (@inout MyArray) -> () cond_br undef, bb1, bb2 bb2: %r = tuple() return %r : $() }