blob: 04e32468b532e2604c67dd0f6dcc7b6b251bc4a0 [file] [log] [blame]
// RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-NORMAL %s
// RUN: %target-swift-frontend -O -module-name devirt_default_case -emit-sil -enable-testing %s | %FileCheck -check-prefix=CHECK -check-prefix=CHECK-TESTABLE %s
@_silgen_name("action")
func action(_ n:Int) -> ()
// public class
open class Base1 {
@inline(never) func inner() { action(1)}
func middle() { inner() }
// Check that call to Base1.middle cannot be devirtualized
//
// CHECK-LABEL: sil @$s19devirt_default_case5Base1C5outer{{[_0-9a-zA-Z]*}}F
// CHECK: class_method
// CHECK: } // end sil function '$s19devirt_default_case5Base1C5outer{{[_0-9a-zA-Z]*}}F'
public func outer() {
middle()
}
}
// public class
open class Derived1 : Base1 {
override func inner() { action(2) }
@inline(never) final override func middle() { inner() }
}
// private class
private class Base2 {
@inline(never) func inner() { action(3)}
func middle() { inner() }
func outer() { middle() }
}
// private class
private class Derived2 : Base2 {
override func inner() { action(4) }
@inline(never) final override func middle() { inner() }
}
// Check that call to Base2.middle can be devirtualized
//
// CHECK-LABEL: sil @$s19devirt_default_case9callOuteryS2iF
// CHECK: function_ref @$s19devirt_default_case5Base233_{{.*}}5inner
// CHECK: function_ref @$s19devirt_default_case8Derived233_{{.*}}6middle
// CHECK-NOT: class_method
// CHECK: } // end sil function '$s19devirt_default_case9callOuteryS2iF'
public func callOuter(_ x: Int) -> Int {
var o:Base2
if x == 1 {
o = Base2()
} else {
o = Derived2()
}
o.outer()
return x
}
// internl class
class Base3 {
@inline(never) func inner() { action(5)}
@inline(never) func middle() { inner() }
// Check that call to Base3.middle can be devirtualized when not compiling
// for testing.
//
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @$s19devirt_default_case5Base3C5outeryyF : $@convention(method) (@guaranteed Base3) -> () {
// CHECK: function_ref @$s19devirt_default_case5Base3C6middleyyF
// CHECK: function_ref @$s19devirt_default_case8Derived333_{{.*}}6middle
// CHECK-NORMAL-NOT: class_method
// CHECK-TESTABLE: class_method %0 : $Base3, #Base3.middle!1
// CHECK: } // end sil function '$s19devirt_default_case5Base3C5outeryyF'
@inline(never) func outer() {
middle()
}
}
// private class
private class Derived3 : Base3 {
override func inner() { action(6) }
@inline(never) final override func middle() { inner() }
override func outer() {
}
}
class A2 { @inline(never) func f() -> Int { return 0 } }
class B2 : A2 {}
class C2 : A2 {}
class D2: B2 {}
class E2 :C2 {}
class A3 { @inline(never) func f() -> Int { return 0 } }
class B3 : A3 { @inline(never) override func f() -> Int { return 1 }}
class C3 : A3 {}
class D3: C3 {}
class E3 :C3 {}
// CHECK-TESTABLE: sil{{( hidden)?}} [noinline] @$s19devirt_default_case3fooySiAA2A3CF
public func testfoo1() -> Int {
return foo(E2())
}
public func testfoo3() -> Int {
return foo(E3())
}
// Check that call to A3.f() can be devirtualized.
//
// CHECK-NORMAL: sil hidden [noinline] @$s19devirt_default_case3fooySiAA2A3CF
// CHECK-NORMAL: function_ref @$s19devirt_default_case2B3C1fSiyFTf4d_n
// CHECK-NORMAL: function_ref @$s19devirt_default_case2A3C1fSiyFTf4d_n
// CHECK-NORMAL-NOT: class_method
// CHECK: } // end sil function '$s19devirt_default_case3fooySiAA2A3CF'
class Base4 {
@inline(never)
func test() {
// Check that call to foo() can be devirtualized
//
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @$s19devirt_default_case5Base4C4testyyF
// CHECK: function_ref @$s19devirt_default_case5Base4C3fooyyFTf4d_n
// CHECK: function_ref @$s19devirt_default_case8Derived4C3fooyyFTf4d_n
// CHECK-NORMAL-NOT: class_method
// CHECK-TESTABLE: class_method %0 : $Base4, #Base4.foo!1
// CHECK: } // end sil function '$s19devirt_default_case5Base4C4testyyF'
foo()
}
@inline(never) func foo() { }
}
// A, C,D,E all use the same implementation.
// B has its own implementation.
@inline(never)
func foo(_ a: A3) -> Int {
return a.f()
}
class Derived4 : Base4 {
@inline(never) override func foo() { }
}
open class Base5 {
@inline(never)
open func test() {
foo()
}
@inline(never) public final func foo() { }
}
class Derived5 : Base5 {
}
open class C6 {
func bar() -> Int { return 1 }
}
class D6 : C6 {
override func bar() -> Int { return 2 }
}
@inline(never)
func check_static_class_devirt(_ c: C6) -> Int {
// Check that C.bar() and D.bar() are devirtualized.
//
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @$s19devirt_default_case019check_static_class_A0ySiAA2C6CF
// CHECK: checked_cast_br [exact] %0 : $C6 to $C6
// CHECK: checked_cast_br [exact] %0 : $C6 to $D6
// CHECK: class_method
// CHECK: } // end sil function '$s19devirt_default_case019check_static_class_A0ySiAA2C6CF'
return c.bar()
}
public func test_check_static_class_devirt() -> Int {
return check_static_class_devirt(D6())
}
class A7 { @inline(never) func foo() -> Bool { return false } }
class B7 : A7 { @inline(never) override func foo() -> Bool { return true } }
public func test_check_call_on_downcasted_instance() -> Bool {
return check_call_on_downcasted_instance(B7())
}
@inline(never)
func callIt(_ b3: Base3, _ b4: Base4, _ b5: Base5) {
b3.outer()
b4.test()
b5.test()
}
public func externalEntryPoint() {
callIt(Base3(), Base4(), Base5())
}
open class M {
func foo() -> Int32 {
return 0
}
}
open class M1: M {
@inline(never)
override func foo() -> Int32 {
return 1
}
}
internal class M2: M1 {
@inline(never)
override func foo() -> Int32 {
return 2
}
}
internal class M3: M1 {
@inline(never)
override func foo() -> Int32 {
return 3
}
}
internal class M22: M2 {
@inline(never)
override func foo() -> Int32 {
return 22
}
}
internal class M222: M22 {
@inline(never)
override func foo() -> Int32 {
return 222
}
}
internal class M33: M3 {
@inline(never)
override func foo() -> Int32 {
return 33
}
}
// Check that speculative devirtualization tries to devirtualize the first N
// alternatives, if it has too many.
// The alternatives should be taken in a breadth-first order, starting with
// the static type of the instance.
@inline(never)
public func testSpeculativeDevirtualizationWithTooManyAlternatives(_ c:M1) -> Int32{
return c.foo()
}
@inline(never)
func foo(_ a: A2) -> Int {
return a.f()
}
@inline(never)
func check_call_on_downcasted_instance(_ a: A7) -> Bool {
if a is B7 {
return (a as! B7).foo()
}
return a.foo()
}