Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 49bced4

Browse filesBrowse files
authored
[libc++] Add basic constant folding for std::format (#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 ```
1 parent e7e4d99 commit 49bced4
Copy full SHA for 49bced4

File tree

2 files changed

+54
-0
lines changed
Filter options

2 files changed

+54
-0
lines changed

‎libcxx/include/__format/format_functions.h

Copy file name to clipboardExpand all lines: libcxx/include/__format/format_functions.h
+43
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
#define _LIBCPP___FORMAT_FORMAT_FUNCTIONS
1212

1313
#include <__algorithm/clamp.h>
14+
#include <__algorithm/ranges_find_first_of.h>
15+
#include <__chrono/statically_widen.h>
1416
#include <__concepts/convertible_to.h>
1517
#include <__concepts/same_as.h>
1618
#include <__config>
@@ -36,6 +38,7 @@
3638
#include <__iterator/iterator_traits.h> // iter_value_t
3739
#include <__variant/monostate.h>
3840
#include <array>
41+
#include <optional>
3942
#include <string>
4043
#include <string_view>
4144

@@ -447,10 +450,47 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
447450
}
448451
# endif
449452

453+
// Try constant folding the format string instead of going through the whole formatting machinery. If there is no
454+
// constant folding no extra code should be emitted (with optimizations enabled) and the function returns nullopt. When
455+
// constant folding is successful, the formatting is performed and the resulting string is returned.
456+
namespace __format {
457+
template <class _CharT>
458+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<basic_string<_CharT>> __try_constant_folding(
459+
basic_string_view<_CharT> __fmt,
460+
basic_format_args<basic_format_context<back_insert_iterator<__format::__output_buffer<_CharT>>, _CharT>> __args) {
461+
// Fold strings not containing '{' or '}' to just return the string
462+
if (bool __is_identity = [&] [[__gnu__::__pure__]] // Make sure the compiler knows this call can be eliminated
463+
{ return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }();
464+
__builtin_constant_p(__is_identity) && __is_identity)
465+
return basic_string<_CharT>{__fmt};
466+
467+
// Fold '{}' to the appropriate conversion function
468+
if (auto __only_first_arg = __fmt == _LIBCPP_STATICALLY_WIDEN(_CharT, "{}");
469+
__builtin_constant_p(__only_first_arg) && __only_first_arg) {
470+
if (auto __arg = __args.get(0); __builtin_constant_p(__arg.__type_)) {
471+
return std::__visit_format_arg(
472+
[]<class _Tp>(_Tp&& __argument) -> optional<basic_string<_CharT>> {
473+
if constexpr (is_same_v<remove_cvref_t<_Tp>, basic_string_view<_CharT>>) {
474+
return basic_string<_CharT>{__argument};
475+
} else {
476+
return nullopt;
477+
}
478+
},
479+
__arg);
480+
}
481+
}
482+
483+
return nullopt;
484+
}
485+
} // namespace __format
486+
450487
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
451488
// fires too eagerly, see http://llvm.org/PR61563.
452489
template <class = void>
453490
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) {
491+
auto __result = __format::__try_constant_folding(__fmt, __args);
492+
if (__result.has_value())
493+
return *std::move(__result);
454494
__format::__allocating_buffer<char> __buffer;
455495
std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
456496
return string{__buffer.__view()};
@@ -462,6 +502,9 @@ template <class = void>
462502
template <class = void>
463503
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
464504
vformat(wstring_view __fmt, wformat_args __args) {
505+
auto __result = __format::__try_constant_folding(__fmt, __args);
506+
if (__result.has_value())
507+
return *std::move(__result);
465508
__format::__allocating_buffer<wchar_t> __buffer;
466509
std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
467510
return wstring{__buffer.__view()};

‎libcxx/test/benchmarks/format/format.bench.cpp

Copy file name to clipboardExpand all lines: libcxx/test/benchmarks/format/format.bench.cpp
+11
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,15 @@ BENCHMARK(BM_format_string<char>)->RangeMultiplier(2)->Range(1, 1 << 20);
3535
BENCHMARK(BM_format_string<wchar_t>)->RangeMultiplier(2)->Range(1, 1 << 20);
3636
#endif
3737

38+
template <class CharT>
39+
static void BM_string_without_formatting(benchmark::State& state) {
40+
for (auto _ : state) {
41+
benchmark::DoNotOptimize(std::format(CSTR("Hello, World!")));
42+
}
43+
}
44+
BENCHMARK(BM_string_without_formatting<char>);
45+
#ifndef TEST_HAS_NO_WIDE_CHARACTERS
46+
BENCHMARK(BM_string_without_formatting<wchar_t>);
47+
#endif
48+
3849
BENCHMARK_MAIN();

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.