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