Files
swift-mirror/test/SILOptimizer/devirt_jump_thread.sil
Nate Chandler e5d87f75a8 [SIL] Add source formal type to checked_cast_br.
It is necessary for opaque values where for casts that will newly start
out as checked_cast_brs and be lowered to checked_cast_addr_brs, since
the latter has the source formal type, IRGen relies on being able to
access it, and there's no way in general to obtain the source formal
type from the source lowered type.
2023-07-27 15:04:15 -07:00

444 lines
23 KiB
Plaintext

// 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: bb1(%{{.*}} : $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 bb2
// CHECK-NOT: checked_cast_br
// CHECK: bb3:
// CHECK-NOT: function_ref
// CHECK: class_method
// CHECK-NOT: function_ref
// CHECK: br bb2
// 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] FooClass in %0 : $FooClass to FooClass, bb5, bb6 // id: %3
bb1(%4 : $Int32): // Preds: bb5 bb6
checked_cast_br [exact] FooClass in %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] FooClass in %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] FooClass in %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 : (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 : (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 : (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 : (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
// CHECK: class_method
// CHECK: br bb4
// CHECK: bb3(%{{.*}} : $FooClass):
// CHECK-NOT: class_method
// CHECK: br bb1
// CHECK-NOT: checked_cast_br
// 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] FooClass in %0 : $FooClass to FooClass, bb3, bb4 // id: %1
bb1(%2 : $Int32): // Preds: bb3 bb4
checked_cast_br [exact] FooClass in %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 : (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 : (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] FooClass in %0 : $FooClass to FooClass, bb3, bb4 // id: %1
bb1(%2 : $Int32): // Preds: bb3 bb4
%60 = alloc_stack $Int32
checked_cast_br [exact] FooClass in %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 : (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 : (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] FooClass in %0 : $FooClass to FooClass, bb3, bb4 // id: %1
bb1(%2 : $Int32): // Preds: bb3 bb4
%101 = objc_method %100 : $Bar, #Bar.foo!foreign : (Bar) -> () -> (), $@convention(objc_method) (Bar) -> ()
checked_cast_br [exact] FooClass in %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 : (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 : (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: @_TFC18devirt_jump_thread8FooClass3foofS0_FSiSi // devirt_jump_thread.FooClass.foo (devirt_jump_thread.FooClass)(Swift.Int32) -> Swift.Int32
#FooClass.value!getter: @_TFC18devirt_jump_thread8FooClassg5valueSi // devirt_jump_thread.FooClass.value.getter : Swift.Int32
#FooClass.value!setter: @_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 AnyObject in %0
// CHECK: checked_cast_br AnyObject in %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 AnyObject in %0 : $AnyObject to C, bb1, bb2
bb1(%4 : $C):
%5 = enum $Optional<C>, #Optional.some!enumelt, %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: bb5, default bb4
bb4:
br bb13
bb5(%13 : $C):
strong_retain %1 : $AnyObject
checked_cast_br AnyObject in %1 : $AnyObject to C, bb6, bb7
bb6(%16 : $C):
%17 = enum $Optional<C>, #Optional.some!enumelt, %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: 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, %29 : $AnyObject
strong_retain %26 : $C
%32 = init_existential_ref %26 : $C : $C, $AnyObject
%33 = enum $Optional<AnyObject>, #Optional.some!enumelt, %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