mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
332 lines
6.9 KiB
Swift
332 lines
6.9 KiB
Swift
//===--- PolymorphicCalls.swift -------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/*
|
|
This benchmark is used to check the performance of polymorphic invocations.
|
|
Essentially, it checks how good a compiler can optimize virtual calls of class
|
|
methods in cases where multiple sub-classes of a given class are available.
|
|
|
|
In particular, this benchmark would benefit from a good devirtualization.
|
|
In case of applying a speculative devirtualization, it would be benefit from
|
|
applying a jump-threading in combination with the speculative devirtualization.
|
|
*/
|
|
|
|
import TestsUtils
|
|
|
|
public let benchmarks = [
|
|
BenchmarkInfo(
|
|
name: "PolymorphicCalls",
|
|
runFunction: run_PolymorphicCalls,
|
|
tags: [.abstraction, .cpubench]
|
|
),
|
|
]
|
|
|
|
public class A {
|
|
let b: B
|
|
init(b:B) {
|
|
self.b = b
|
|
}
|
|
|
|
public func run1() -> Int {
|
|
return b.f1() + b.f2() + b.f3()
|
|
}
|
|
|
|
public func run2() -> Int {
|
|
return b.run()
|
|
}
|
|
}
|
|
|
|
// B has no known subclasses
|
|
public class B {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
public func f1() -> Int {
|
|
return x + 1
|
|
}
|
|
public func f2() -> Int {
|
|
return x + 11
|
|
}
|
|
public func f3() -> Int {
|
|
return x + 111
|
|
}
|
|
public func run() -> Int {
|
|
return f1() + f2() + f3()
|
|
}
|
|
}
|
|
|
|
|
|
public class A1 {
|
|
let b: B1
|
|
public init(b:B1) {
|
|
self.b = b
|
|
}
|
|
public func run1() -> Int {
|
|
return b.f1() + b.f2() + b.f3()
|
|
}
|
|
public func run2() -> Int {
|
|
return b.run()
|
|
}
|
|
}
|
|
|
|
// B1 has 1 known subclass
|
|
public class B1 {
|
|
func f1() -> Int { return 0 }
|
|
func f2() -> Int { return 0 }
|
|
func f3() -> Int { return 0 }
|
|
public func run() -> Int {
|
|
return f1() + f2() + f3()
|
|
}
|
|
}
|
|
|
|
public class C1: B1 {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
override public func f1() -> Int {
|
|
return x + 2
|
|
}
|
|
override public func f2() -> Int {
|
|
return x + 22
|
|
}
|
|
override public func f3() -> Int {
|
|
return x + 222
|
|
}
|
|
}
|
|
|
|
|
|
public class A2 {
|
|
let b:B2
|
|
public init(b:B2) {
|
|
self.b = b
|
|
}
|
|
public func run1() -> Int {
|
|
return b.f1() + b.f2() + b.f3()
|
|
}
|
|
public func run2() -> Int {
|
|
return b.run()
|
|
}
|
|
}
|
|
|
|
// B2 has 2 known subclasses
|
|
public class B2 {
|
|
func f1() -> Int { return 0 }
|
|
func f2() -> Int { return 0 }
|
|
func f3() -> Int { return 0 }
|
|
public func run() -> Int {
|
|
return f1() + f2() + f3()
|
|
}
|
|
}
|
|
|
|
public class C2 : B2 {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
override public func f1() -> Int {
|
|
return x + 3
|
|
}
|
|
override public func f2() -> Int {
|
|
return x + 33
|
|
}
|
|
override public func f3() -> Int {
|
|
return x + 333
|
|
}
|
|
}
|
|
|
|
public class D2 : B2 {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
override public func f1() -> Int {
|
|
return x + 4
|
|
}
|
|
override public func f2() -> Int {
|
|
return x + 44
|
|
}
|
|
override public func f3() -> Int {
|
|
return x + 444
|
|
}
|
|
}
|
|
|
|
|
|
public class A3 {
|
|
let b: B3
|
|
|
|
public init(b:B3) {
|
|
self.b = b
|
|
}
|
|
|
|
public func run1() -> Int {
|
|
return b.f1() + b.f2() + b.f3()
|
|
}
|
|
public func run2() -> Int {
|
|
return b.run()
|
|
}
|
|
}
|
|
|
|
|
|
// B3 has 3 known subclasses
|
|
public class B3 {
|
|
func f1() -> Int { return 0 }
|
|
func f2() -> Int { return 0 }
|
|
func f3() -> Int { return 0 }
|
|
public func run() -> Int {
|
|
return f1() + f2() + f3()
|
|
}
|
|
}
|
|
|
|
|
|
public class C3: B3 {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
override public func f1() -> Int {
|
|
return x + 5
|
|
}
|
|
override public func f2() -> Int {
|
|
return x + 55
|
|
}
|
|
override public func f3() -> Int {
|
|
return x + 555
|
|
}
|
|
}
|
|
public class D3: B3 {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
override public func f1() -> Int {
|
|
return x + 6
|
|
}
|
|
override public func f2() -> Int {
|
|
return x + 66
|
|
}
|
|
override public func f3() -> Int {
|
|
return x + 666
|
|
}
|
|
}
|
|
public class E3:B3 {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
override public func f1() -> Int {
|
|
return x + 7
|
|
}
|
|
override public func f2() -> Int {
|
|
return x + 77
|
|
}
|
|
override public func f3() -> Int {
|
|
return x + 777
|
|
}
|
|
}
|
|
public class F3 : B3 {
|
|
let x: Int
|
|
init(x:Int) {
|
|
self.x = x
|
|
}
|
|
override public func f1() -> Int {
|
|
return x + 8
|
|
}
|
|
override public func f2() -> Int {
|
|
return x + 88
|
|
}
|
|
override public func f3() -> Int {
|
|
return x + 888
|
|
}}
|
|
|
|
// Test the cost of polymorphic method invocation
|
|
// on a class without any subclasses
|
|
@inline(never)
|
|
func test(_ a:A, _ upTo: Int) -> Int64 {
|
|
var cnt: Int64 = 0
|
|
for _ in 0..<upTo {
|
|
cnt += Int64(a.run2())
|
|
}
|
|
return cnt
|
|
}
|
|
|
|
// Test the cost of polymorphic method invocation
|
|
// on a class with 1 subclass
|
|
@inline(never)
|
|
func test(_ a:A1, _ upTo: Int) -> Int64 {
|
|
var cnt: Int64 = 0
|
|
for _ in 0..<upTo {
|
|
cnt += Int64(a.run2())
|
|
}
|
|
return cnt
|
|
}
|
|
|
|
// Test the cost of polymorphic method invocation
|
|
// on a class with 2 subclasses
|
|
@inline(never)
|
|
func test(_ a:A2, _ upTo: Int) -> Int64 {
|
|
var cnt: Int64 = 0
|
|
for _ in 0..<upTo {
|
|
cnt += Int64(a.run2())
|
|
}
|
|
return cnt
|
|
}
|
|
|
|
// Test the cost of polymorphic method invocation
|
|
// on a class with 2 subclasses on objects
|
|
// of different subclasses
|
|
@inline(never)
|
|
func test(_ a2_c2:A2, _ a2_d2:A2, _ upTo: Int) -> Int64 {
|
|
var cnt: Int64 = 0
|
|
for _ in 0..<upTo/2 {
|
|
cnt += Int64(a2_c2.run2())
|
|
cnt += Int64(a2_d2.run2())
|
|
}
|
|
return cnt
|
|
}
|
|
|
|
// Test the cost of polymorphic method invocation
|
|
// on a class with 4 subclasses on objects
|
|
// of different subclasses
|
|
@inline(never)
|
|
func test(_ a3_c3: A3, _ a3_d3: A3, _ a3_e3: A3, _ a3_f3: A3, _ upTo: Int) -> Int64 {
|
|
var cnt: Int64 = 0
|
|
for _ in 0..<upTo/4 {
|
|
cnt += Int64(a3_c3.run2())
|
|
cnt += Int64(a3_d3.run2())
|
|
cnt += Int64(a3_e3.run2())
|
|
cnt += Int64(a3_f3.run2())
|
|
}
|
|
return cnt
|
|
}
|
|
|
|
let a = A(b:B(x:1))
|
|
let a1 = A1(b:C1(x:1))
|
|
let a2 = A2(b:C2(x:1))
|
|
let a2_c2 = A2(b:C2(x:1))
|
|
let a2_d2 = A2(b:D2(x:1))
|
|
let a3_c3 = A3(b:C3(x:1))
|
|
let a3_d3 = A3(b:D3(x:1))
|
|
let a3_e3 = A3(b:E3(x:1))
|
|
let a3_f3 = A3(b:F3(x:1))
|
|
|
|
@inline(never)
|
|
public func run_PolymorphicCalls(_ N:Int) {
|
|
let upTo = 10_000 * N
|
|
_ = test(a, upTo)
|
|
_ = test(a1, upTo)
|
|
_ = test(a2, upTo)
|
|
_ = test(a2_c2, a2_d2, upTo)
|
|
_ = test(a3_c3, a3_d3, a3_e3, a3_f3, upTo)
|
|
}
|