| // RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -sil-combine -verify-skip-unreachable-must-be-last | %FileCheck %s |
| // REQUIRES: objc_interop |
| |
| // FIXME: https://bugs.swift.org/browse/SR-2808 |
| // XFAIL: resilient_stdlib |
| |
| // See https://bugs.swift.org/browse/SR-5065, rdar://32511494 |
| // XFAIL: * |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| |
| class ZZZ { |
| @objc deinit |
| init() |
| } |
| |
| class C {} |
| |
| sil @stringcore_invariant_check : $@convention(thin) (@owned _LegacyStringCore) -> @owned Optional<_CocoaString> |
| sil @reabstraction_thunk : $@convention(thin) (@owned @callee_owned () -> @owned Optional<_CocoaString>) -> @out Optional<_CocoaString> |
| |
| // CHECK-LABEL: sil @dead_closure_elimination : $@convention(thin) (@owned _LegacyStringCore) -> () |
| // CHECK: bb0 |
| // CHECK-NEXT: release_value |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @dead_closure_elimination : $@convention(thin) (@owned _LegacyStringCore) -> () { |
| bb0(%0 : $_LegacyStringCore): |
| %1 = function_ref @stringcore_invariant_check : $@convention(thin) (@owned _LegacyStringCore) -> @owned Optional<_CocoaString> |
| %2 = partial_apply %1(%0) : $@convention(thin) (@owned _LegacyStringCore) -> @owned Optional<_CocoaString> |
| %3 = function_ref @reabstraction_thunk : $@convention(thin) (@owned @callee_owned () -> @owned Optional<_CocoaString>) -> @out Optional<_CocoaString> |
| %4 = partial_apply %3(%2) : $@convention(thin) (@owned @callee_owned () -> @owned Optional<_CocoaString>) -> @out Optional<_CocoaString> |
| strong_release %4 : $@callee_owned () -> @out Optional<_CocoaString> |
| %5 = tuple() |
| return %5 : $() |
| } |
| |
| // CHECK-LABEL: sil @dead_closure_elimination2 |
| // CHECK: bb0 |
| // CHECK-NEXT: br bb1 |
| // CHECK: bb1 |
| // CHECK-NEXT: release_value |
| // CHECK-NEXT: tuple |
| // CHECK-NEXT: return |
| sil @dead_closure_elimination2 : $@convention(thin) (@owned _LegacyStringCore) -> () { |
| bb0(%0 : $_LegacyStringCore): |
| %1 = function_ref @stringcore_invariant_check : $@convention(thin) (@owned _LegacyStringCore) -> @owned Optional<_CocoaString> |
| %2 = partial_apply %1(%0) : $@convention(thin) (@owned _LegacyStringCore) -> @owned Optional<_CocoaString> |
| %3 = function_ref @reabstraction_thunk : $@convention(thin) (@owned @callee_owned () -> @owned Optional<_CocoaString>) -> @out Optional<_CocoaString> |
| %4 = partial_apply %3(%2) : $@convention(thin) (@owned @callee_owned () -> @owned Optional<_CocoaString>) -> @out Optional<_CocoaString> |
| br bb1 |
| |
| bb1: |
| strong_retain %4 : $@callee_owned () -> @out Optional<_CocoaString> |
| strong_release %4 : $@callee_owned () -> @out Optional<_CocoaString> |
| strong_release %4 : $@callee_owned () -> @out Optional<_CocoaString> |
| %5 = tuple() |
| return %5 : $() |
| } |
| |
| // FIXME: <rdar://problem/20980377> Add dead array elimination to DeadObjectElimination |
| // CHECK-LABEL: test_dead_array |
| // CHECK: bb0(%0 : $ZZZ): |
| // DISABLED-CHECK-NEXT: strong_release %0 |
| // DISABLED-CHECK-NEXT: tuple |
| // DISABLED-CHECK-NEXT: return |
| sil @test_dead_array : $@convention(thin) (@owned ZZZ) -> () { |
| bb0(%0 : $ZZZ): |
| %1 = integer_literal $Builtin.Word, 1 |
| %2 = function_ref @_allocate_uninitialized_ZZZ : $@convention(thin) (Builtin.Word) -> @owned (Array<ZZZ>, Builtin.RawPointer) |
| %3 = apply %2(%1) : $@convention(thin) (Builtin.Word) -> @owned (Array<ZZZ>, Builtin.RawPointer) |
| %4 = tuple_extract %3 : $(Array<ZZZ>, Builtin.RawPointer), 0 |
| %5 = tuple_extract %3 : $(Array<ZZZ>, Builtin.RawPointer), 1 |
| %6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*ZZZ |
| store %0 to %6 : $*ZZZ |
| %8 = struct_extract %4 : $Array<ZZZ>, #Array._buffer |
| %9 = struct_extract %8 : $_ArrayBuffer<ZZZ>, #_ArrayBuffer._storage |
| %10 = struct_extract %9 : $_BridgeStorage<_ContiguousArrayStorageBase, _NSArrayCore>, #_BridgeStorage.rawValue |
| strong_release %10 : $Builtin.BridgeObject |
| %12 = tuple () |
| return %12 : $() |
| } |
| |
| sil [_semantics "array.uninitialized"] @_allocate_uninitialized_ZZZ : $@convention(thin) (Builtin.Word) -> @owned (Array<ZZZ>, Builtin.RawPointer) |
| |
| // dead_array test helpers |
| sil [thunk] @dead_array_run_closure : $@convention(thin) (@owned @callee_owned () -> Bool) -> () { |
| bb0(%0 : $@callee_owned () -> Bool): |
| %1 = apply %0() : $@callee_owned () -> Bool |
| %2 = tuple () |
| return %2 : $() |
| } |
| |
| sil @dead_array_closure : $@convention(thin) (@inout _HeapBuffer<C, Int>) -> Bool { |
| bb0(%0 : $*_HeapBuffer<C, Int>): |
| %1 = struct_element_addr %0 : $*_HeapBuffer<C, Int>, #_HeapBuffer._storage // user: %2 |
| %2 = is_unique %1 : $*Optional<Builtin.NativeObject> // user: %3 |
| %3 = struct $Bool (%2 : $Builtin.Int1) // user: %4 |
| return %3 : $Bool // id: %4 |
| } |
| |
| // Mimicks Swift._allocateUninitializedArray |
| sil [_semantics "array.uninitialized"] @dead_array_alloc : $@convention(thin) <τ_0_0> (Builtin.Word) -> @owned (Array<τ_0_0>, Builtin.RawPointer) |
| |
| // <rdar://problem/20980377> HeapBuffer.swift test case spuriously reports a "unique" buffer |
| // CHECK-LABEL: sil @dead_array |
| // CHECK-NOT: release |
| // CHECK: retain_value %{{[0-9]+}} : $Optional<Builtin.NativeObject> |
| // CHECK: apply |
| // CHECK: strong_release %{{[0-9]+}} : $Builtin.BridgeObject |
| sil @dead_array : $@convention(thin) (@inout _HeapBuffer<C, Int>) -> () { |
| bb0(%0 : $*_HeapBuffer<C, Int>): |
| %1 = integer_literal $Builtin.Word, 1 // user: %3 |
| %2 = function_ref @dead_array_alloc : $@convention(thin) <τ_0_0> (Builtin.Word) -> @owned (Array<τ_0_0>, Builtin.RawPointer) |
| %3 = apply %2<_HeapBuffer<C, Int>>(%1) : $@convention(thin) <τ_0_0> (Builtin.Word) -> @owned (Array<τ_0_0>, Builtin.RawPointer) |
| %4 = tuple_extract %3 : $(Array<_HeapBuffer<C, Int>>, Builtin.RawPointer), 0 // user: %15 |
| %5 = tuple_extract %3 : $(Array<_HeapBuffer<C, Int>>, Builtin.RawPointer), 1 // user: %6 |
| %6 = pointer_to_address %5 : $Builtin.RawPointer to [strict] $*_HeapBuffer<C, Int> // user: %9 |
| %7 = load %0 : $*_HeapBuffer<C, Int> // users: %8, %9 |
| %8 = struct_extract %7 : $_HeapBuffer<C, Int>, #_HeapBuffer._storage // user: %13 |
| store %7 to %6 : $*_HeapBuffer<C, Int> // id: %9 |
| %10 = function_ref @dead_array_run_closure : $@convention(thin) (@owned @callee_owned () -> Bool) -> () // user: %14 |
| %11 = function_ref @dead_array_closure : $@convention(thin) (@inout _HeapBuffer<C, Int>) -> Bool // user: %12 |
| %12 = partial_apply %11(%0) : $@convention(thin) (@inout _HeapBuffer<C, Int>) -> Bool // user: %14 |
| retain_value %8 : $Optional<Builtin.NativeObject> // id: %13 |
| %14 = apply %10(%12) : $@convention(thin) (@owned @callee_owned () -> Bool) -> () |
| %15 = struct_extract %4 : $Array<_HeapBuffer<C, Int>>, #Array._buffer // user: %16 |
| %16 = struct_extract %15 : $_ArrayBuffer<_HeapBuffer<C, Int>>, #_ArrayBuffer._storage // user: %17 |
| %17 = struct_extract %16 : $_BridgeStorage<_ContiguousArrayStorageBase, _NSArrayCore>, #_BridgeStorage.rawValue // user: %18 |
| strong_release %17 : $Builtin.BridgeObject // id: %18 |
| %19 = tuple () // user: %20 |
| return %19 : $() // id: %20 |
| } |
| |
| // Check that it does not crash the compiler. |
| // Int is ObjC-bridgeable in this case, but its conformance is not know, |
| // because Foundation is not imported yet. |
| // Therefore the cast may succeed from the compiler point of view. |
| // CHECK-LABEL: sil @cast_of_class_to_int |
| // CHECK: unconditional_checked_cast_addr |
| // CHECK: return |
| sil @cast_of_class_to_int : $@convention(thin) (C) -> Int { |
| bb0(%0 : $C): |
| %1 = alloc_stack $Int |
| %2 = alloc_stack $C |
| store %0 to %2 : $*C |
| unconditional_checked_cast_addr C in %2 : $*C to Int in %1 : $*Int |
| %4 = load %1 : $*Int |
| dealloc_stack %2 : $*C |
| dealloc_stack %1 : $*Int |
| return %4 : $Int |
| } |
| |
| @objc(XX) protocol XX { |
| } |
| |
| class XXImpl : XX { |
| @objc deinit |
| init() |
| } |
| |
| // CHECK-LABEL: sil @remove_release_objc_metatype_to_object |
| // CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject |
| sil @remove_release_objc_metatype_to_object : $@convention(thin) () -> () { |
| bb0: |
| %0 = metatype $@thick XXImpl.Type // user: %1 |
| %1 = thick_to_objc_metatype %0 : $@thick XXImpl.Type to $@objc_metatype XXImpl.Type // user: %2 |
| %2 = objc_metatype_to_object %1 : $@objc_metatype XXImpl.Type to $AnyObject // users: %3, %4 |
| debug_value %2 : $AnyObject // id: %3 |
| strong_release %2 : $AnyObject // id: %4 |
| %5 = tuple () // user: %6 |
| return %5 : $() // id: %6 |
| } |
| |
| // CHECK-LABEL: sil @remove_release_objc_existential_metatype_to_object |
| // CHECK-NOT: strong_release {{%[0-9]+}} : $AnyObject |
| sil @remove_release_objc_existential_metatype_to_object: $@convention(thin) (@owned XX) -> () { |
| bb0(%0 : $XX): |
| debug_value %0 : $XX // id: %1 |
| %2 = existential_metatype $@thick XX.Type, %0 : $XX // user: %3 |
| %3 = thick_to_objc_metatype %2 : $@thick XX.Type to $@objc_metatype XX.Type // user: %4 |
| %4 = objc_existential_metatype_to_object %3 : $@objc_metatype XX.Type to $AnyObject // users: %5, %6 |
| debug_value %4 : $AnyObject, let, name "obj1" // id: %5 |
| strong_release %4 : $AnyObject // id: %6 |
| strong_release %0 : $XX // id: %7 |
| %8 = tuple () // user: %9 |
| return %8 : $() // id: %9 |
| } |
| |