Files
swift-mirror/test/SILOptimizer/devirt_jump_thread.sil
Erik Eckstein 1de19a1b32 SimplifyCFG: fix a compile time problem with block merging
When merging many blocks to a single block (in the wrong order), instructions are getting moved over and over again.
This is quadratic and can result in very long compile times for large functions.
To fix this, always move the instruction to smaller block to the larger block.

rdar://problem/56268570
2020-04-10 20:10:24 +02:00

444 lines
22 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] %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 : (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] %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 : (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] %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 : (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] %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] %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 %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, %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 %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