Raw File
sil_combine_objc.sil
// RUN: %target-sil-opt -enable-sil-verify-all %s -sil-combine -verify-skip-unreachable-must-be-last | FileCheck %s
// REQUIRES: objc_interop

sil_stage canonical

import Builtin
import Swift

class ZZZ {
  @objc deinit 
  init()
}

class C {}

sil @stringcore_invariant_check : $@convention(thin) (@owned _StringCore) -> @owned Optional<_CocoaStringType>
sil @reabstraction_thunk : $@convention(thin) (@out Optional<_CocoaStringType>, @owned @callee_owned () -> @owned Optional<_CocoaStringType>) -> ()

// CHECK-LABEL: sil @dead_closure_elimination : $@convention(thin) (@owned _StringCore) -> ()
// CHECK: bb0
// CHECK-NEXT: release_value
// CHECK-NEXT: tuple
// CHECK-NEXT: return
sil @dead_closure_elimination : $@convention(thin) (@owned _StringCore) -> () {
bb0(%0 : $_StringCore):
  %1 = function_ref @stringcore_invariant_check : $@convention(thin) (@owned _StringCore) -> @owned Optional<_CocoaStringType>
  %2 = partial_apply %1(%0) : $@convention(thin) (@owned _StringCore) -> @owned Optional<_CocoaStringType>
  %3 = function_ref @reabstraction_thunk : $@convention(thin) (@out Optional<_CocoaStringType>, @owned @callee_owned () -> @owned Optional<_CocoaStringType>) -> ()
  %4 = partial_apply %3(%2) : $@convention(thin) (@out Optional<_CocoaStringType>, @owned @callee_owned () -> @owned Optional<_CocoaStringType>) -> ()
  strong_release %4 : $@callee_owned (@out Optional<_CocoaStringType>) -> ()
  %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 _StringCore) -> () {
bb0(%0 : $_StringCore):
  %1 = function_ref @stringcore_invariant_check : $@convention(thin) (@owned _StringCore) -> @owned Optional<_CocoaStringType>
  %2 = partial_apply %1(%0) : $@convention(thin) (@owned _StringCore) -> @owned Optional<_CocoaStringType>
  %3 = function_ref @reabstraction_thunk : $@convention(thin) (@out Optional<_CocoaStringType>, @owned @callee_owned () -> @owned Optional<_CocoaStringType>) -> ()
  %4 = partial_apply %3(%2) : $@convention(thin) (@out Optional<_CocoaStringType>, @owned @callee_owned () -> @owned Optional<_CocoaStringType>) -> ()
  br bb1

bb1:
  strong_retain %4 : $@callee_owned (@out Optional<_CocoaStringType>) -> ()
  strong_release %4 : $@callee_owned (@out Optional<_CocoaStringType>) -> ()
  strong_release %4 : $@callee_owned (@out Optional<_CocoaStringType>) -> ()
  %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 $*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, _NSArrayCoreType>, #_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 $*_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, _NSArrayCoreType>, #_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 take_always C in %2 : $*C to Int in %1 : $*Int 
  %4 = load %1 : $*Int
  dealloc_stack %2 : $*C
  dealloc_stack %1 : $*Int
  return %4 : $Int
}

back to top