1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// UNSUPPORTED: c++03
10
11#include <cstddef>
12
13#include "benchmark/benchmark.h"
14
15template <std::size_t Depth>
16struct Chain : Chain<Depth - 1> {};
17
18template <>
19struct Chain<0> {
20 virtual ~Chain() noexcept = default;
21};
22
23template <std::size_t Index, std::size_t Depth>
24struct Dag : Dag<Index, Depth - 1>, Dag<Index + 1, Depth - 1> {};
25
26template <std::size_t Index>
27struct Dag<Index, 0> {
28 virtual ~Dag() noexcept = default;
29};
30
31template <std::size_t Depth>
32struct VChain : virtual VChain<Depth - 1> {};
33
34template <>
35struct VChain<0> {
36 virtual ~VChain() noexcept = default;
37};
38
39template <std::size_t Index, std::size_t Depth>
40struct VDag : virtual VDag<Index, Depth - 1>, virtual VDag<Index + 1, Depth - 1> {};
41
42template <std::size_t Index>
43struct VDag<Index, 0> {
44 virtual ~VDag() noexcept = default;
45};
46
47template <typename Dyn, typename From, typename To = Dyn>
48static void DynCast(benchmark::State& state) {
49 Dyn obj;
50 From* from_ptr = &obj;
51 for (auto _ : state) {
52 To* to_ptr = dynamic_cast<To*>(from_ptr);
53 benchmark::DoNotOptimize(to_ptr);
54 }
55}
56
57static void StaticCast(benchmark::State& state) {
58 Chain<9> obj;
59 Chain<0>* from_ptr = &obj;
60 for (auto _ : state) {
61 Chain<9>* to_ptr = static_cast<Chain<9>*>(from_ptr);
62 benchmark::DoNotOptimize(value&: to_ptr);
63 }
64}
65
66// Downcast along a chain from base to the most derived type
67BENCHMARK(DynCast<Chain<1>, Chain<0>>)->Name(name: "Chain, 1 level");
68BENCHMARK(DynCast<Chain<2>, Chain<0>>)->Name(name: "Chain, 2 levels");
69BENCHMARK(DynCast<Chain<3>, Chain<0>>)->Name(name: "Chain, 3 levels");
70BENCHMARK(DynCast<Chain<4>, Chain<0>>)->Name(name: "Chain, 4 levels");
71BENCHMARK(DynCast<Chain<5>, Chain<0>>)->Name(name: "Chain, 5 levels");
72BENCHMARK(DynCast<Chain<6>, Chain<0>>)->Name(name: "Chain, 6 levels");
73BENCHMARK(DynCast<Chain<7>, Chain<0>>)->Name(name: "Chain, 7 levels");
74BENCHMARK(DynCast<Chain<8>, Chain<0>>)->Name(name: "Chain, 8 levels");
75BENCHMARK(DynCast<Chain<9>, Chain<0>>)->Name(name: "Chain, 9 levels");
76
77// Downcast along a chain from base to the middle of the chain
78BENCHMARK(DynCast<Chain<2>, Chain<0>, Chain<1>>)->Name(name: "Chain middle, 1 level");
79BENCHMARK(DynCast<Chain<4>, Chain<0>, Chain<2>>)->Name(name: "Chain middle, 2 levels");
80BENCHMARK(DynCast<Chain<6>, Chain<0>, Chain<3>>)->Name(name: "Chain middle, 3 levels");
81BENCHMARK(DynCast<Chain<8>, Chain<0>, Chain<4>>)->Name(name: "Chain middle, 4 levels");
82
83// Downcast along a chain that fails
84BENCHMARK(DynCast<Chain<1>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 1 level");
85BENCHMARK(DynCast<Chain<2>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 2 levels");
86BENCHMARK(DynCast<Chain<3>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 3 levels");
87BENCHMARK(DynCast<Chain<4>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 4 levels");
88BENCHMARK(DynCast<Chain<5>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 5 levels");
89BENCHMARK(DynCast<Chain<6>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 6 levels");
90BENCHMARK(DynCast<Chain<7>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 7 levels");
91BENCHMARK(DynCast<Chain<8>, Chain<0>, Chain<9>>)->Name(name: "Chain fail, 8 levels");
92
93// Downcast along a virtual inheritance chain from base to the most derived type
94BENCHMARK(DynCast<VChain<1>, VChain<0>>)->Name(name: "VChain, 1 level");
95BENCHMARK(DynCast<VChain<2>, VChain<0>>)->Name(name: "VChain, 2 levels");
96BENCHMARK(DynCast<VChain<3>, VChain<0>>)->Name(name: "VChain, 3 levels");
97BENCHMARK(DynCast<VChain<4>, VChain<0>>)->Name(name: "VChain, 4 levels");
98BENCHMARK(DynCast<VChain<5>, VChain<0>>)->Name(name: "VChain, 5 levels");
99
100// Downcast along a virtual inheritance chain from base to the middle of the chain
101BENCHMARK(DynCast<VChain<2>, VChain<0>, VChain<1>>)->Name(name: "VChain middle, 1 level");
102BENCHMARK(DynCast<VChain<4>, VChain<0>, VChain<2>>)->Name(name: "VChain middle, 2 levels");
103BENCHMARK(DynCast<VChain<6>, VChain<0>, VChain<3>>)->Name(name: "VChain middle, 3 levels");
104BENCHMARK(DynCast<VChain<8>, VChain<0>, VChain<4>>)->Name(name: "VChain middle, 4 levels");
105
106// Downcast along a virtual chain that fails
107BENCHMARK(DynCast<VChain<1>, VChain<0>, VChain<8>>)->Name(name: "VChain fail, 1 level");
108BENCHMARK(DynCast<VChain<2>, VChain<0>, VChain<8>>)->Name(name: "VChain fail, 2 levels");
109BENCHMARK(DynCast<VChain<3>, VChain<0>, VChain<8>>)->Name(name: "VChain fail, 3 levels");
110BENCHMARK(DynCast<VChain<4>, VChain<0>, VChain<8>>)->Name(name: "VChain fail, 4 levels");
111BENCHMARK(DynCast<VChain<5>, VChain<0>, VChain<8>>)->Name(name: "VChain fail, 5 levels");
112
113// Downcast along a DAG from base to the most derived type
114BENCHMARK(DynCast<Dag<0, 3>, Dag<3, 0>>)->Name(name: "DAG rightmost, 3 levels");
115BENCHMARK(DynCast<Dag<0, 4>, Dag<4, 0>>)->Name(name: "DAG rightmost, 4 levels");
116BENCHMARK(DynCast<Dag<0, 5>, Dag<5, 0>>)->Name(name: "DAG rightmost, 5 levels");
117BENCHMARK(DynCast<Dag<0, 3>, Dag<0, 0>>)->Name(name: "DAG leftmost, 3 levels");
118BENCHMARK(DynCast<Dag<0, 4>, Dag<0, 0>>)->Name(name: "DAG leftmost, 4 levels");
119BENCHMARK(DynCast<Dag<0, 5>, Dag<0, 0>>)->Name(name: "DAG leftmost, 5 levels");
120
121// Downcast along a DAG from base to the middle of the DAG
122BENCHMARK(DynCast<Dag<0, 4>, Dag<4, 0>, Dag<3, 1>>)->Name(name: "DAG rightmost middle, 1 level");
123BENCHMARK(DynCast<Dag<0, 4>, Dag<4, 0>, Dag<2, 2>>)->Name(name: "DAG rightmost middle, 2 levels");
124BENCHMARK(DynCast<Dag<0, 4>, Dag<4, 0>, Dag<1, 3>>)->Name(name: "DAG rightmost middle, 3 levels");
125BENCHMARK(DynCast<Dag<0, 4>, Dag<0, 0>, Dag<0, 1>>)->Name(name: "DAG leftmost middle, 1 level");
126BENCHMARK(DynCast<Dag<0, 4>, Dag<0, 0>, Dag<0, 2>>)->Name(name: "DAG leftmost middle, 2 levels");
127BENCHMARK(DynCast<Dag<0, 4>, Dag<0, 0>, Dag<0, 3>>)->Name(name: "DAG leftmost middle, 3 levels");
128
129// Sidecast along a DAG
130BENCHMARK(DynCast<Dag<0, 3>, Dag<3, 0>, Dag<0, 0>>)->Name(name: "DAG sidecast, 3 levels");
131BENCHMARK(DynCast<Dag<0, 3>, Dag<2, 1>, Dag<0, 1>>)->Name(name: "DAG sidecast, 2 levels");
132BENCHMARK(DynCast<Dag<0, 3>, Dag<1, 2>, Dag<0, 2>>)->Name(name: "DAG sidecast, 1 level");
133
134// Sidecast along a DAG that fails
135BENCHMARK(DynCast<Dag<0, 3>, Dag<3, 0>, Dag<0, 4>>)->Name(name: "DAG sidecast fail, 3 levels");
136BENCHMARK(DynCast<Dag<0, 3>, Dag<2, 1>, Dag<0, 4>>)->Name(name: "DAG sidecast fail, 2 levels");
137BENCHMARK(DynCast<Dag<0, 3>, Dag<1, 2>, Dag<0, 4>>)->Name(name: "DAG sidecast fail, 1 level");
138
139// Downcast along a virtual inheritance DAG from base to the most derived type
140BENCHMARK(DynCast<VDag<0, 3>, VDag<3, 0>>)->Name(name: "VDAG rightmost, 3 levels");
141BENCHMARK(DynCast<VDag<0, 4>, VDag<4, 0>>)->Name(name: "VDAG rightmost, 4 levels");
142BENCHMARK(DynCast<VDag<0, 5>, VDag<5, 0>>)->Name(name: "VDAG rightmost, 5 levels");
143BENCHMARK(DynCast<VDag<0, 3>, VDag<0, 0>>)->Name(name: "VDAG leftmost, 3 levels");
144BENCHMARK(DynCast<VDag<0, 4>, VDag<0, 0>>)->Name(name: "VDAG leftmost, 4 levels");
145BENCHMARK(DynCast<VDag<0, 5>, VDag<0, 0>>)->Name(name: "VDAG leftmost, 5 levels");
146
147// Downcast along a virtual inheritance DAG from base to the middle of the DAG
148BENCHMARK(DynCast<VDag<0, 3>, VDag<3, 0>, VDag<2, 1>>)->Name(name: "VDAG rightmost middle, 1 level");
149BENCHMARK(DynCast<VDag<0, 4>, VDag<4, 0>, VDag<2, 2>>)->Name(name: "VDAG rightmost middle, 2 levels");
150BENCHMARK(DynCast<VDag<0, 5>, VDag<5, 0>, VDag<2, 3>>)->Name(name: "VDAG rightmost middle, 3 levels");
151BENCHMARK(DynCast<VDag<0, 3>, VDag<0, 0>, VDag<0, 1>>)->Name(name: "VDAG leftmost middle, 1 level");
152BENCHMARK(DynCast<VDag<0, 4>, VDag<0, 0>, VDag<0, 2>>)->Name(name: "VDAG leftmost middle, 2 levels");
153BENCHMARK(DynCast<VDag<0, 5>, VDag<0, 0>, VDag<0, 3>>)->Name(name: "VDAG leftmost middle, 3 levels");
154
155// Sidecast along a virtual inheritance DAG
156BENCHMARK(DynCast<VDag<0, 3>, VDag<3, 0>, VDag<0, 0>>)->Name(name: "VDAG sidecast, 3 levels");
157BENCHMARK(DynCast<VDag<0, 3>, VDag<2, 1>, VDag<0, 1>>)->Name(name: "VDAG sidecast, 2 levels");
158BENCHMARK(DynCast<VDag<0, 3>, VDag<1, 2>, VDag<0, 2>>)->Name(name: "VDAG sidecast, 1 level");
159
160// Sidecast along a virtual inheritance DAG that fails
161BENCHMARK(DynCast<VDag<0, 3>, VDag<3, 0>, VDag<0, 4>>)->Name(name: "VDAG sidecast fail, 3 levels");
162BENCHMARK(DynCast<VDag<0, 3>, VDag<2, 1>, VDag<0, 4>>)->Name(name: "VDAG sidecast fail, 2 levels");
163BENCHMARK(DynCast<VDag<0, 3>, VDag<1, 2>, VDag<0, 4>>)->Name(name: "VDAG sidecast fail, 1 level");
164
165// Cast to complete object pointer
166BENCHMARK(DynCast<Chain<8>, Chain<0>, void>)->Name(name: "Chain to complete");
167BENCHMARK(DynCast<VChain<5>, VChain<0>, void>)->Name(name: "VChain to complete");
168BENCHMARK(DynCast<Dag<0, 3>, Dag<3, 0>, void>)->Name(name: "DAG to complete");
169BENCHMARK(DynCast<VDag<0, 3>, VDag<3, 0>, void>)->Name(name: "VDAG to complete");
170
171// Static cast as the baseline.
172BENCHMARK(StaticCast)->Name(name: "Static");
173
174BENCHMARK_MAIN();
175

source code of libcxx/test/benchmarks/libcxxabi/dynamic_cast.bench.cpp