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 // This is a dummy feature that prevents this test from running by default.
10 // REQUIRES: template-cost-testing
11
12 // Test the cost of the mechanism used to create an overload set used by variant
13 // to determine which alternative to construct.
14
15 // The table below compares the compile time and object size for each of the
16 // variants listed in the RUN script.
17 //
18 // Impl Compile Time Object Size
19 // -----------------------------------------------------
20 // flat: 959 ms 792 KiB
21 // recursive: 23,444 ms 23,000 KiB
22 // -----------------------------------------------------
23 // variant_old: 16,894 ms 17,000 KiB
24 // variant_new: 1,105 ms 828 KiB
25
26
27 // RUN: %{cxx} %{flags} %{compile_flags} -std=c++17 -c %s \
28 // RUN: -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -g \
29 // RUN: -DTEST_NS=flat_impl -o %S/flat.o
30 // RUN: %{cxx} %{flags} %{compile_flags} -std=c++17 -c %s \
31 // RUN: -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -g \
32 // RUN: -DTEST_NS=rec_impl -o %S/rec.o
33 // RUN: %{cxx} %{flags} %{compile_flags} -std=c++17 -c %s \
34 // RUN: -ggdb -ggnu-pubnames -ftemplate-depth=5000 -ftime-trace -g \
35 // RUN: -DTEST_NS=variant_impl -o %S/variant.o
36
37 #include <type_traits>
38 #include <tuple>
39 #include <cassert>
40 #include <variant>
41
42 #include "test_macros.h"
43 #include "template_cost_testing.h"
44
45 template <std::size_t Idx>
46 struct TestType {};
47
48 template <class T>
49 struct ID {
50 using type = T;
51 };
52
53 namespace flat_impl {
54
55 struct OverloadBase { void operator()() const; };
56
57 template <class Tp, std::size_t Idx>
58 struct Overload {
59 auto operator()(Tp, Tp) const -> ID<Tp>;
60 };
61
62 template <class ...Bases>
63 struct AllOverloads : OverloadBase, Bases... {};
64
65 template <class IdxSeq>
66 struct MakeOverloads;
67
68 template <std::size_t ..._Idx>
69 struct MakeOverloads<std::__tuple_indices<_Idx...> > {
70 template <class ...Types>
71 using Apply = AllOverloads<Overload<Types, _Idx>...>;
72 };
73
74 template <class ...Types>
75 using Overloads = typename MakeOverloads<
76 std::__make_indices_imp<sizeof...(Types), 0> >::template Apply<Types...>;
77
78 } // namespace flat_impl
79
80
81 namespace rec_impl {
82
83 template <class... Types> struct Overload;
84
85 template <>
86 struct Overload<> { void operator()() const; };
87
88 template <class Tp, class... Types>
89 struct Overload<Tp, Types...> : Overload<Types...> {
90 using Overload<Types...>::operator();
91 auto operator()(Tp, Tp) const -> ID<Tp>;
92 };
93
94 template <class... Types>
95 using Overloads = Overload<Types...>;
96
97 } // namespace rec_impl
98
99 namespace variant_impl {
100 template <class ...Types>
101 using Overloads = std::__variant_detail::_MakeOverloads<Types...>;
102 } // namespace variant_impl
103
104 #ifndef TEST_NS
105 #error TEST_NS must be defined
106 #endif
107
108 #define TEST_TYPE() TestType< __COUNTER__ >,
109 using T1 = TEST_NS::Overloads<REPEAT_1000(TEST_TYPE) TestType<1>, TestType<1>, int>;
110 static_assert(__COUNTER__ >= 1000, "");
111
fn1(T1 x)112 void fn1(T1 x) { DoNotOptimize(&x); }
fn2(typename std::invoke_result_t<T1,int,int>::type x)113 void fn2(typename std::invoke_result_t<T1, int, int>::type x) { DoNotOptimize(&x); }
114
main(int,char **)115 int main(int, char**) {
116 DoNotOptimize(&fn1);
117 DoNotOptimize(&fn2);
118 return 0;
119 }
120