Raw File
// RUN: %target-sil-opt -enable-sil-verify-all %s -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 {
  @sil_stored 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] [fragile] @_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] [fragile] @_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 = class_method [volatile] %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 [transparent] [fragile] @_TFSb21_getBuiltinLogicValuefSbFT_Bi1_ : $@convention(method) (Bool) -> Builtin.Int1


sil [fragile] @_TZFsoi3eeeFTGSqPs9AnyObject__GSqPS____Sb : $@convention(thin) (@owned Optional<AnyObject>, @owned Optional<AnyObject>) -> Bool

sil_witness_table C: AnyObject module main


back to top