[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