[gcc r16-7970] libstdc+: Eliminate usage of alloca for non-localized formatting

Tomasz Kaminski tkaminsk@gcc.gnu.org
Tue Mar 10 07:34:58 GMT 2026


https://gcc.gnu.org/g:43e5eab8a4f5e95fb8539ef74de033ed9945623c

commit r16-7970-g43e5eab8a4f5e95fb8539ef74de033ed9945623c
Author: Tomasz Kamiński <tkaminsk@redhat.com>
Date:   Thu Mar 5 15:00:31 2026 +0100

    libstdc+: Eliminate usage of alloca for non-localized formatting
    
    This patch eliminate the use of __builtin_alloca for non-localized formatting
    of integers and pointers.
    
    For integers, the transcoding to _CharT moved from _M_format_int function
    to format. This makes the maximum size (that depends on sizeof(_Int)) of the
    buffer known (__buf_size) and allows use local array of _CharT (__wbuf) for
    the storage. The _M_format_int is modified to accept the string of _CharT.
    
    For pointers, r16-7844-gbfc2b87f8244a1 modified _Pres_p and _Pres_P to have
    same value as _Pres_x and _Pres_X, so format specifiers are subset of one
    allowed for integers. In consequence we simply delegate to format method
    of __formatter_int, reducing the code duplication. The set of allowed
    specifiers is still limited per C++ standard by __formatter_ptr::parse.
    
    This patch fix issue in __formatter_ptr::parse, where for 'p' and 'P' the value
    of _M_alt was negated for _M_spec (result of previous parse) instead of __spec
    (result of current parse), and adjust the __formatter_ptr default constructor
    to set _M_spec._M_type and _M_spec._M_alt appropriately.
    
    libstdc++-v3/ChangeLog:
    
            * include/std/format (__formatter_int::format): Handle transcoding
            to _CharT before calling _M_format_int.
            (__formatter_int::_M_format_int): Accept basic_string_view<_CharT>
            and remove transcoding.
            (__formatter_ptr::__formatter_ptr): Configure _M_spec member.
            (__formatter_ptr::parse): Negate _M_alt for __spec and not _M_spec.
            (__formatter_ptr::format): Delegate to __formatter_int.
    
    Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
    Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>

Diff:
---
 libstdc++-v3/include/std/format | 102 ++++++++++++----------------------------
 1 file changed, 29 insertions(+), 73 deletions(-)

diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index 786edbe29b20..cfb57f4a7a66 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -1647,7 +1647,8 @@ namespace __format
 	  if (_M_spec._M_type == _Pres_c)
 	    return _M_format_character(_S_to_character(__i), __fc);
 
-	  char __buf[sizeof(_Int) * __CHAR_BIT__ + 3];
+	  constexpr size_t __buf_size = sizeof(_Int) * __CHAR_BIT__ + 3;
+	  char __buf[__buf_size];
 	  to_chars_result __res{};
 
 	  string_view __base_prefix;
@@ -1707,8 +1708,21 @@ namespace __format
 	    }
 	  __start = __format::__put_sign(__i, _M_spec._M_sign, __start - 1);
 
-	  return _M_format_int(string_view(__start, __res.ptr - __start),
-			       __start_digits - __start, __fc);
+
+	  string_view __narrow_str(__start, __res.ptr - __start);
+	  size_t __prefix_len = __start_digits - __start;
+	  if constexpr (is_same_v<char, _CharT>)
+	    return _M_format_int(__narrow_str,  __prefix_len, __fc);
+#ifdef _GLIBCXX_USE_WCHAR_T
+	  else
+	    {
+	      _CharT __wbuf[__buf_size];
+	      size_t __n = __narrow_str.size();
+	      std::__to_wstring_numeric(__narrow_str.data(), __n, __wbuf);
+	      return _M_format_int(basic_string_view<_CharT>(__wbuf, __n),
+				   __prefix_len, __fc);
+	    }
+#endif
 	}
 
       template<typename _Out>
@@ -1795,24 +1809,10 @@ namespace __format
 
       template<typename _Out>
 	typename basic_format_context<_Out, _CharT>::iterator
