mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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.
444 lines
23 KiB
Plaintext
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
|
|
|
|
|
|
|