mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
If we have a self value that does not dominate loop preheader, and the array semantics call does not consume the self value, that means there will be instructions that consume the self value with the loop. In ossa, we cannot hoist such semantic calls because there is no support for creating destroys for them in the preheader. Add a bailout to avoid the ownership error. rdar://145673368
444 lines
14 KiB
Plaintext
444 lines
14 KiB
Plaintext
// RUN: %target-sil-opt -parse-serialized-sil -enable-sil-verify-all %s -array-property-opt | %FileCheck %s
|
|
|
|
// Linux doesn't have the same symbol name for _ArrayBuffer, which is part of
|
|
// the ObjC runtime interop. Use `_ContiguousArrayBuffer instead.
|
|
// REQUIRES: objc_interop
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
struct ArrayIntBuffer {
|
|
var storage : Builtin.NativeObject
|
|
}
|
|
|
|
struct MyArray<T> {
|
|
var buffer : ArrayIntBuffer
|
|
}
|
|
|
|
enum MyBool{
|
|
case True
|
|
case False
|
|
}
|
|
|
|
class MyClass {
|
|
}
|
|
|
|
struct MyInt {
|
|
@_hasStorage var _value: Builtin.Int64
|
|
}
|
|
|
|
// CHECK-LABEL: sil @clone_switch_enum_exit :
|
|
// CHECK: bb1:
|
|
// CHECK: [[FUNC1:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC1]]
|
|
// CHECK: cond_br {{.*}}, bb11, bb2
|
|
// CHECK: bb2:
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK: [[FUNC2:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC2]]
|
|
// CHECK-LABEL: } // end sil function 'clone_switch_enum_exit'
|
|
|
|
/// We need to split the loop exit edge from bb1 to bb3 before updating ssa form
|
|
/// after cloning.
|
|
sil @clone_switch_enum_exit : $@convention(thin) (@inout MyArray<MyClass>, @inout MyBool) -> MyBool {
|
|
bb0(%0 : $*MyArray<MyClass>, %1 : $*MyBool):
|
|
%3 = load %0 : $*MyArray<MyClass>
|
|
br bb1
|
|
|
|
bb1:
|
|
%2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%4 = load %1 : $*MyBool
|
|
retain_value %3 : $MyArray<MyClass>
|
|
%5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
switch_enum %4 : $MyBool, case #MyBool.False!enumelt: bb5, case #MyBool.True!enumelt: bb2
|
|
|
|
bb2:
|
|
%6 = integer_literal $Builtin.Int1, -1
|
|
cond_br %6, bb3, bb4
|
|
|
|
bb3:
|
|
br bb1
|
|
|
|
bb4:
|
|
br bb6
|
|
|
|
bb5:
|
|
br bb6
|
|
|
|
bb6:
|
|
return %4 : $MyBool
|
|
}
|
|
|
|
protocol AProtocol : class {
|
|
}
|
|
|
|
// CHECK-LABEL: sil @cant_handle_open_existential_use_outside_loop :
|
|
// CHECK: bb1:
|
|
// CHECK: [[FUNC1:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC1]]
|
|
// CHECK-NOT: [[FUNC2:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK-NOT: apply [[FUNC2]]
|
|
// CHECK-LABEL: } // end sil function 'cant_handle_open_existential_use_outside_loop'
|
|
sil @cant_handle_open_existential_use_outside_loop : $@convention(thin) (@inout MyArray<MyClass>, @inout MyBool, @owned AProtocol) -> MyBool {
|
|
bb0(%0 : $*MyArray<MyClass>, %1 : $*MyBool, %10 : $AProtocol):
|
|
%3 = load %0 : $*MyArray<MyClass>
|
|
br bb1
|
|
|
|
bb1:
|
|
%2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%4 = load %1 : $*MyBool
|
|
retain_value %3 : $MyArray<MyClass>
|
|
%5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%11 = open_existential_ref %10 : $AProtocol to $@opened("B538073C-2428-11E5-AC93-C82A1428F987", AProtocol) Self
|
|
switch_enum %4 : $MyBool, case #MyBool.False!enumelt: bb5, case #MyBool.True!enumelt: bb2
|
|
|
|
bb2:
|
|
%6 = integer_literal $Builtin.Int1, -1
|
|
cond_br %6, bb3, bb4
|
|
|
|
bb3:
|
|
br bb1
|
|
|
|
bb4:
|
|
br bb6
|
|
|
|
bb5:
|
|
br bb6
|
|
|
|
bb6:
|
|
release_value %11 : $@opened("B538073C-2428-11E5-AC93-C82A1428F987", AProtocol) Self
|
|
return %4 : $MyBool
|
|
}
|
|
|
|
sil public_external [_semantics "array.props.isNativeTypeChecked"] @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool {
|
|
bb0(%0: $MyArray<MyClass>):
|
|
unreachable
|
|
}
|
|
|
|
sil public_external [_semantics "array.props.isNativeTypeChecked"] @arrayPropertyIsNativeGuaranteed : $@convention(method) (@guaranteed MyArray<MyClass>) -> Bool {
|
|
bb0(%0: $MyArray<MyClass>):
|
|
unreachable
|
|
}
|
|
|
|
// Make sure we can handle try_apply when splitting edges. This test used to crash.
|
|
|
|
sil @throwing_fun : $@convention(thin) () -> (MyBool, @error any Error)
|
|
|
|
// CHECK-LABEL: sil @clone_try_apply_exit :
|
|
// CHECK: bb1:
|
|
// CHECK: [[FUNC1:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC1]]
|
|
// CHECK: cond_br {{.*}}, bb10, bb2
|
|
// CHECK: bb2:
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK: [[FUNC2:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC2]]
|
|
// CHECK-LABEL: } // end sil function 'clone_try_apply_exit'
|
|
sil @clone_try_apply_exit : $@convention(thin) (@inout MyArray<MyClass>, @inout MyBool) -> (MyBool, @error any Error) {
|
|
bb0(%0 : $*MyArray<MyClass>, %1 : $*MyBool):
|
|
%3 = load %0 : $*MyArray<MyClass>
|
|
br bb1
|
|
|
|
bb1:
|
|
%2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%4 = load %1 : $*MyBool
|
|
retain_value %3 : $MyArray<MyClass>
|
|
%5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%7 = function_ref @throwing_fun : $@convention(thin) () -> (MyBool, @error any Error)
|
|
try_apply %7() : $@convention(thin) () -> (MyBool, @error any Error), normal bb2, error bb6
|
|
|
|
bb2(%8 : $MyBool):
|
|
%6 = integer_literal $Builtin.Int1, -1
|
|
cond_br %6, bb3, bb5
|
|
|
|
bb3:
|
|
br bb1
|
|
|
|
bb5:
|
|
return %4 : $MyBool
|
|
|
|
bb6(%9 : $Error):
|
|
throw %9 : $Error
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dominator_update_outside_non_exit_block :
|
|
// CHECK: bb1:
|
|
// CHECK: [[FUNC1:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC1]]
|
|
// CHECK: cond_br {{.*}}, bb16, bb2
|
|
// CHECK: bb2:
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK: [[FUNC2:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC2]]
|
|
// CHECK-LABEL: } // end sil function 'dominator_update_outside_non_exit_block'
|
|
sil @dominator_update_outside_non_exit_block : $@convention(thin) (@inout MyArray<MyClass>, @inout Builtin.Int1) -> Builtin.Int1 {
|
|
bb0(%0 : $*MyArray<MyClass>, %1 : $*Builtin.Int1):
|
|
%3 = load %0 : $*MyArray<MyClass>
|
|
br bb1
|
|
|
|
bb1:
|
|
%2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%4 = load %1 : $*Builtin.Int1
|
|
retain_value %3 : $MyArray<MyClass>
|
|
%5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
cond_br %4, bb2, bb7
|
|
|
|
bb2:
|
|
cond_br undef, bb3, bb6
|
|
|
|
bb3:
|
|
%6 = integer_literal $Builtin.Int1, -1
|
|
cond_br %6, bb4, bb5
|
|
|
|
bb4:
|
|
br bb1
|
|
|
|
bb5:
|
|
br bb10
|
|
|
|
bb6: // Exit block; b1 dom b4
|
|
br bb10
|
|
|
|
bb7: // Exit block; b1 dom b4
|
|
cond_br undef, bb8, bb9
|
|
|
|
bb8:
|
|
br bb10
|
|
|
|
bb9:
|
|
br bb10
|
|
|
|
bb10:
|
|
return %4 : $Builtin.Int1
|
|
}
|
|
|
|
// CHECK-LABEL: sil @dominator_update_outside_non_exit_block_2 :
|
|
// CHECK: bb1:
|
|
// CHECK: [[FUNC1:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC1]]
|
|
// CHECK: cond_br {{.*}}, bb17, bb2
|
|
// CHECK: bb2:
|
|
// CHECK: br bb3
|
|
// CHECK: bb3:
|
|
// CHECK: [[FUNC2:%.*]] = function_ref @arrayPropertyIsNative
|
|
// CHECK: apply [[FUNC2]]
|
|
// CHECK-LABEL: } // end sil function 'dominator_update_outside_non_exit_block_2'
|
|
sil @dominator_update_outside_non_exit_block_2 : $@convention(thin) (@inout MyArray<MyClass>, @inout Builtin.Int1) -> Builtin.Int1 {
|
|
bb0(%0 : $*MyArray<MyClass>, %1 : $*Builtin.Int1):
|
|
%3 = load %0 : $*MyArray<MyClass>
|
|
br bb1
|
|
|
|
bb1:
|
|
%2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%4 = load %1 : $*Builtin.Int1
|
|
retain_value %3 : $MyArray<MyClass>
|
|
%5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
cond_br %4, bb2, bb5
|
|
|
|
bb2:
|
|
cond_br undef, bb3, bb9
|
|
|
|
bb3:
|
|
%6 = integer_literal $Builtin.Int1, -1
|
|
cond_br %6, bb4, bb10
|
|
|
|
bb4:
|
|
br bb1
|
|
|
|
bb5: // Exit block; b1 dom b4
|
|
cond_br undef, bb6, bb7
|
|
|
|
bb6: // Exit Block; b1 dom b4
|
|
br bb8
|
|
|
|
bb7:
|
|
br bb8
|
|
|
|
bb8: // Non-exit Dominated by bb1
|
|
br bb11
|
|
|
|
bb9: // Exit dominated by bb3
|
|
br bb11
|
|
|
|
bb10: // Exit dominated by bb3
|
|
br bb11
|
|
|
|
bb11: // Non-exit dominated by bb1
|
|
return %4 : $Builtin.Int1
|
|
}
|
|
|
|
class Klass {
|
|
var val: Optional<MyInt>
|
|
}
|
|
|
|
struct WrapperStruct {
|
|
var val: Klass
|
|
}
|
|
|
|
sil @use_klass : $@convention(thin) (@in_guaranteed Klass) -> ()
|
|
|
|
// Test verifier does not fire for address phis
|
|
// Check if array property opt is kicking in by looking for 2 calls to hoistableIsNativeTypeChecked
|
|
// CHECK-LABEL: sil @test_sink_address_proj :
|
|
// [[FUNC:%.*]] = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
// apply [[FUNC]]
|
|
// apply [[FUNC]]
|
|
// CHECK-LABEL: } // end sil function 'test_sink_address_proj'
|
|
sil @test_sink_address_proj : $@convention(thin) (@inout MyArray<MyClass>, @in_guaranteed WrapperStruct) -> () {
|
|
bb0(%0 : $*MyArray<MyClass>, %1 : $*WrapperStruct):
|
|
%3 = load %0 : $*MyArray<MyClass>
|
|
br bb1
|
|
|
|
bb1:
|
|
%2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
retain_value %3 : $MyArray<MyClass>
|
|
%5 = apply %2(%3) : $@convention(method) (@owned MyArray<MyClass>) -> Bool
|
|
%ele = struct_element_addr %1 : $*WrapperStruct, #WrapperStruct.val
|
|
cond_br undef, bb5, bb2
|
|
|
|
bb2:
|
|
%6 = integer_literal $Builtin.Int1, -1
|
|
cond_br %6, bb3, bb4
|
|
|
|
bb3:
|
|
br bb1
|
|
|
|
bb4:
|
|
br bb6
|
|
|
|
bb5:
|
|
%f = function_ref @use_klass : $@convention(thin) (@in_guaranteed Klass) -> ()
|
|
%a = apply %f(%ele) : $@convention(thin) (@in_guaranteed Klass) -> ()
|
|
br bb6
|
|
|
|
bb6:
|
|
%t = tuple ()
|
|
return %t : $()
|
|
}
|
|
|
|
sil [_semantics "array.props.isNativeTypeChecked"] @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed Array<Klass>) -> Bool
|
|
sil [_semantics "array.get_element"] @getElement : $@convention(method) (MyInt, Bool, _DependenceToken, @guaranteed Array<Klass>) -> @owned Klass
|
|
sil [_semantics "array.get_count"] @getCount : $@convention(method) (@guaranteed Array<Klass>) -> MyInt
|
|
|
|
// Test verifier does not fire for address phis
|
|
// Check if array property opt is kicking in by looking for 2 calls to hoistableIsNativeTypeChecked
|
|
// CHECK-LABEL: sil @test_array_prop_opt :
|
|
// [[FUNC:%.*]] = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed Array<Klass>) -> Bool
|
|
// apply [[FUNC]]
|
|
// apply [[FUNC]]
|
|
// CHECK-LABEL: } // end sil function 'test_array_prop_opt'
|
|
sil @test_array_prop_opt : $@convention(thin) (@guaranteed Optional<Array<Klass>>) -> MyInt {
|
|
bb0(%0 : $Optional<Array<Klass>>):
|
|
%4 = integer_literal $Builtin.Int64, 0
|
|
switch_enum %0 : $Optional<Array<Klass>>, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb1
|
|
|
|
bb1:
|
|
br bb12(%4 : $Builtin.Int64)
|
|
|
|
bb2(%12 : $Array<Klass>):
|
|
%14 = function_ref @getCount : $@convention(method) (@guaranteed Array<Klass>) -> MyInt
|
|
retain_value %0 : $Optional<Array<Klass>>
|
|
retain_value %0 : $Optional<Array<Klass>>
|
|
%17 = apply %14(%12) : $@convention(method) (@guaranteed Array<Klass>) -> MyInt
|
|
%18 = struct_extract %17 : $MyInt, #MyInt._value
|
|
%19 = builtin "cmp_eq_Int64"(%18 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1
|
|
cond_br %19, bb3, bb4
|
|
|
|
bb3:
|
|
release_value %0 : $Optional<Array<Klass>>
|
|
%22 = unchecked_enum_data %0 : $Optional<Array<Klass>>, #Optional.some!enumelt
|
|
%23 = struct_extract %22 : $Array<Klass>, #Array._buffer
|
|
%24 = struct_extract %23 : $_ArrayBuffer<Klass>, #_ArrayBuffer._storage
|
|
%25 = struct_extract %24 : $_BridgeStorage<__ContiguousArrayStorageBase>, #_BridgeStorage.rawValue
|
|
strong_release %25 : $Builtin.BridgeObject
|
|
br bb12(%4 : $Builtin.Int64)
|
|
|
|
bb4:
|
|
%28 = function_ref @hoistableIsNativeTypeChecked : $@convention(method) (@guaranteed Array<Klass>) -> Bool
|
|
%29 = function_ref @getElement : $@convention(method) (MyInt, Bool, _DependenceToken, @guaranteed Array<Klass>) -> @owned Klass
|
|
%30 = integer_literal $Builtin.Int64, 1
|
|
%31 = integer_literal $Builtin.Int1, -1
|
|
%32 = struct $_DependenceToken ()
|
|
br bb5(%4 : $Builtin.Int64)
|
|
|
|
bb5(%34 : $Builtin.Int64):
|
|
%35 = struct $MyInt (%34 : $Builtin.Int64)
|
|
%36 = apply %28(%12) : $@convention(method) (@guaranteed Array<Klass>) -> Bool
|
|
%37 = apply %29(%35, %36, %32, %12) : $@convention(method) (MyInt, Bool, _DependenceToken, @guaranteed Array<Klass>) -> @owned Klass
|
|
%38 = builtin "sadd_with_overflow_Int64"(%34 : $Builtin.Int64, %30 : $Builtin.Int64, %31 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
|
|
%39 = tuple_extract %38 : $(Builtin.Int64, Builtin.Int1), 0
|
|
%40 = tuple_extract %38 : $(Builtin.Int64, Builtin.Int1), 1
|
|
cond_fail %40 : $Builtin.Int1, "arithmetic overflow"
|
|
%43 = ref_element_addr %37 : $Klass, #Klass.val
|
|
%44 = begin_access [read] [dynamic] [no_nested_conflict] %43 : $*Optional<MyInt>
|
|
%45 = load %44 : $*Optional<MyInt>
|
|
end_access %44 : $*Optional<MyInt>
|
|
switch_enum %45 : $Optional<MyInt>, case #Optional.some!enumelt: bb9, case #Optional.none!enumelt: bb6
|
|
|
|
bb6:
|
|
strong_release %37 : $Klass
|
|
%49 = builtin "cmp_eq_Int64"(%39 : $Builtin.Int64, %18 : $Builtin.Int64) : $Builtin.Int1
|
|
cond_br %49, bb7, bb8
|
|
|
|
bb7:
|
|
release_value %0 : $Optional<Array<Klass>>
|
|
release_value %0 : $Optional<Array<Klass>>
|
|
br bb12(%4 : $Builtin.Int64)
|
|
|
|
bb8:
|
|
br bb5(%39 : $Builtin.Int64)
|
|
|
|
bb9:
|
|
release_value %0 : $Optional<Array<Klass>>
|
|
%57 = begin_access [read] [dynamic] [no_nested_conflict] %43 : $*Optional<MyInt>
|
|
%58 = load %57 : $*Optional<MyInt>
|
|
end_access %57 : $*Optional<MyInt>
|
|
switch_enum %58 : $Optional<MyInt>, case #Optional.some!enumelt: bb11, case #Optional.none!enumelt: bb10
|
|
|
|
bb10:
|
|
cond_fail %31 : $Builtin.Int1, "Unexpectedly found nil while unwrapping an Optional value"
|
|
unreachable
|
|
|
|
bb11(%63 : $MyInt):
|
|
release_value %0 : $Optional<Array<Klass>>
|
|
strong_release %37 : $Klass
|
|
%66 = struct_extract %63 : $MyInt, #MyInt._value
|
|
br bb12(%66 : $Builtin.Int64)
|
|
|
|
bb12(%69 : $Builtin.Int64):
|
|
%70 = struct $MyInt (%69 : $Builtin.Int64)
|
|
return %70 : $MyInt
|
|
}
|
|
|
|
// CHECK-LABEL: sil @load_copy_within_loop :
|
|
// CHECK: [[FUNC1:%.*]] = function_ref @arrayPropertyIsNativeGuaranteed : $@convention(method) (@guaranteed MyArray<MyClass>) -> Bool
|
|
// CHECK: apply [[FUNC1]]
|
|
// CHECK: [[FUNC2:%.*]] = function_ref @arrayPropertyIsNativeGuaranteed : $@convention(method) (@guaranteed MyArray<MyClass>) -> Bool
|
|
// CHECK: apply [[FUNC2]]
|
|
// CHECK-LABEL: } // end sil function 'load_copy_within_loop'
|
|
sil @load_copy_within_loop : $@convention(thin) (@inout MyArray<MyClass>, @inout MyBool) -> MyBool {
|
|
bb0(%0 : $*MyArray<MyClass>, %1 : $*MyBool):
|
|
br bb1
|
|
|
|
bb1:
|
|
%3 = load %0
|
|
retain_value %3
|
|
%5 = load %1
|
|
%6 = function_ref @arrayPropertyIsNativeGuaranteed : $@convention(method) (@guaranteed MyArray<MyClass>) -> Bool
|
|
%7 = apply %6(%3) : $@convention(method) (@guaranteed MyArray<MyClass>) -> Bool
|
|
release_value %3
|
|
cond_br undef, bb2, bb3
|
|
|
|
bb2:
|
|
br bb1
|
|
|
|
bb3:
|
|
return %5
|
|
}
|
|
|