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