[libcxx-commits] [libcxx] [libc++] Add basic constant folding for std::format (PR #107197)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jan 27 08:13:47 PST 2025
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/107197
>From 657a6cb4b55f682ad1d9a6dbc065e790c3e8f74d 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 | 36 +++++++++++++++++++
.../test/benchmarks/format/format.bench.cpp | 9 +++++
2 files changed, 45 insertions(+)
diff --git a/libcxx/include/__format/format_functions.h b/libcxx/include/__format/format_functions.h
index 5feaf7e5a064ad..281817a85aa9d7 100644
--- a/libcxx/include/__format/format_functions.h
+++ b/libcxx/include/__format/format_functions.h
@@ -11,6 +11,8 @@
#define _LIBCPP___FORMAT_FORMAT_FUNCTIONS
#include <__algorithm/clamp.h>
+#include <__algorithm/ranges_find_first_of.h>
+#include <__chrono/statically_widen.h>
#include <__concepts/convertible_to.h>
#include <__concepts/same_as.h>
#include <__config>
@@ -447,10 +449,41 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
}
# endif
+template <class _CharT>
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<basic_string<_CharT>> __try_constant_folding_format(
+ basic_string_view<_CharT> __fmt,
+ basic_format_args<basic_format_context<back_insert_iterator<__format::__output_buffer<_CharT>>, _CharT>> __args) {
+ // [[gnu::pure]] is added to ensure that the compiler always knows that this call can be eliminated.
+ if (bool __is_identity =
+ [&] [[__gnu__::__pure__]] { return 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) {
+ auto __result = std::__try_constant_folding_format(__fmt, __args);
+ if (__result.has_value())
+ return *__result;
__format::__allocating_buffer<char> __buffer;
std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
return string{__buffer.__view()};
@@ -462,6 +495,9 @@ template <class = void>
template <class = void>
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
vformat(wstring_view __fmt, wformat_args __args) {
+ auto __result = std::__try_constant_folding_format(__fmt, __args);
+ if (__result.has_value())
+ return *__result;
__format::__allocating_buffer<wchar_t> __buffer;
std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
return wstring{__buffer.__view()};
diff --git a/libcxx/test/benchmarks/format/format.bench.cpp b/libcxx/test/benchmarks/format/format.bench.cpp
index 267ef229506685..044cad6d09e40d 100644
--- a/libcxx/test/benchmarks/format/format.bench.cpp
+++ b/libcxx/test/benchmarks/format/format.bench.cpp
@@ -35,4 +35,13 @@ BENCHMARK(BM_format_string<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
BENCHMARK(BM_format_string<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
#endif
+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