Files
swift-mirror/test/SILOptimizer/array_property_opt.sil
2023-06-30 09:33:36 -07:00

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
}