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