[libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Sep 4 01:13:19 PDT 2024


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/107197

```
-------------------------------------------------------------------
Benchmark                                        old            new
-------------------------------------------------------------------
BM_format_string<char>/1                     42.1 ns        7.67 ns
BM_format_string<char>/2                     22.3 ns        3.84 ns
BM_format_string<char>/4                     10.6 ns        1.92 ns
BM_format_string<char>/8                     5.31 ns       0.815 ns
BM_format_string<char>/16                    2.79 ns       0.480 ns
BM_format_string<char>/32                    1.63 ns       0.550 ns
BM_format_string<char>/64                   0.782 ns       0.276 ns
BM_format_string<char>/128                  0.397 ns       0.145 ns
BM_format_string<char>/256                  0.211 ns       0.066 ns
BM_format_string<char>/512                  0.154 ns       0.035 ns
BM_format_string<char>/1024                 0.146 ns       0.021 ns
BM_format_string<char>/2048                 0.125 ns       0.033 ns
BM_format_string<char>/4096                 0.097 ns       0.016 ns
BM_format_string<char>/8192                 0.077 ns       0.012 ns
BM_format_string<char>/16384                0.066 ns       0.010 ns
BM_format_string<char>/32768                0.062 ns       0.016 ns
BM_format_string<char>/65536                0.062 ns       0.016 ns
BM_format_string<char>/131072               0.443 ns       0.015 ns
BM_format_string<char>/262144               0.629 ns       0.017 ns
BM_format_string<char>/524288               0.715 ns       0.020 ns
BM_format_string<char>/1048576              0.757 ns       0.020 ns
BM_format_string<wchar_t>/1                  38.8 ns        34.0 ns
BM_format_string<wchar_t>/2                  19.4 ns        16.9 ns
BM_format_string<wchar_t>/4                  9.88 ns        8.45 ns
BM_format_string<wchar_t>/8                  6.30 ns        6.47 ns
BM_format_string<wchar_t>/16                 3.11 ns        3.21 ns
BM_format_string<wchar_t>/32                 1.60 ns        1.63 ns
BM_format_string<wchar_t>/64                0.899 ns       0.925 ns
BM_format_string<wchar_t>/128               0.676 ns       0.693 ns
BM_format_string<wchar_t>/256               0.658 ns       0.685 ns
BM_format_string<wchar_t>/512               0.556 ns       0.531 ns
BM_format_string<wchar_t>/1024              0.428 ns       0.402 ns
BM_format_string<wchar_t>/2048              0.328 ns       0.319 ns
BM_format_string<wchar_t>/4096              0.276 ns       0.274 ns
BM_format_string<wchar_t>/8192              0.252 ns       0.251 ns
BM_format_string<wchar_t>/16384             0.248 ns       0.246 ns
BM_format_string<wchar_t>/32768             0.229 ns       0.232 ns
BM_format_string<wchar_t>/65536             0.248 ns       0.246 ns
BM_format_string<wchar_t>/131072            0.250 ns       0.240 ns
BM_format_string<wchar_t>/262144             3.03 ns        3.03 ns
BM_format_string<wchar_t>/524288             3.14 ns        3.15 ns
BM_format_string<wchar_t>/1048576            3.60 ns        3.61 ns
BM_string_without_formatting<char>           32.2 ns       0.470 ns
BM_string_without_formatting<wchar_t>        38.8 ns        10.2 ns
```



>From 44e0a1763bb020dae2cbc1dbd92a9479e8f8f15f Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Tue, 3 Sep 2024 19:39:17 +0200
Subject: [PATCH] [libc++] Add basic constant folding for std::format

---
 libcxx/include/__format/format_functions.h | 48 +++++++++++++++++++---
 libcxx/test/benchmarks/format.bench.cpp    |  9 ++++
 2 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 1518ab5768d243..dbb0b7bfcb12b4 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -11,6 +11,7 @@
 #define _LIBCPP___FORMAT_FORMAT_FUNCTIONS
 
 #include <__algorithm/clamp.h>
+#include <__algorithm/ranges_find_first_of.h>
 #include <__concepts/convertible_to.h>
 #include <__concepts/same_as.h>
 #include <__config>
@@ -448,13 +449,44 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
 }
 #  endif
 
+template <class _CharT>
+[[nodiscard]] optional<basic_string<_CharT>> __try_constant_folding(
+    basic_string_view<_CharT> __fmt,
+    basic_format_args<basic_format_context<back_insert_iterator<__format::__output_buffer<_CharT>>, _CharT>> __args) {
+  return nullopt;
+  if (bool __is_identity = std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end();
+      __builtin_constant_p(__is_identity) && __is_identity)
+    return basic_string<_CharT>{__fmt};
+
+  if (auto __only_first_arg = __fmt == _LIBCPP_STATICALLY_WIDEN(_CharT, "{}");
+      __builtin_constant_p(__only_first_arg) && __only_first_arg) {
+    if (auto __arg = __args.get(0); __builtin_constant_p(__arg.__type_)) {
+      return std::__visit_format_arg(
+          []<class _Tp>(_Tp&& __argument) -> optional<basic_string<_CharT>> {
+            if constexpr (is_same_v<remove_cvref_t<_Tp>, basic_string_view<_CharT>>) {
+              return basic_string<_CharT>{__argument};
+            } else {
+              return nullopt;
+            }
+          },
+          __arg);
+    }
+  }
+
+  return nullopt;
+}
+
 // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
 // fires too eagerly, see http://llvm.org/PR61563.
 template <class = void>
 [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) {
-  string __res;
-  std::vformat_to(std::back_inserter(__res), __fmt, __args);
-  return __res;
+  return std::__try_constant_folding(__fmt, __args)
+      .or_else([&]() -> optional<string> {
+        string __res;
+        std::vformat_to(std::back_inserter(__res), __fmt, __args);
+        return __res;
+      })
+      .value();
 }
 
 #  ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -463,9 +495,13 @@ template <class = void>
 template <class = void>
 [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
 vformat(wstring_view __fmt, wformat_args __args) {
-  wstring __res;
-  std::vformat_to(std::back_inserter(__res), __fmt, __args);
-  return __res;
+  return std::__try_constant_folding(__fmt, __args)
+      .or_else([&]() -> optional<wstring> {
+        wstring __res;
+        std::vformat_to(std::back_inserter(__res), __fmt, __args);
+        return __res;
+      })
+      .value();
 }
 #  endif
 
diff --git a/libcxx/test/benchmarks/format.bench.cpp b/libcxx/test/benchmarks/format.bench.cpp
index 17eaccb18ee1c4..5632aa5b9810f3 100644
--- a/libcxx/test/benchmarks/format.bench.cpp
+++ b/libcxx/test/benchmarks/format.bench.cpp
@@ -28,4 +28,13 @@ static void BM_format_string(benchmark::State& state) {
 BENCHMARK(BM_format_string<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
 BENCHMARK(BM_format_string<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
 
+template <class CharT>
+static void BM_string_without_formatting(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::format(CSTR("Hello, World!")));
+  }
+}
+BENCHMARK(BM_string_without_formatting<char>);
+BENCHMARK(BM_string_without_formatting<wchar_t>);
+
 BENCHMARK_MAIN();



More information about the libcxx-commits mailing list