//===----------------------------------------------------------------------===// // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include #include #include #include #include #include "CartesianBenchmarks.h" #include "benchmark/benchmark.h" // *** Localization *** enum class LocalizationE { False, True }; struct AllLocalizations : EnumValuesAsTuple { static constexpr const char* Names[] = {"LocFalse", "LocTrue"}; }; template struct Localization {}; template <> struct Localization { static constexpr const char* fmt = ""; }; template <> struct Localization { static constexpr const char* fmt = "L"; }; // *** Types *** enum class TypeE { Float, Double, LongDouble }; // TODO FMT Set to 3 after to_chars has long double suport. struct AllTypes : EnumValuesAsTuple { static constexpr const char* Names[] = {"Float", "Double", "LongDouble"}; }; template struct Type {}; template <> struct Type { using type = float; }; template <> struct Type { using type = double; }; template <> struct Type { using type = long double; }; // *** Values *** enum class ValueE { Inf, Random }; struct AllValues : EnumValuesAsTuple { static constexpr const char* Names[] = {"Inf", "Random"}; }; template struct Value {}; template <> struct Value { template static std::array make_data() { std::array result; std::fill(result.begin(), result.end(), -std::numeric_limits::infinity()); return result; } }; template <> struct Value { template static std::array make_data() { std::random_device seed; std::mt19937 generator(seed()); std::uniform_int_distribution> distribution; std::array result; std::generate(result.begin(), result.end(), [&] { while (true) { auto result = std::bit_cast(distribution(generator)); if (std::isfinite(result)) return result; } }); return result; } }; // *** Display Type *** enum class DisplayTypeE { Default, Hex, Scientific, Fixed, General, }; struct AllDisplayTypes : EnumValuesAsTuple { static constexpr const char* Names[] = {"DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed", "DisplayGeneral"}; }; template struct DisplayType {}; template <> struct DisplayType { static constexpr const char* fmt = ""; }; template <> struct DisplayType { static constexpr const char* fmt = "a"; }; template <> struct DisplayType { static constexpr const char* fmt = "e"; }; template <> struct DisplayType { static constexpr const char* fmt = "f"; }; template <> struct DisplayType { static constexpr const char* fmt = "g"; }; // *** Alignment *** enum class AlignmentE { None, Left, Center, Right, ZeroPadding }; struct AllAlignments : EnumValuesAsTuple { static constexpr const char* Names[] = {"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", "ZeroPadding"}; }; template struct Alignment {}; template <> struct Alignment { static constexpr const char* fmt = ""; }; template <> struct Alignment { // Width > PrecisionE::Huge static constexpr const char* fmt = "0<17500"; }; template <> struct Alignment { // Width > PrecisionE::Huge static constexpr const char* fmt = "0^17500"; }; template <> struct Alignment { // Width > PrecisionE::Huge static constexpr const char* fmt = "0>17500"; }; template <> struct Alignment { // Width > PrecisionE::Huge static constexpr const char* fmt = "017500"; }; enum class PrecisionE { None, Zero, Small, Huge }; struct AllPrecisions : EnumValuesAsTuple { static constexpr const char* Names[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"}; }; template struct Precision {}; template <> struct Precision { static constexpr const char* fmt = ""; }; template <> struct Precision { static constexpr const char* fmt = ".0"; }; template <> struct Precision { static constexpr const char* fmt = ".10"; }; template <> struct Precision { // The maximum precision for a minimal sub normal long double is +/- 0x1p-16494. // This value is always larger than that value forcing the trailing zero path // to be executed. static constexpr const char* fmt = ".17000"; }; template struct FloatingPoint { using F = typename Type::type; void run(benchmark::State& state) const { std::array data{Value::template make_data()}; std::array output; while (state.KeepRunningBatch(1000)) for (F value : data) benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value)); } std::string name() const { return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name(); } static constexpr std::string make_fmt() { return std::string("{:") + Alignment::fmt + Precision::fmt + Localization::fmt + DisplayType::fmt + "}"; } static constexpr auto fmt = []() { constexpr size_t s = make_fmt().size(); std::array r; std::ranges::copy(make_fmt(), r.begin()); return r; }(); }; int main(int argc, char** argv) { benchmark::Initialize(&argc, argv); if (benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; makeCartesianProductBenchmark(); benchmark::RunSpecifiedBenchmarks(); }