1db2944e3SMark de Wever //===----------------------------------------------------------------------===//
2db2944e3SMark de Wever // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3db2944e3SMark de Wever // See https://llvm.org/LICENSE.txt for license information.
4db2944e3SMark de Wever // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5db2944e3SMark de Wever //
6db2944e3SMark de Wever //===----------------------------------------------------------------------===//
7db2944e3SMark de Wever
8db2944e3SMark de Wever #include <format>
9db2944e3SMark de Wever
10db2944e3SMark de Wever #include <array>
11db2944e3SMark de Wever #include <limits>
12db2944e3SMark de Wever #include <random>
13db2944e3SMark de Wever #include <string>
14db2944e3SMark de Wever
15db2944e3SMark de Wever #include "CartesianBenchmarks.h"
16db2944e3SMark de Wever #include "benchmark/benchmark.h"
17db2944e3SMark de Wever
18db2944e3SMark de Wever // *** Localization ***
19db2944e3SMark de Wever enum class LocalizationE { False, True };
20db2944e3SMark de Wever struct AllLocalizations : EnumValuesAsTuple<AllLocalizations, LocalizationE, 2> {
21db2944e3SMark de Wever static constexpr const char* Names[] = {"LocFalse", "LocTrue"};
22db2944e3SMark de Wever };
23db2944e3SMark de Wever
24db2944e3SMark de Wever template <LocalizationE E>
25db2944e3SMark de Wever struct Localization {};
26db2944e3SMark de Wever
27db2944e3SMark de Wever template <>
28db2944e3SMark de Wever struct Localization<LocalizationE::False> {
29db2944e3SMark de Wever static constexpr const char* fmt = "";
30db2944e3SMark de Wever };
31db2944e3SMark de Wever
32db2944e3SMark de Wever template <>
33db2944e3SMark de Wever struct Localization<LocalizationE::True> {
34db2944e3SMark de Wever static constexpr const char* fmt = "L";
35db2944e3SMark de Wever };
36db2944e3SMark de Wever
37db2944e3SMark de Wever // *** Types ***
38db2944e3SMark de Wever enum class TypeE { Float, Double, LongDouble };
39db2944e3SMark de Wever // TODO FMT Set to 3 after to_chars has long double suport.
40db2944e3SMark de Wever struct AllTypes : EnumValuesAsTuple<AllTypes, TypeE, 2> {
41db2944e3SMark de Wever static constexpr const char* Names[] = {"Float", "Double", "LongDouble"};
42db2944e3SMark de Wever };
43db2944e3SMark de Wever
44db2944e3SMark de Wever template <TypeE E>
45db2944e3SMark de Wever struct Type {};
46db2944e3SMark de Wever
47db2944e3SMark de Wever template <>
48db2944e3SMark de Wever struct Type<TypeE::Float> {
49db2944e3SMark de Wever using type = float;
50db2944e3SMark de Wever };
51db2944e3SMark de Wever
52db2944e3SMark de Wever template <>
53db2944e3SMark de Wever struct Type<TypeE::Double> {
54db2944e3SMark de Wever using type = double;
55db2944e3SMark de Wever };
56db2944e3SMark de Wever
57db2944e3SMark de Wever template <>
58db2944e3SMark de Wever struct Type<TypeE::LongDouble> {
59db2944e3SMark de Wever using type = long double;
60db2944e3SMark de Wever };
61db2944e3SMark de Wever
62db2944e3SMark de Wever // *** Values ***
63db2944e3SMark de Wever enum class ValueE { Inf, Random };
64db2944e3SMark de Wever struct AllValues : EnumValuesAsTuple<AllValues, ValueE, 2> {
65db2944e3SMark de Wever static constexpr const char* Names[] = {"Inf", "Random"};
66db2944e3SMark de Wever };
67db2944e3SMark de Wever
68db2944e3SMark de Wever template <ValueE E>
69db2944e3SMark de Wever struct Value {};
70db2944e3SMark de Wever
71db2944e3SMark de Wever template <>
72db2944e3SMark de Wever struct Value<ValueE::Inf> {
73db2944e3SMark de Wever template <class F>
make_dataValue74db2944e3SMark de Wever static std::array<F, 1000> make_data() {
75db2944e3SMark de Wever std::array<F, 1000> result;
76db2944e3SMark de Wever std::fill(result.begin(), result.end(), -std::numeric_limits<F>::infinity());
77db2944e3SMark de Wever return result;
78db2944e3SMark de Wever }
79db2944e3SMark de Wever };
80db2944e3SMark de Wever
81db2944e3SMark de Wever template <>
82db2944e3SMark de Wever struct Value<ValueE::Random> {
83db2944e3SMark de Wever template <class F>
make_dataValue84db2944e3SMark de Wever static std::array<F, 1000> make_data() {
85db2944e3SMark de Wever std::random_device seed;
86db2944e3SMark de Wever std::mt19937 generator(seed());
87db2944e3SMark de Wever std::uniform_int_distribution<std::conditional_t<sizeof(F) == sizeof(uint32_t), uint32_t, uint64_t>> distribution;
88db2944e3SMark de Wever
89db2944e3SMark de Wever std::array<F, 1000> result;
90db2944e3SMark de Wever std::generate(result.begin(), result.end(), [&] {
91db2944e3SMark de Wever while (true) {
92db2944e3SMark de Wever auto result = std::bit_cast<F>(distribution(generator));
93db2944e3SMark de Wever if (std::isfinite(result))
94db2944e3SMark de Wever return result;
95db2944e3SMark de Wever }
96db2944e3SMark de Wever });
97db2944e3SMark de Wever return result;
98db2944e3SMark de Wever }
99db2944e3SMark de Wever };
100db2944e3SMark de Wever
101db2944e3SMark de Wever // *** Display Type ***
102db2944e3SMark de Wever enum class DisplayTypeE {
103db2944e3SMark de Wever Default,
104db2944e3SMark de Wever Hex,
105db2944e3SMark de Wever Scientific,
106db2944e3SMark de Wever Fixed,
107db2944e3SMark de Wever General,
108db2944e3SMark de Wever };
109db2944e3SMark de Wever struct AllDisplayTypes : EnumValuesAsTuple<AllDisplayTypes, DisplayTypeE, 5> {
110db2944e3SMark de Wever static constexpr const char* Names[] = {"DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed",
111db2944e3SMark de Wever "DisplayGeneral"};
112db2944e3SMark de Wever };
113db2944e3SMark de Wever
114db2944e3SMark de Wever template <DisplayTypeE E>
115db2944e3SMark de Wever struct DisplayType {};
116db2944e3SMark de Wever
117db2944e3SMark de Wever template <>
118db2944e3SMark de Wever struct DisplayType<DisplayTypeE::Default> {
119db2944e3SMark de Wever static constexpr const char* fmt = "";
120db2944e3SMark de Wever };
121db2944e3SMark de Wever
122db2944e3SMark de Wever template <>
123db2944e3SMark de Wever struct DisplayType<DisplayTypeE::Hex> {
124db2944e3SMark de Wever static constexpr const char* fmt = "a";
125db2944e3SMark de Wever };
126db2944e3SMark de Wever
127db2944e3SMark de Wever template <>
128db2944e3SMark de Wever struct DisplayType<DisplayTypeE::Scientific> {
129db2944e3SMark de Wever static constexpr const char* fmt = "e";
130db2944e3SMark de Wever };
131db2944e3SMark de Wever
132db2944e3SMark de Wever template <>
133db2944e3SMark de Wever struct DisplayType<DisplayTypeE::Fixed> {
134db2944e3SMark de Wever static constexpr const char* fmt = "f";
135db2944e3SMark de Wever };
136db2944e3SMark de Wever
137db2944e3SMark de Wever template <>
138db2944e3SMark de Wever struct DisplayType<DisplayTypeE::General> {
139db2944e3SMark de Wever static constexpr const char* fmt = "g";
140db2944e3SMark de Wever };
141db2944e3SMark de Wever
142db2944e3SMark de Wever // *** Alignment ***
143db2944e3SMark de Wever enum class AlignmentE { None, Left, Center, Right, ZeroPadding };
144db2944e3SMark de Wever struct AllAlignments : EnumValuesAsTuple<AllAlignments, AlignmentE, 5> {
145db2944e3SMark de Wever static constexpr const char* Names[] = {"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight",
146db2944e3SMark de Wever "ZeroPadding"};
147db2944e3SMark de Wever };
148db2944e3SMark de Wever
149db2944e3SMark de Wever template <AlignmentE E>
150db2944e3SMark de Wever struct Alignment {};
151db2944e3SMark de Wever
152db2944e3SMark de Wever template <>
153db2944e3SMark de Wever struct Alignment<AlignmentE::None> {
154db2944e3SMark de Wever static constexpr const char* fmt = "";
155db2944e3SMark de Wever };
156db2944e3SMark de Wever
157db2944e3SMark de Wever template <>
158db2944e3SMark de Wever struct Alignment<AlignmentE::Left> {
159db2944e3SMark de Wever // Width > PrecisionE::Huge
160db2944e3SMark de Wever static constexpr const char* fmt = "0<17500";
161db2944e3SMark de Wever };
162db2944e3SMark de Wever
163db2944e3SMark de Wever template <>
164db2944e3SMark de Wever struct Alignment<AlignmentE::Center> {
165db2944e3SMark de Wever // Width > PrecisionE::Huge
166db2944e3SMark de Wever static constexpr const char* fmt = "0^17500";
167db2944e3SMark de Wever };
168db2944e3SMark de Wever
169db2944e3SMark de Wever template <>
170db2944e3SMark de Wever struct Alignment<AlignmentE::Right> {
171db2944e3SMark de Wever // Width > PrecisionE::Huge
172db2944e3SMark de Wever static constexpr const char* fmt = "0>17500";
173db2944e3SMark de Wever };
174db2944e3SMark de Wever
175db2944e3SMark de Wever template <>
176db2944e3SMark de Wever struct Alignment<AlignmentE::ZeroPadding> {
177db2944e3SMark de Wever // Width > PrecisionE::Huge
178db2944e3SMark de Wever static constexpr const char* fmt = "017500";
179db2944e3SMark de Wever };
180db2944e3SMark de Wever
181db2944e3SMark de Wever enum class PrecisionE { None, Zero, Small, Huge };
182db2944e3SMark de Wever struct AllPrecisions : EnumValuesAsTuple<AllPrecisions, PrecisionE, 4> {
183db2944e3SMark de Wever static constexpr const char* Names[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"};
184db2944e3SMark de Wever };
185db2944e3SMark de Wever
186db2944e3SMark de Wever template <PrecisionE E>
187db2944e3SMark de Wever struct Precision {};
188db2944e3SMark de Wever
189db2944e3SMark de Wever template <>
190db2944e3SMark de Wever struct Precision<PrecisionE::None> {
191db2944e3SMark de Wever static constexpr const char* fmt = "";
192db2944e3SMark de Wever };
193db2944e3SMark de Wever
194db2944e3SMark de Wever template <>
195db2944e3SMark de Wever struct Precision<PrecisionE::Zero> {
196db2944e3SMark de Wever static constexpr const char* fmt = ".0";
197db2944e3SMark de Wever };
198db2944e3SMark de Wever
199db2944e3SMark de Wever template <>
200db2944e3SMark de Wever struct Precision<PrecisionE::Small> {
201db2944e3SMark de Wever static constexpr const char* fmt = ".10";
202db2944e3SMark de Wever };
203db2944e3SMark de Wever
204db2944e3SMark de Wever template <>
205db2944e3SMark de Wever struct Precision<PrecisionE::Huge> {
206db2944e3SMark de Wever // The maximum precision for a minimal sub normal long double is ±0x1p-16494.
207db2944e3SMark de Wever // This value is always larger than that value forcing the trailing zero path
208db2944e3SMark de Wever // to be executed.
209db2944e3SMark de Wever static constexpr const char* fmt = ".17000";
210db2944e3SMark de Wever };
211db2944e3SMark de Wever
212db2944e3SMark de Wever template <class L, class DT, class T, class V, class A, class P>
213db2944e3SMark de Wever struct FloatingPoint {
214db2944e3SMark de Wever using F = typename Type<T::value>::type;
215db2944e3SMark de Wever
runFloatingPoint216db2944e3SMark de Wever void run(benchmark::State& state) const {
217db2944e3SMark de Wever std::array<F, 1000> data{Value<V::value>::template make_data<F>()};
218db2944e3SMark de Wever std::array<char, 20'000> output;
219db2944e3SMark de Wever
220db2944e3SMark de Wever while (state.KeepRunningBatch(1000))
221db2944e3SMark de Wever for (F value : data)
222*aed5ddf8SMark de Wever benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
223db2944e3SMark de Wever }
224db2944e3SMark de Wever
nameFloatingPoint225db2944e3SMark de Wever std::string name() const {
226db2944e3SMark de Wever return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name();
227db2944e3SMark de Wever }
228*aed5ddf8SMark de Wever
make_fmtFloatingPoint229*aed5ddf8SMark de Wever static constexpr std::string make_fmt() {
230*aed5ddf8SMark de Wever return std::string("{:") + Alignment<A::value>::fmt + Precision<P::value>::fmt + Localization<L::value>::fmt +
231*aed5ddf8SMark de Wever DisplayType<DT::value>::fmt + "}";
232*aed5ddf8SMark de Wever }
233*aed5ddf8SMark de Wever
__anon1dbc81ed0202FloatingPoint234*aed5ddf8SMark de Wever static constexpr auto fmt = []() {
235*aed5ddf8SMark de Wever constexpr size_t s = make_fmt().size();
236*aed5ddf8SMark de Wever std::array<char, s> r;
237*aed5ddf8SMark de Wever std::ranges::copy(make_fmt(), r.begin());
238*aed5ddf8SMark de Wever return r;
239*aed5ddf8SMark de Wever }();
240db2944e3SMark de Wever };
241db2944e3SMark de Wever
main(int argc,char ** argv)242db2944e3SMark de Wever int main(int argc, char** argv) {
243db2944e3SMark de Wever benchmark::Initialize(&argc, argv);
244db2944e3SMark de Wever if (benchmark::ReportUnrecognizedArguments(argc, argv))
245db2944e3SMark de Wever return 1;
246db2944e3SMark de Wever
247db2944e3SMark de Wever makeCartesianProductBenchmark<FloatingPoint, AllLocalizations, AllDisplayTypes, AllTypes, AllValues, AllAlignments,
248db2944e3SMark de Wever AllPrecisions>();
249db2944e3SMark de Wever
250db2944e3SMark de Wever benchmark::RunSpecifiedBenchmarks();
251db2944e3SMark de Wever }
252