-	_M_format_int(string_view __narrow_str, size_t __prefix_len,
+	_M_format_int(basic_string_view<_CharT> __str, size_t __prefix_len,
 		      basic_format_context<_Out, _CharT>& __fc) const
 	{
 	  size_t __width = _M_spec._M_get_width(__fc);
-
-	  basic_string_view<_CharT> __str;
-	  if constexpr (is_same_v<char, _CharT>)
-	    __str = __narrow_str;
-#ifdef _GLIBCXX_USE_WCHAR_T
-	  else
-	    {
-	      size_t __n = __narrow_str.size();
-	      auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
-	      std::__to_wstring_numeric(__narrow_str.data(), __n, __p);
-	      __str = {__p, __n};
-	    }
-#endif
-
 	  if (_M_spec._M_localized)
 	    {
 	      const auto& __l = __fc.locale();
@@ -2433,7 +2433,13 @@ namespace __format
   template<__format::__char _CharT>
     struct __formatter_ptr
     {
-      __formatter_ptr() = default;
+      constexpr
+      __formatter_ptr() noexcept
+      : _M_spec()
+      {
+	_M_spec._M_type = _Pres_p;
+	_M_spec._M_alt = true;
+      }
 
       constexpr
       __formatter_ptr(_Spec<_CharT> __spec) noexcept
@@ -2483,14 +2489,14 @@ namespace __format
 	if (*__first == 'p')
 	  {
 	    __spec._M_type = _Pres_p;
-	    _M_spec._M_alt = !_M_spec._M_alt;
+	    __spec._M_alt = !__spec._M_alt;
 	    ++__first;
 	  }
 #if __glibcxx_format >= 202304L
 	else if (*__first == 'P')
 	  {
 	    __spec._M_type = _Pres_P;
-	    _M_spec._M_alt = !_M_spec._M_alt;
+	    __spec._M_alt = !__spec._M_alt;
 	    ++__first;
 	  }
 #endif
@@ -2506,57 +2512,7 @@ namespace __format
 	format(const void* __v, basic_format_context<_Out, _CharT>& __fc) const
 	{
 	  auto __u = reinterpret_cast<__UINTPTR_TYPE__>(__v);
-	  char __buf[2 + sizeof(__v) * 2];
-	  auto [__ptr, __ec] = std::to_chars(__buf + 2, std::end(__buf),
-					     __u, 16);
-	  int __n = __ptr - __buf;
-	  __buf[0] = '0';
-	  __buf[1] = 'x';
-#if __glibcxx_format >= 202304L
-	  if (_M_spec._M_type == __format::_Pres_P)
-	    {
-	      __buf[1] = 'X';
-	      for (auto __p = __buf + 2; __p != __ptr; ++__p)
-#if __has_builtin(__builtin_toupper)
-		*__p = __builtin_toupper(*__p);
-#else
-		*__p = std::toupper(*__p);
-#endif
-	    }
-#endif
-
-	  basic_string_view<_CharT> __str;
-	  if constexpr (is_same_v<_CharT, char>)
-	    __str = string_view(__buf, __n);
-#ifdef _GLIBCXX_USE_WCHAR_T
-	  else
-	    {
-	      auto __p = (_CharT*)__builtin_alloca(__n * sizeof(_CharT));
-	      std::__to_wstring_numeric(__buf, __n, __p);
-	      __str = wstring_view(__p, __n);
-	    }
-#endif
-
-#if __glibcxx_format >= 202304L
-	  if (_M_spec._M_zero_fill)
-	    {
-	      size_t __width = _M_spec._M_get_width(__fc);
-	      if (__width <= __str.size())
-		return __format::__write(__fc.out(), __str);
-
-	      auto __out = __fc.out();
-	      // Write "0x" or "0X" prefix before zero-filling.
-	      __out = __format::__write(std::move(__out), __str.substr(0, 2));
-	      __str.remove_prefix(2);
-	      size_t __nfill = __width - __n;
-	      return __format::__write_padded(std::move(__out), __str,
-					      __format::_Align_right,
-					      __nfill, _CharT('0'));
-	    }
-#endif
-
-	  return __format::__write_padded_as_spec(__str, __n, __fc, _M_spec,
-						  __format::_Align_right);
+	  return __formatter_int<_CharT>(_M_spec).format(__u, __fc);
 	}
 
     private:
@@ -2571,7 +2527,7 @@ namespace __format
 	}
       }
 
-      __format::_Spec<_CharT> _M_spec{};
+      __format::_Spec<_CharT> _M_spec;
     };
 
 } // namespace __format


More information about the Libstdc++-cvs mailing list