// 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 { 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, @inout MyBool) -> MyBool { bb0(%0 : $*MyArray, %1 : $*MyBool): %3 = load %0 : $*MyArray br bb1 bb1: %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray) -> Bool %4 = load %1 : $*MyBool retain_value %3 : $MyArray %5 = apply %2(%3) : $@convention(method) (@owned MyArray) -> 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, @inout MyBool, @owned AProtocol) -> MyBool { bb0(%0 : $*MyArray, %1 : $*MyBool, %10 : $AProtocol): %3 = load %0 : $*MyArray br bb1 bb1: %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray) -> Bool %4 = load %1 : $*MyBool retain_value %3 : $MyArray %5 = apply %2(%3) : $@convention(method) (@owned MyArray) -> 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) -> Bool { bb0(%0: $MyArray): unreachable } sil public_external [_semantics "array.props.isNativeTypeChecked"] @arrayPropertyIsNativeGuaranteed : $@convention(method) (@guaranteed MyArray) -> Bool { bb0(%0: $MyArray): 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, @inout MyBool) -> (MyBool, @error any Error) { bb0(%0 : $*MyArray, %1 : $*MyBool): %3 = load %0 : $*MyArray br bb1 bb1: %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray) -> Bool %4 = load %1 : $*MyBool retain_value %3 : $MyArray %5 = apply %2(%3) : $@convention(method) (@owned MyArray) -> 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, @inout Builtin.Int1) -> Builtin.Int1 { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %3 = load %0 : $*MyArray br bb1 bb1: %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray) -> Bool %4 = load %1 : $*Builtin.Int1 retain_value %3 : $MyArray %5 = apply %2(%3) : $@convention(method) (@owned MyArray) -> 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, @inout Builtin.Int1) -> Builtin.Int1 { bb0(%0 : $*MyArray, %1 : $*Builtin.Int1): %3 = load %0 : $*MyArray br bb1 bb1: %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray) -> Bool %4 = load %1 : $*Builtin.Int1 retain_value %3 : $MyArray %5 = apply %2(%3) : $@convention(method) (@owned MyArray) -> 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 } 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) -> Bool // apply [[FUNC]] // apply [[FUNC]] // CHECK-LABEL: } // end sil function 'test_sink_address_proj' sil @test_sink_address_proj : $@convention(thin) (@inout MyArray, @in_guaranteed WrapperStruct) -> () { bb0(%0 : $*MyArray, %1 : $*WrapperStruct): %3 = load %0 : $*MyArray br bb1 bb1: %2 = function_ref @arrayPropertyIsNative : $@convention(method) (@owned MyArray) -> Bool retain_value %3 : $MyArray %5 = apply %2(%3) : $@convention(method) (@owned MyArray) -> 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) -> Bool sil [_semantics "array.get_element"] @getElement : $@convention(method) (MyInt, Bool, _DependenceToken, @guaranteed Array) -> @owned Klass sil [_semantics "array.get_count"] @getCount : $@convention(method) (@guaranteed Array) -> 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) -> Bool // apply [[FUNC]] // apply [[FUNC]] // CHECK-LABEL: } // end sil function 'test_array_prop_opt' sil @test_array_prop_opt : $@convention(thin) (@guaranteed Optional>) -> MyInt { bb0(%0 : $Optional>): %4 = integer_literal $Builtin.Int64, 0 switch_enum %0 : $Optional>, case #Optional.some!enumelt: bb2, case #Optional.none!enumelt: bb1 bb1: br bb12(%4 : $Builtin.Int64) bb2(%12 : $Array): %14 = function_ref @getCount : $@convention(method) (@guaranteed Array) -> MyInt retain_value %0 : $Optional> retain_value %0 : $Optional> %17 = apply %14(%12) : $@convention(method) (@guaranteed Array) -> 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> %22 = unchecked_enum_data %0 : $Optional>, #Optional.some!enumelt %23 = struct_extract %22 : $Array, #Array._buffer %24 = struct_extract %23 : $_ArrayBuffer, #_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) -> Bool %29 = function_ref @getElement : $@convention(method) (MyInt, Bool, _DependenceToken, @guaranteed Array) -> @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) -> Bool %37 = apply %29(%35, %36, %32, %12) : $@convention(method) (MyInt, Bool, _DependenceToken, @guaranteed Array) -> @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 %45 = load %44 : $*Optional end_access %44 : $*Optional switch_enum %45 : $Optional, 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> release_value %0 : $Optional> br bb12(%4 : $Builtin.Int64) bb8: br bb5(%39 : $Builtin.Int64) bb9: release_value %0 : $Optional> %57 = begin_access [read] [dynamic] [no_nested_conflict] %43 : $*Optional %58 = load %57 : $*Optional end_access %57 : $*Optional switch_enum %58 : $Optional, 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> 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) -> Bool // CHECK: apply [[FUNC1]] // CHECK: [[FUNC2:%.*]] = function_ref @arrayPropertyIsNativeGuaranteed : $@convention(method) (@guaranteed MyArray) -> Bool // CHECK: apply [[FUNC2]] // CHECK-LABEL: } // end sil function 'load_copy_within_loop' sil @load_copy_within_loop : $@convention(thin) (@inout MyArray, @inout MyBool) -> MyBool { bb0(%0 : $*MyArray, %1 : $*MyBool): br bb1 bb1: %3 = load %0 retain_value %3 %5 = load %1 %6 = function_ref @arrayPropertyIsNativeGuaranteed : $@convention(method) (@guaranteed MyArray) -> Bool %7 = apply %6(%3) : $@convention(method) (@guaranteed MyArray) -> Bool release_value %3 cond_br undef, bb2, bb3 bb2: br bb1 bb3: return %5 }