| // RUN: %target-sil-opt -enable-objc-interop -assume-parsing-unqualified-ownership-sil -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 [transparent] [serialized] @_TFSb21_getBuiltinLogicValuefSbFT_Bi1_ : $@convention(method) (Bool) -> Builtin.Int1 |
| |
| |
| sil [serialized] @_TZFsoi3eeeFTGSqPs9AnyObject__GSqPS____Sb : $@convention(thin) (@owned Optional<AnyObject>, @owned Optional<AnyObject>) -> Bool |
| |
| |
| |