blob: 16efb83d12be913a2a8fb79f400b29ae9b3eabad [file] [log] [blame]
// RUN: %target-sil-opt -enable-sil-verify-all %s -specdevirt -code-sinking -dce -early-codemotion -disable-sil-cm-rr-cm=0 -retain-sinking | %FileCheck %s
sil_stage canonical
import Builtin
import Swift
class A {
func ping(x: Builtin.Int32) -> Builtin.Int32
}
class B : A {
override func ping(x: Builtin.Int32) -> Builtin.Int32
}
class C : A {
override func ping(x: Builtin.Int32) -> Builtin.Int32
}
class D : C {
override func ping(x: Builtin.Int32) -> Builtin.Int32
}
sil @external_func : $@convention(thin) (A) -> Builtin.Int32
sil @_TFC25polymorphic_inline_caches1A4pingfS0_FBi32_Bi32_ : $@convention(method) (Builtin.Int32, @guaranteed A) -> Builtin.Int32
sil @_TFC25polymorphic_inline_caches1B4pingfS0_FBi32_Bi32_ : $@convention(method) (Builtin.Int32, @guaranteed B) -> Builtin.Int32
sil @_TFC25polymorphic_inline_caches1C4pingfS0_FBi32_Bi32_ : $@convention(method) (Builtin.Int32, @guaranteed C) -> Builtin.Int32
sil @_TFC25polymorphic_inline_caches1D4pingfS0_FBi32_Bi32_ : $@convention(method) (Builtin.Int32, @guaranteed D) -> Builtin.Int32
// CHECK-LABEL: sil @_TF25polymorphic_inline_caches3fooFTCS_1ABi32__Bi32_
sil @_TF25polymorphic_inline_caches3fooFTCS_1ABi32__Bi32_ : $@convention(thin) (@owned A, Builtin.Int32) -> Builtin.Int32 {
// CHECK: bb0
bb0(%0 : $A, %1 : $Builtin.Int32):
// CHECK-NOT: strong_retain %0
strong_retain %0 : $A
// CHECK-NOT: class_method
%5 = class_method %0 : $A, #A.ping!1 : (A) -> (Builtin.Int32) -> Builtin.Int32, $@convention(method) (Builtin.Int32, @guaranteed A) -> Builtin.Int32
// CHECK-NOT: apply
%6 = apply %5(%1, %0) : $@convention(method) (Builtin.Int32, @guaranteed A) -> Builtin.Int32
// CHECK: checked_cast_br [exact] %0 : $A to $A, bb2, bb3
// CHECK: bb1
strong_release %0 : $A
// CHECK: return
return %6 : $Builtin.Int32
// CHECK: bb2
// CHECK: [[APING:%.*]] = function_ref @_TFC25polymorphic_inline_caches1A4pingfS0_FBi32_Bi32_
// CHECK: apply [[APING]]
// CHECK: bb3
// CHECK: checked_cast_br [exact] %0 : $A to $B, bb5, bb6
// CHECK: bb4
// CHECK: br bb1
// CHECK: bb5
// CHECK: [[BPING:%.*]] = function_ref @_TFC25polymorphic_inline_caches1B4pingfS0_FBi32_Bi32_
// CHECK: apply [[BPING]]
// CHECK: bb6
// CHECK: checked_cast_br [exact] %0 : $A to $C, bb8, bb9
// CHECK: bb7
// CHECK: br bb4
// CHECK: bb8
// CHECK: [[CPING:%.*]] = function_ref @_TFC25polymorphic_inline_caches1C4pingfS0_FBi32_Bi32_
// CHECK: apply [[CPING]]
// CHECK: bb9
// CHECK: [[PING:%.*]] = class_method %0 : $A, #A.ping!1
// CHECK: apply [[PING]]
}
// CHECK-LABEL: sil @polymorphic_inline_caches_dont_sink_retain
sil @polymorphic_inline_caches_dont_sink_retain : $@convention(thin) (@owned A, Builtin.Int32) -> Builtin.Int32 {
// CHECK: bb0
bb0(%0 : $A, %1 : $Builtin.Int32):
// CHECK: strong_retain %0
%4 = function_ref @external_func : $@convention(thin) (A) -> Builtin.Int32
%5 = class_method %0 : $A, #A.ping!1 : (A) -> (Builtin.Int32) -> Builtin.Int32, $@convention(method) (Builtin.Int32, @guaranteed A) -> Builtin.Int32
// Don't sink this retain, because its argument is used by %6 (apply of @external_func)
strong_retain %0 : $A
// CHECK-NOT: class_method
// CHECK: apply
// CHECK-NOT: apply
%6 = apply %4(%0) : $@convention(thin) (A) -> Builtin.Int32
%7 = apply %5(%1, %0) : $@convention(method) (Builtin.Int32, @guaranteed A) -> Builtin.Int32
// CHECK: checked_cast_br [exact] %0 : $A to $A, bb2, bb3
// CHECK: bb1
strong_release %0 : $A
// CHECK: return
return %6 : $Builtin.Int32
// CHECK: bb2
// CHECK: [[APING:%.*]] = function_ref @_TFC25polymorphic_inline_caches1A4pingfS0_FBi32_Bi32_
// CHECK: apply [[APING]]
// CHECK: bb3
// CHECK: checked_cast_br [exact] %0 : $A to $B, bb5, bb6
// CHECK: bb4
// CHECK: br bb1
// CHECK: bb5
// CHECK: [[BPING:%.*]] = function_ref @_TFC25polymorphic_inline_caches1B4pingfS0_FBi32_Bi32_
// CHECK: apply [[BPING]]
// CHECK: bb6
// CHECK: checked_cast_br [exact] %0 : $A to $C, bb8, bb9
// CHECK: bb7
// CHECK: br bb4
// CHECK: bb8
// CHECK: [[CPING:%.*]] = function_ref @_TFC25polymorphic_inline_caches1C4pingfS0_FBi32_Bi32_
// CHECK: apply [[CPING]]
// CHECK: bb9
// CHECK: [[PING:%.*]] = class_method %0 : $A, #A.ping!1
// CHECK: apply [[PING]]
}
sil_vtable A {
#A.ping!1: @_TFC25polymorphic_inline_caches1A4pingfS0_FBi32_Bi32_
}
sil_vtable B {
#A.ping!1: @_TFC25polymorphic_inline_caches1B4pingfS0_FBi32_Bi32_
}
sil_vtable C {
#A.ping!1: @_TFC25polymorphic_inline_caches1C4pingfS0_FBi32_Bi32_
}
sil_vtable D {
#A.ping!1: @_TFC25polymorphic_inline_caches1D4pingfS0_FBi32_Bi32_
}
protocol P {
func foo()
}
public class E : P {
@inline(never) func foo()
deinit
init()
}
public class F : E {
@inline(never) override func foo()
deinit
override init()
}
public final class G : E {
@inline(never) override final func foo()
deinit
override init()
}
sil [noinline] @_TFC5casts1E3foofS0_FT_T_ : $@convention(method) (@guaranteed E) -> ()
sil [noinline] @_TFC5casts1F3foofS0_FT_T_ : $@convention(method) (@guaranteed F) -> ()
sil [noinline] @_TFC5casts1G3foofS0_FT_T_ : $@convention(method) (@guaranteed G) -> ()
// CHECK-LABEL: sil [noinline] @_TF5casts18unchecked_ref_castFBoT_
sil [noinline] @_TF5casts18unchecked_ref_castFBoT_ : $@convention(thin) (@owned Builtin.NativeObject) -> () {
// CHECK: bb0
bb0(%0 : $Builtin.NativeObject):
strong_retain %0 : $Builtin.NativeObject
// CHECK: [[CAST:%.*]] = unchecked_ref_cast %0 : $Builtin.NativeObject to $E
%3 = unchecked_ref_cast %0 : $Builtin.NativeObject to $E
// CHECK-NOT: class_method
%4 = class_method %3 : $E, #E.foo!1 : (E) -> () -> (), $@convention(method) (@guaranteed E) -> ()
%5 = apply %4(%3) : $@convention(method) (@guaranteed E) -> ()
strong_release %0 : $Builtin.NativeObject
%7 = tuple ()
return %7 : $()
// CHECK: checked_cast_br [exact] [[CAST]] : $E to $E, bb2, bb3
// CHECK: bb1
// CHECK: strong_release %0
// CHECK: return
// CHECK: bb2
// CHECK: [[EFOO:%.*]] = function_ref @_TFC5casts1E3foofS0_FT_T_
// CHECK: strong_retain %0
// CHECK: apply [[EFOO]]
// CHECK: bb3
// CHECK: checked_cast_br [exact] [[CAST]] : $E to $F, bb5, bb6
// CHECK: bb4
// CHECK: br bb1
// CHECK: bb5
// CHECK: [[FFOO:%.*]] = function_ref @_TFC5casts1F3foofS0_FT_T_
// CHECK: strong_retain %0
// CHECK: apply [[FFOO]]
// CHECK: bb6
// CHECK: checked_cast_br [exact] [[CAST]] : $E to $G, bb8, bb9
// CHECK: bb7
// CHECK: bb8
// CHECK: [[GFOO:%.*]] = function_ref @_TFC5casts1G3foofS0_FT_T_
// CHECK: strong_retain %0
// CHECK: apply [[GFOO]]
// CHECK: bb9
// CHECK: [[DYNAMIC:%.*]] = class_method [[CAST]] : $E, #E.foo!1
// CHECK: strong_retain %0
// CHECK: apply [[DYNAMIC]]
}
// CHECK-LABEL: sil [noinline] @_TF5casts22unchecked_ref_castFCS_1ET_
sil [noinline] @_TF5casts22unchecked_ref_castFCS_1ET_ : $@convention(thin) (@owned E) -> () {
// CHECK: bb0
bb0(%0 : $E):
strong_retain %0 : $E
// CHECK: [[CAST:%.*]] = unchecked_ref_cast %0 : $E to $F
%3 = unchecked_ref_cast %0 : $E to $F
// CHECK-NOT: class_method
%4 = class_method %3 : $F, #F.foo!1 : (F) -> () -> (), $@convention(method) (@guaranteed F) -> ()
%5 = apply %4(%3) : $@convention(method) (@guaranteed F) -> ()
strong_release %0 : $E
%7 = tuple ()
return %7 : $()
// CHECK: checked_cast_br [exact] [[CAST]] : $F to $F, bb2, bb3
// CHECK: bb1
// CHECK: strong_release %0
// CHECK: return
// CHECK: bb2
// CHECK: [[FFOO:%.*]] = function_ref @_TFC5casts1F3foofS0_FT_T_
// CHECK: strong_retain %0
// CHECK: apply [[FFOO]]
// CHECK: bb3
// CHECK: [[DYNAMIC:%.*]] = class_method [[CAST]] : $F, #F.foo!1
// CHECK: strong_retain %0
// CHECK: apply [[DYNAMIC]]
}
sil_vtable E {
#E.foo!1: @_TFC5casts1E3foofS0_FT_T_
}
sil_vtable F {
#E.foo!1: @_TFC5casts1F3foofS0_FT_T_
}
sil_vtable G {
#E.foo!1: @_TFC5casts1G3foofS0_FT_T_
}