Files
swift-mirror/test/SILOptimizer/polymorphic_inline_caches.sil
Roman Levenstein 8ad61d5cd6 Use function signatures for SILDeclRefs in witness_tables, vtables and witness_method instructions.
Textual SIL was sometimes ambiguous when SILDeclRefs were used, because the textual representation of SILDeclRefs was the same for functions that have the same name, but different signatures.
2017-01-27 12:16:14 -08:00

232 lines
7.8 KiB
Plaintext

// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -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_
}