blob: e5eaf9a56080f1e7d0ad1073208f14e9208aea51 [file] [log] [blame]
// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all %s -jumpthread-simplify-cfg -cse | %FileCheck %s
// Check that jump-threading works for sequences of checked_cast_br instructions produced by the devirtualizer.
// This allows for simplifications of code like e.g. f.foo() + f.foo()
sil_stage canonical
import Builtin
import Swift
import SwiftShims
/// Don't jumpthread blocks that contain objc method instructions. We don't
/// support building phis with objc method values.
class Bar {
init()
@objc func foo()
}
public class FooClass {
@_hasStorage var value: Int32 { get set }
@inline(never) func foo(x: Int32) -> Int32
init(value: Int32)
deinit
}
// devirt_jump_thread.FooClass.value.getter : Swift.Int32
sil [transparent] [serialized] @_TFC18devirt_jump_thread8FooClassg5valueSi : $@convention(method) (@guaranteed FooClass) -> Int32 {
bb0(%0 : $FooClass):
%1 = ref_element_addr %0 : $FooClass, #FooClass.value // user: %2
%2 = load %1 : $*Int32 // user: %4
return %2 : $Int32 // id: %4
}
// devirt_jump_thread.FooClass.value.setter : Swift.Int32
sil [transparent] [serialized] @_TFC18devirt_jump_thread8FooClasss5valueSi : $@convention(method) (Int32, @guaranteed FooClass) -> () {
bb0(%0 : $Int32, %1 : $FooClass):
%2 = ref_element_addr %1 : $FooClass, #FooClass.value // user: %3
store %0 to %2 : $*Int32 // id: %3
%5 = tuple () // user: %6
return %5 : $() // id: %6
}
// devirt_jump_thread.FooClass.foo (devirt_jump_thread.FooClass)(Swift.Int32) -> Swift.Int32
sil [noinline] @_TFC18devirt_jump_thread8FooClass3foofS0_FSiSi : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 {
bb0(%0 : $Int32, %1 : $FooClass):
// function_ref @!objc with unmangled suffix "no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi"
%2 = function_ref @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %3
%3 = apply %2(%0, %1) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %6
return %3 : $Int32 // id: %6
}
// Check that checked_cast_br instructions resulting from devirtualization
// get jump-threaded.
//
// CHECK-LABEL: sil @_TF18devirt_jump_thread26jumpthread_checked_cast_brFCS_8FooClassSi
// CHECK: checked_cast_br
// CHECK: bb2(%{{.*}} : $FooClass):
// CHECK: function_ref @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi
// CHECK-NOT: function_ref @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi
// CHECK-NOT: class_method
// CHECK: br bb1
// CHECK-NOT: checked_cast_br
// CHECK: bb3:
// CHECK-NOT: function_ref
// CHECK: class_method
// CHECK-NOT: function_ref
// CHECK: br bb1
// CHECK: }
// devirt_jump_thread.jumpthread_checked_cast_br (devirt_jump_thread.FooClass) -> Swift.Int32
sil @_TF18devirt_jump_thread26jumpthread_checked_cast_brFCS_8FooClassSi : $@convention(thin) (@guaranteed FooClass) -> Int32 {
bb0(%0 : $FooClass):
%1 = integer_literal $Builtin.Int32, 2 // user: %2
%2 = struct $Int32 (%1 : $Builtin.Int32) // users: %37, %43, %48, %54
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb5, bb6 // id: %3
bb1(%4 : $Int32): // Preds: bb5 bb6
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb7, bb8 // id: %5
bb2(%6 : $Int32): // Preds: bb7 bb8
%7 = struct_extract %4 : $Int32, #Int32._value // user: %10
%8 = struct_extract %6 : $Int32, #Int32._value // user: %10
%9 = integer_literal $Builtin.Int1, -1 // users: %10, %19, %28
%10 = builtin "sadd_with_overflow_Int32"(%7 : $Builtin.Int32, %8 : $Builtin.Int32, %9 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %11, %12
%11 = tuple_extract %10 : $(Builtin.Int32, Builtin.Int1), 0 // user: %19
%12 = tuple_extract %10 : $(Builtin.Int32, Builtin.Int1), 1 // user: %13
cond_fail %12 : $Builtin.Int1 // id: %13
%14 = integer_literal $Builtin.Int32, 3 // user: %15
%15 = struct $Int32 (%14 : $Builtin.Int32) // users: %59, %65
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb9, bb10 // id: %16
bb3(%17 : $Int32): // Preds: bb9 bb10
%18 = struct_extract %17 : $Int32, #Int32._value // user: %19
%19 = builtin "sadd_with_overflow_Int32"(%11 : $Builtin.Int32, %18 : $Builtin.Int32, %9 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %20, %21
%20 = tuple_extract %19 : $(Builtin.Int32, Builtin.Int1), 0 // user: %28
%21 = tuple_extract %19 : $(Builtin.Int32, Builtin.Int1), 1 // user: %22
cond_fail %21 : $Builtin.Int1 // id: %22
%23 = integer_literal $Builtin.Int32, 4 // user: %24
%24 = struct $Int32 (%23 : $Builtin.Int32) // users: %69, %74
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb11, bb12 // id: %25
bb4(%26 : $Int32): // Preds: bb11 bb12
%27 = struct_extract %26 : $Int32, #Int32._value // user: %28
%28 = builtin "sadd_with_overflow_Int32"(%20 : $Builtin.Int32, %27 : $Builtin.Int32, %9 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %29, %30
%29 = tuple_extract %28 : $(Builtin.Int32, Builtin.Int1), 0 // user: %32
%30 = tuple_extract %28 : $(Builtin.Int32, Builtin.Int1), 1 // user: %31
cond_fail %30 : $Builtin.Int1 // id: %31
%32 = struct $Int32 (%29 : $Builtin.Int32) // user: %33
return %32 : $Int32 // id: %33
bb5(%34 : $FooClass): // Preds: bb0
// function_ref @!objc with unmangled suffix "no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi"
%35 = function_ref @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %37
strong_retain %0 : $FooClass // id: %36
%37 = apply %35(%2, %34) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %40
fix_lifetime %34 : $FooClass // id: %38
strong_release %0 : $FooClass // id: %39
br bb1(%37 : $Int32) // id: %40
bb6: // Preds: bb0
%41 = class_method %0 : $FooClass, #FooClass.foo!1 : (FooClass) -> (Int32) -> Int32, $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %43
strong_retain %0 : $FooClass // id: %42
%43 = apply %41(%2, %0) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %44
br bb1(%43 : $Int32) // id: %44
bb7(%45 : $FooClass): // Preds: bb1
// function_ref @!objc with unmangled suffix "no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi"
%46 = function_ref @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %48
strong_retain %0 : $FooClass // id: %47
%48 = apply %46(%2, %45) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %51
fix_lifetime %45 : $FooClass // id: %49
strong_release %0 : $FooClass // id: %50
br bb2(%48 : $Int32) // id: %51
bb8: // Preds: bb1
%52 = class_method %0 : $FooClass, #FooClass.foo!1 : (FooClass) -> (Int32) -> Int32, $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %54
strong_retain %0 : $FooClass // id: %53
%54 = apply %52(%2, %0) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %55
br bb2(%54 : $Int32) // id: %55
bb9(%56 : $FooClass): // Preds: bb2
// function_ref @!objc with unmangled suffix "no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi"
%57 = function_ref @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %59
strong_retain %0 : $FooClass // id: %58
%59 = apply %57(%15, %56) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %62
fix_lifetime %56 : $FooClass // id: %60
strong_release %0 : $FooClass // id: %61
br bb3(%59 : $Int32) // id: %62
bb10: // Preds: bb2
%63 = class_method %0 : $FooClass, #FooClass.foo!1 : (FooClass) -> (Int32) -> Int32, $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %65
strong_retain %0 : $FooClass // id: %64
%65 = apply %63(%15, %0) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %66
br bb3(%65 : $Int32) // id: %66
bb11(%67 : $FooClass): // Preds: bb3
// function_ref @!objc with unmangled suffix "no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi"
%68 = function_ref @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %69
%69 = apply %68(%24, %67) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %72
fix_lifetime %67 : $FooClass // id: %70
strong_release %67 : $FooClass // id: %71
br bb4(%69 : $Int32) // id: %72
bb12: // Preds: bb3
%73 = class_method %0 : $FooClass, #FooClass.foo!1 : (FooClass) -> (Int32) -> Int32, $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %74
%74 = apply %73(%24, %0) : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 // user: %75
br bb4(%74 : $Int32) // id: %75
}
// Check that checked_cast_br gets jump threaded
// CHECK-LABEL: sil @_TF18devirt_jump_thread6doubleFCS_8FooClassSi
// CHECK: checked_cast_br
// CHECK: bb2(%{{.*}} : $FooClass):
// CHECK-NOT: class_method
// CHECK: br bb1
// CHECK-NOT: checked_cast_br
// CHECK: bb3
// CHECK: class_method
// CHECK: br bb1
// CHECK }
// devirt_jump_thread.double (devirt_jump_thread.FooClass) -> Swift.Int32
sil @_TF18devirt_jump_thread6doubleFCS_8FooClassSi : $@convention(thin) (@guaranteed FooClass) -> Int32 {
bb0(%0 : $FooClass):
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb3, bb4 // id: %1
bb1(%2 : $Int32): // Preds: bb3 bb4
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb5, bb6 // id: %3
bb2(%4 : $Int32): // Preds: bb5 bb6
%5 = struct_extract %2 : $Int32, #Int32._value // user: %8
%6 = struct_extract %4 : $Int32, #Int32._value // user: %8
%7 = integer_literal $Builtin.Int1, -1 // user: %8
%8 = builtin "sadd_with_overflow_Int32"(%5 : $Builtin.Int32, %6 : $Builtin.Int32, %7 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %9, %10
%9 = tuple_extract %8 : $(Builtin.Int32, Builtin.Int1), 0 // user: %12
%10 = tuple_extract %8 : $(Builtin.Int32, Builtin.Int1), 1 // user: %11
cond_fail %10 : $Builtin.Int1 // id: %11
%12 = struct $Int32 (%9 : $Builtin.Int32) // user: %13
return %12 : $Int32 // id: %13
bb3(%14 : $FooClass): // Preds: bb0
%15 = ref_element_addr %14 : $FooClass, #FooClass.value // user: %16
%16 = load %15 : $*Int32 // user: %17
br bb1(%16 : $Int32) // id: %17
bb4: // Preds: bb0
%18 = class_method %0 : $FooClass, #FooClass.value!getter.1 : (FooClass) -> () -> Int32, $@convention(method) (@guaranteed FooClass) -> Int32 // user: %20
strong_retain %0 : $FooClass // id: %19
%20 = apply %18(%0) : $@convention(method) (@guaranteed FooClass) -> Int32 // user: %21
br bb1(%20 : $Int32) // id: %21
bb5(%22 : $FooClass): // Preds: bb1
%23 = ref_element_addr %22 : $FooClass, #FooClass.value // user: %24
%24 = load %23 : $*Int32 // user: %26
strong_release %22 : $FooClass // id: %25
br bb2(%24 : $Int32) // id: %26
bb6: // Preds: bb1
%27 = class_method %0 : $FooClass, #FooClass.value!getter.1 : (FooClass) -> () -> Int32, $@convention(method) (@guaranteed FooClass) -> Int32 // user: %28
%28 = apply %27(%0) : $@convention(method) (@guaranteed FooClass) -> Int32 // user: %29
br bb2(%28 : $Int32) // id: %29
}
// Check that checked_cast_br in bb1 does not get jump threaded
// because bb1 contains some instructions that cannot be cloned, namely alloc_stack.
//
// CHECK-LABEL: sil @_TF18devirt_jump_thread6dont_jump_thread_alloc_stackFCS_8FooClassSi
// CHECK: bb0(%{{.*}} : $FooClass):
// CHECK: checked_cast_br
// CHECK: bb1(%{{.*}} : $Int32):
// CHECK: checked_cast_br
// CHECK: bb2(%{{.*}} : $Int32):
// CHECK }
sil @_TF18devirt_jump_thread6dont_jump_thread_alloc_stackFCS_8FooClassSi : $@convention(thin) (@guaranteed FooClass) -> Int32 {
bb0(%0 : $FooClass):
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb3, bb4 // id: %1
bb1(%2 : $Int32): // Preds: bb3 bb4
%60 = alloc_stack $Int32
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb5, bb6 // id: %3
bb2(%4 : $Int32): // Preds: bb5 bb6
%5 = struct_extract %2 : $Int32, #Int32._value // user: %8
%6 = struct_extract %4 : $Int32, #Int32._value // user: %8
%7 = integer_literal $Builtin.Int1, -1 // user: %8
%8 = builtin "sadd_with_overflow_Int32"(%5 : $Builtin.Int32, %6 : $Builtin.Int32, %7 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %9, %10
%9 = tuple_extract %8 : $(Builtin.Int32, Builtin.Int1), 0 // user: %12
%10 = tuple_extract %8 : $(Builtin.Int32, Builtin.Int1), 1 // user: %11
cond_fail %10 : $Builtin.Int1 // id: %11
dealloc_stack %60 : $*Int32
%12 = struct $Int32 (%9 : $Builtin.Int32) // user: %13
return %12 : $Int32 // id: %13
bb3(%14 : $FooClass): // Preds: bb0
%15 = ref_element_addr %14 : $FooClass, #FooClass.value // user: %16
%16 = load %15 : $*Int32 // user: %17
br bb1(%16 : $Int32) // id: %17
bb4: // Preds: bb0
%18 = class_method %0 : $FooClass, #FooClass.value!getter.1 : (FooClass) -> () -> Int32, $@convention(method) (@guaranteed FooClass) -> Int32 // user: %20
%20 = apply %18(%0) : $@convention(method) (@guaranteed FooClass) -> Int32 // user: %21
br bb1(%20 : $Int32) // id: %21
bb5(%22 : $FooClass): // Preds: bb1
%23 = ref_element_addr %22 : $FooClass, #FooClass.value // user: %24
%24 = load %23 : $*Int32 // user: %26
br bb2(%24 : $Int32) // id: %26
bb6: // Preds: bb1
%27 = class_method %0 : $FooClass, #FooClass.value!getter.1 : (FooClass) -> () -> Int32, $@convention(method) (@guaranteed FooClass) -> Int32 // user: %28
%28 = apply %27(%0) : $@convention(method) (@guaranteed FooClass) -> Int32 // user: %29
br bb2(%28 : $Int32) // id: %29
}
// Check that checked_cast_br in bb1 does not get jump threaded
// because bb1 contains some instructions that cannot be cloned, e.g. class_method
// referring to an objc method.
//
// CHECK-LABEL: sil @_TF18devirt_jump_thread6dont_jump_thread_objc_methodFCS_8FooClassSi
// CHECK: bb0(%{{.*}} : $FooClass):
// CHECK: checked_cast_br
// CHECK: bb1(%{{.*}} : $Int32):
// CHECK: checked_cast_br
// CHECK: bb2(%{{.*}} : $Int32):
// CHECK }
sil @_TF18devirt_jump_thread6dont_jump_thread_objc_methodFCS_8FooClassSi : $@convention(thin) (@guaranteed FooClass) -> Int32 {
bb0(%0 : $FooClass):
%100 = alloc_ref $Bar
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb3, bb4 // id: %1
bb1(%2 : $Int32): // Preds: bb3 bb4
%101 = objc_method %100 : $Bar, #Bar.foo!1.foreign : (Bar) -> () -> (), $@convention(objc_method) (Bar) -> ()
checked_cast_br [exact] %0 : $FooClass to $FooClass, bb5, bb6 // id: %3
bb2(%4 : $Int32): // Preds: bb5 bb6
%5 = struct_extract %2 : $Int32, #Int32._value // user: %8
%6 = struct_extract %4 : $Int32, #Int32._value // user: %8
%7 = integer_literal $Builtin.Int1, -1 // user: %8
%8 = builtin "sadd_with_overflow_Int32"(%5 : $Builtin.Int32, %6 : $Builtin.Int32, %7 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %9, %10
%9 = tuple_extract %8 : $(Builtin.Int32, Builtin.Int1), 0 // user: %12
%10 = tuple_extract %8 : $(Builtin.Int32, Builtin.Int1), 1 // user: %11
cond_fail %10 : $Builtin.Int1 // id: %11
%12 = struct $Int32 (%9 : $Builtin.Int32) // user: %13
return %12 : $Int32 // id: %13
bb3(%14 : $FooClass): // Preds: bb0
%15 = ref_element_addr %14 : $FooClass, #FooClass.value // user: %16
%16 = load %15 : $*Int32 // user: %17
br bb1(%16 : $Int32) // id: %17
bb4: // Preds: bb0
%18 = class_method %0 : $FooClass, #FooClass.value!getter.1 : (FooClass) -> () -> Int32, $@convention(method) (@guaranteed FooClass) -> Int32 // user: %20
strong_retain %0 : $FooClass // id: %19
%20 = apply %18(%0) : $@convention(method) (@guaranteed FooClass) -> Int32 // user: %21
br bb1(%20 : $Int32) // id: %21
bb5(%22 : $FooClass): // Preds: bb1
%23 = ref_element_addr %22 : $FooClass, #FooClass.value // user: %24
%24 = load %23 : $*Int32 // user: %26
strong_release %22 : $FooClass // id: %25
br bb2(%24 : $Int32) // id: %26
bb6: // Preds: bb1
%27 = class_method %0 : $FooClass, #FooClass.value!getter.1 : (FooClass) -> () -> Int32, $@convention(method) (@guaranteed FooClass) -> Int32 // user: %28
%28 = apply %27(%0) : $@convention(method) (@guaranteed FooClass) -> Int32 // user: %29
br bb2(%28 : $Int32) // id: %29
}
// @!objc with unmangled suffix "no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi"
sil [noinline] @_TTOS_no2g__TFC18devirt_jump_thread8FooClass3foofS0_FSiSi : $@convention(method) (Int32, @guaranteed FooClass) -> Int32 {
bb0(%0 : $Int32, %1 : $FooClass):
%2 = integer_literal $Builtin.Int32, 11 // user: %5
%3 = struct_extract %0 : $Int32, #Int32._value // user: %5
%4 = integer_literal $Builtin.Int1, -1 // user: %5
%5 = builtin "sadd_with_overflow_Int32"(%3 : $Builtin.Int32, %2 : $Builtin.Int32, %4 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1) // users: %6, %7
%6 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 0 // user: %9
%7 = tuple_extract %5 : $(Builtin.Int32, Builtin.Int1), 1 // user: %8
cond_fail %7 : $Builtin.Int1 // id: %8
%9 = struct $Int32 (%6 : $Builtin.Int32) // user: %10
return %9 : $Int32 // id: %10
}
sil_vtable FooClass {
#FooClass.foo!1: @_TFC18devirt_jump_thread8FooClass3foofS0_FSiSi // devirt_jump_thread.FooClass.foo (devirt_jump_thread.FooClass)(Swift.Int32) -> Swift.Int32
#FooClass.value!getter.1: @_TFC18devirt_jump_thread8FooClassg5valueSi // devirt_jump_thread.FooClass.value.getter : Swift.Int32
#FooClass.value!setter.1: @_TFC18devirt_jump_thread8FooClasss5valueSi // devirt_jump_thread.FooClass.value.setter : Swift.Int32
}
class C {
deinit
init()
}
// Check that checked_cast_br jump-threading works properly when both
// conditions are arguments of the function's entry block.
// CHECK: sil @test_checked_cast_br_jump_threading_with_entry_bb_arguments
// CHECK: checked_cast_br %0
// CHECK: checked_cast_br %1
// CHECK: return
sil @test_checked_cast_br_jump_threading_with_entry_bb_arguments : $@convention(thin) (@owned AnyObject, @owned AnyObject) -> Int32 {
bb0(%0 : $AnyObject, %1 : $AnyObject):
strong_retain %0 : $AnyObject
checked_cast_br %0 : $AnyObject to $C, bb1, bb2
bb1(%4 : $C):
%5 = enum $Optional<C>, #Optional.some!enumelt.1, %4 : $C
br bb3(%5 : $Optional<C>)
bb2:
strong_release %0 : $AnyObject
%8 = enum $Optional<C>, #Optional.none!enumelt
br bb3(%8 : $Optional<C>)
bb3(%10 : $Optional<C>):
switch_enum %10 : $Optional<C>, case #Optional.some!enumelt.1: bb5, default bb4
bb4:
br bb13
bb5(%13 : $C):
strong_retain %1 : $AnyObject
checked_cast_br %1 : $AnyObject to $C, bb6, bb7
bb6(%16 : $C):
%17 = enum $Optional<C>, #Optional.some!enumelt.1, %16 : $C
br bb8(%17 : $Optional<C>)
bb7:
strong_release %1 : $AnyObject
%20 = enum $Optional<C>, #Optional.none!enumelt
br bb8(%20 : $Optional<C>)
bb8(%22 : $Optional<C>):
switch_enum %22 : $Optional<C>, case #Optional.some!enumelt.1: bb10, default bb9
bb9:
strong_release %13 : $C
br bb13
bb10(%26 : $C):
%27 = function_ref @_TZFsoi3eeeFTGSqPs9AnyObject__GSqPS____Sb : $@convention(thin) (@owned Optional<AnyObject>, @owned Optional<AnyObject>) -> Bool
strong_retain %13 : $C
%29 = init_existential_ref %13 : $C : $C, $AnyObject
%30 = enum $Optional<AnyObject>, #Optional.some!enumelt.1, %29 : $AnyObject
strong_retain %26 : $C
%32 = init_existential_ref %26 : $C : $C, $AnyObject
%33 = enum $Optional<AnyObject>, #Optional.some!enumelt.1, %32 : $AnyObject
%34 = apply %27(%30, %33) : $@convention(thin) (@owned Optional<AnyObject>, @owned Optional<AnyObject>) -> Bool
%35 = struct_extract %34 : $Bool, #Bool._value
cond_br %35, bb11, bb12
bb11:
%37 = integer_literal $Builtin.Int32, 1
%38 = struct $Int32 (%37 : $Builtin.Int32)
strong_release %26 : $C
strong_release %13 : $C
br bb14(%38 : $Int32)
bb12:
strong_release %26 : $C
strong_release %13 : $C
br bb13
bb13:
%45 = integer_literal $Builtin.Int32, 0
%46 = struct $Int32 (%45 : $Builtin.Int32)
br bb14(%46 : $Int32)
bb14(%48 : $Int32):
strong_release %1 : $AnyObject
strong_release %0 : $AnyObject
return %48 : $Int32
}
sil [serialized] @_TZFsoi3eeeFTGSqPs9AnyObject__GSqPS____Sb : $@convention(thin) (@owned Optional<AnyObject>, @owned Optional<AnyObject>) -> Bool