Skip to content

Navigation Menu

Sign in
Appearance settings

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 d531697

Browse filesBrowse files
committed
[libc++] Add basic constant folding for std::format
1 parent 9e44f0d commit d531697
Copy full SHA for d531697

File tree

Expand file treeCollapse file tree

2 files changed

+51
-0
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+51
-0
lines changed

‎libcxx/include/__format/format_functions.h

Copy file name to clipboardExpand all lines: libcxx/include/__format/format_functions.h
+42Lines changed: 42 additions & 0 deletions
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>
@@ -447,10 +449,47 @@ format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) {
447449
}
448450
# endif
449451

452+
// Try constant folding the format string instead of going through the whole formatting machinery. If there is no
453+
// constant folding no extra code should be emitted (with optimizations enabled) and the function returns nullopt. When
454+
// constant folding is successful, the formatting is performed and the resulting string is returned.
455+
namespace __format {
456+
template <class _CharT>
457+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<basic_string<_CharT>> __try_constant_folding(
458+
basic_string_view<_CharT> __fmt,
459+
basic_format_args<basic_format_context<back_insert_iterator<__format::__output_buffer<_CharT>>, _CharT>> __args) {
460+
// Fold strings not containing '{' or '}' to just return the string
461+
if (bool __is_identity = [&] [[__gnu__::__pure__]] // Make sure the compiler knows this call can be eliminated
462+
{ return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }();
463+
__builtin_constant_p(__is_identity) && __is_identity)
464+
return basic_string<_CharT>{__fmt};
465+
466+
// Fold '{}' to the appropriate conversion function
467+
if (auto __only_first_arg = __fmt == _LIBCPP_STATICALLY_WIDEN(_CharT, "{}");
468+
__builtin_constant_p(__only_first_arg) && __only_first_arg) {
469+
if (auto __arg = __args.get(0); __builtin_constant_p(__arg.__type_)) {
470+
return std::__visit_format_arg(
471+
[]<class _Tp>(_Tp&& __argument) -> optional<basic_string<_CharT>> {
472+
if constexpr (is_same_v<remove_cvref_t<_Tp>, basic_string_view<_CharT>>) {
473+
return basic_string<_CharT>{__argument};
474+
} else {
475+
return nullopt;
476+
}
477+
},
478+
__arg);
479+
}
480+
}
481+
482+
return nullopt;
483+
}
484+
} // namespace __format
485+
450486
// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup
451487
// fires too eagerly, see http://llvm.org/PR61563.
452488
template <class = void>
453489
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) {
490+
auto __result = __format::__try_constant_folding(__fmt, __args);
491+
if (__result.has_value())
492+
return *std::move(__result);
454493
__format::__allocating_buffer<char> __buffer;
455494
std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
456495
return string{__buffer.__view()};
@@ -462,6 +501,9 @@ template <class = void>
462501
template <class = void>
463502
[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring
464503
vformat(wstring_view __fmt, wformat_args __args) {
504+
auto __result = __format::__try_constant_folding(__fmt, __args);
505+
if (__result.has_value())
506+
return *std::move(__result);
465507
__format::__allocating_buffer<wchar_t> __buffer;
466508
std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args);
467509
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
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,13 @@ 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+
BENCHMARK(BM_string_without_formatting<wchar_t>);
46+
3847
BENCHMARK_MAIN();

0 commit comments

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