public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
@ 2022-11-02  9:25 Jakub Jelinek
  2022-11-07 13:45 ` Jonathan Wakely
  2022-11-07 16:11 ` Joseph Myers
  0 siblings, 2 replies; 9+ messages in thread
From: Jakub Jelinek @ 2022-11-02  9:25 UTC (permalink / raw)
  To: Jonathan Wakely, Patrick Palka; +Cc: gcc-patches, libstdc++

Hi!

The following patch adds std::{to,from}_chars support for std::float128_t
on glibc 2.26+ for {i?86,x86_64,ia64,powerpc64le}-linux.
When long double is already IEEE quad, previous changes already handle
it by using long double overloads in _Float128 overloads.
The powerpc64le case (with explicit or implicit -mabi=ibmlongdouble)
is handled by using the __float128/__ieee128 entrypoints which are
already in the library and used for -mabi=ieeelongdouble.
For i?86, x86_64 and ia64 this patch adds new library entrypoints,
mostly by enabling the code that was already there for powerpc64le-linux.
Those use __float128 or __ieee128, the patch uses _Float128 for the
exported overloads and internally as template parameter.  While
powerpc64le-linux uses __sprintfieee128 and __strtoieee128,
for _Float128 the patch uses the glibc 2.26 strfromf128 and strtof128
APIs.  So that one can build gcc against older glibc and then compile
user programs on newer glibc, the patch uses weak references unless
gcc is compiled against glibc 2.26+.  strfromf128 unfortunately can't
handle %.0Lf and %.*Le, %.*Lf, %.*Lg format strings sprintf/__sprintfieee128
use, we need to remove the L from those and replace * with actually
directly printing the precision into the format string (i.e. it can
handle %.0f and %.27f (floating point type is implied from the function
name)).
Unlike the std::{,b}float16_t support, this one actually exports APIs
with std::float128_t aka _Float128 in the mangled name, because no
standard format is superset of it.  On the other side, e.g. on i?86/x86_64
it doesn't have restrictions like for _Float16/__bf16 which ISAs need
to be enabled in order to use it.

The denorm_min case in the testcase is temporarily commented out because
of the ERANGE subnormal issue Patrick posted patch for.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2022-11-02  Jakub Jelinek  <jakub@redhat.com>

	* include/std/charconv (from_chars, to_chars): Add _Float128
	overfloads if _GLIBCXX_HAVE_FLOAT128_MATH is defined.
	* config/abi/pre/gnu.ver (GLIBCXX_3.4.31): Export
	_ZSt8to_charsPcS_DF128_, _ZSt8to_charsPcS_DF128_St12chars_format,
	_ZSt8to_charsPcS_DF128_St12chars_formati and
	_ZSt10from_charsPKcS0_RDF128_St12chars_format.
	* src/c++17/floating_from_chars.cc (USE_STRTOF128_FOR_FROM_CHARS):
	Define if needed.
	(__strtof128): Declare.
	(from_chars_impl): Handle _Float128.
	(from_chars): New _Float128 overload if USE_STRTOF128_FOR_FROM_CHARS
	is define.
	* src/c++17/floating_to_chars.cc (__strfromf128): Declare.
	(FLOAT128_TO_CHARS): Define even when _Float128 is supported and
	wider than long double.
	(F128_type): Use _Float128 for that case.
	(floating_type_traits): Specialize for F128_type rather than
	__float128.
	(sprintf_ld): Add length argument.  Handle _Float128.
	(__floating_to_chars_shortest, __floating_to_chars_precision):
	Pass length to sprintf_ld.
	(to_chars): Add _Float128 overloads for the F128_type being
	_Float128 cases.
	* testsuite/20_util/to_chars/float128_c++23.cc: New test.

--- libstdc++-v3/include/std/charconv.jj	2022-10-31 22:20:39.475072806 +0100
+++ libstdc++-v3/include/std/charconv	2022-11-01 16:48:50.693196228 +0100
@@ -736,6 +736,27 @@ namespace __detail
       __value = __val;
     return __res;
   }
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
+  __extension__ from_chars_result
+  from_chars(const char* __first, const char* __last, __ieee128& __value,
+	     chars_format __fmt = chars_format::general) noexcept;
+
+  inline from_chars_result
+  from_chars(const char* __first, const char* __last, _Float128& __value,
+	     chars_format __fmt = chars_format::general) noexcept
+  {
+    __extension__ __ieee128 __val;
+    from_chars_result __res = from_chars(__first, __last, __val, __fmt);
+    if (__res.ec == errc{})
+      __value = __val;
+    return __res;
+  }
+#else
+  from_chars_result
+  from_chars(const char* __first, const char* __last, _Float128& __value,
+	     chars_format __fmt = chars_format::general) noexcept;
+#endif
 #endif
 
 #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) \
@@ -851,6 +872,46 @@ namespace __detail
     return to_chars(__first, __last, static_cast<long double>(__value), __fmt,
 		    __precision);
   }
+#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
+  __extension__ to_chars_result
+  to_chars(char* __first, char* __last, __float128 __value) noexcept;
+  __extension__ to_chars_result
+  to_chars(char* __first, char* __last, __float128 __value,
+	   chars_format __fmt) noexcept;
+  __extension__ to_chars_result
+  to_chars(char* __first, char* __last, __float128 __value,
+	   chars_format __fmt, int __precision) noexcept;
+
+  inline to_chars_result
+  to_chars(char* __first, char* __last, _Float128 __value) noexcept
+  {
+    __extension__
+    return to_chars(__first, __last, static_cast<__float128>(__value));
+  }
+  inline to_chars_result
+  to_chars(char* __first, char* __last, _Float128 __value,
+	   chars_format __fmt) noexcept
+  {
+    __extension__
+    return to_chars(__first, __last, static_cast<__float128>(__value), __fmt);
+  }
+  inline to_chars_result
+  to_chars(char* __first, char* __last, _Float128 __value,
+	   chars_format __fmt, int __precision) noexcept
+  {
+    __extension__
+    return to_chars(__first, __last, static_cast<__float128>(__value), __fmt,
+		    __precision);
+  }
+#else
+  to_chars_result to_chars(char* __first, char* __last, _Float128 __value)
+    noexcept;
+  to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
+			   chars_format __fmt) noexcept;
+  to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
+			   chars_format __fmt, int __precision) noexcept;
+#endif
 #endif
 
 #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
--- libstdc++-v3/config/abi/pre/gnu.ver.jj	2022-10-31 22:20:39.475072806 +0100
+++ libstdc++-v3/config/abi/pre/gnu.ver	2022-11-01 17:00:57.682346445 +0100
@@ -2450,6 +2450,10 @@ GLIBCXX_3.4.31 {
     _ZSt21__to_chars_bfloat16_tPcS_fSt12chars_format;
     _ZSt22__from_chars_float16_tPKcS0_RfSt12chars_format;
     _ZSt23__from_chars_bfloat16_tPKcS0_RfSt12chars_format;
+    _ZSt8to_charsPcS_DF128_;
+    _ZSt8to_charsPcS_DF128_St12chars_format;
+    _ZSt8to_charsPcS_DF128_St12chars_formati;
+    _ZSt10from_charsPKcS0_RDF128_St12chars_format;
 } GLIBCXX_3.4.30;
 
 # Symbols in the support library (libsupc++) have their own tag.
--- libstdc++-v3/src/c++17/floating_from_chars.cc.jj	2022-10-31 22:20:39.476072793 +0100
+++ libstdc++-v3/src/c++17/floating_from_chars.cc	2022-11-01 16:59:23.999615740 +0100
@@ -59,6 +59,14 @@
 #endif
 // strtold for __ieee128
 extern "C" __ieee128 __strtoieee128(const char*, char**);
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+      && defined(__GLIBC_PREREQ)
+#define USE_STRTOF128_FOR_FROM_CHARS 1
+extern "C" _Float128 __strtof128(const char*, char**)
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+  __attribute__((__weak__))
+#endif
+  __asm ("strtof128");
 #endif
 
 #if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
@@ -618,6 +626,16 @@ namespace
 # ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
 	else if constexpr (is_same_v<T, __ieee128>)
 	  tmpval = __strtoieee128(str, &endptr);
+# elif defined(USE_STRTOF128_FOR_FROM_CHARS)
+	else if constexpr (is_same_v<T, _Float128>)
+	  {
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+	    if (&__strtof128 == nullptr)
+	      tmpval = _Float128(std::strtold(str, &endptr);
+	    else
+#endif
+	      tmpval = __strtof128(str, &endptr);
+	  }
 # endif
 #else
 	tmpval = std::strtod(str, &endptr);
@@ -1232,6 +1250,14 @@ from_chars(const char* first, const char
 	   chars_format fmt) noexcept
 {
   // fast_float doesn't support IEEE binary128 format, but we can use strtold.
+  return from_chars_strtod(first, last, value, fmt);
+}
+#elif defined(USE_STRTOF128_FOR_FROM_CHARS)
+from_chars_result
+from_chars(const char* first, const char* last, _Float128& value,
+	   chars_format fmt) noexcept
+{
+  // fast_float doesn't support IEEE binary128 format, but we can use strtold.
   return from_chars_strtod(first, last, value, fmt);
 }
 #endif
--- libstdc++-v3/src/c++17/floating_to_chars.cc.jj	2022-11-01 12:16:14.352652455 +0100
+++ libstdc++-v3/src/c++17/floating_to_chars.cc	2022-11-01 16:25:48.330968909 +0100
@@ -43,6 +43,13 @@
 #endif
 // sprintf for __ieee128
 extern "C" int __sprintfieee128(char*, const char*, ...);
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+      && defined(__GLIBC_PREREQ)
+extern "C" int __strfromf128(char*, size_t, const char*, _Float128)
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+  __attribute__((__weak__))
+#endif
+  __asm ("strfromf128");
 #endif
 
 // This implementation crucially assumes float/double have the
@@ -77,10 +84,11 @@ extern "C" int __sprintfieee128(char*, c
 #if defined _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT && __FLT128_MANT_DIG__ == 113
 // Define overloads of std::to_chars for __float128.
 # define FLOAT128_TO_CHARS 1
-#endif
-
-#ifdef FLOAT128_TO_CHARS
 using F128_type = __float128;
+#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
+      && defined(__GLIBC_PREREQ)
+# define FLOAT128_TO_CHARS 1
+using F128_type = _Float128;
 #else
 using F128_type = void;
 #endif
@@ -252,7 +260,7 @@ namespace
 
 # ifdef FLOAT128_TO_CHARS
   template<>
-    struct floating_type_traits<__float128> : floating_type_traits_binary128
+    struct floating_type_traits<F128_type> : floating_type_traits_binary128
     { };
 # endif
 #endif
@@ -1035,7 +1043,8 @@ namespace
 #pragma GCC diagnostic ignored "-Wabi"
   template<typename T, typename... Extra>
   inline int
-  sprintf_ld(char* buffer, const char* format_string, T value, Extra... args)
+  sprintf_ld(char* buffer, size_t length __attribute__((unused)),
+	     const char* format_string, T value, Extra... args)
   {
     int len;
 
@@ -1045,10 +1054,31 @@ namespace
       fesetround(FE_TONEAREST); // We want round-to-nearest behavior.
 #endif
 
+#ifdef FLOAT128_TO_CHARS
 #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
     if constexpr (is_same_v<T, __ieee128>)
       len = __sprintfieee128(buffer, format_string, args..., value);
     else
+#else
+    if constexpr (is_same_v<T, _Float128>)
+      {
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+	if (&__strfromf128 == nullptr)
+	  len = sprintf(buffer, format_string, args..., (long double)value);
+	else
+#endif
+	if constexpr (sizeof...(args) == 0)
+	  len = __strfromf128(buffer, length, "%.0f", value);
+	else
+	  {
+	    // strfromf128 unfortunately doesn't allow .*
+	    char fmt[3 * sizeof(int) + 6];
+	    sprintf(fmt, "%%.%d%c", args..., int(format_string[4]));
+	    len = __strfromf128(buffer, length, fmt, value);
+	  }
+      }
+    else
+#endif
 #endif
     len = sprintf(buffer, format_string, args..., value);
 
@@ -1206,8 +1236,10 @@ template<typename T>
 	    // can avoid this if we use sprintf to write all but the last
 	    // digit, and carefully compute and write the last digit
 	    // ourselves.
-	    char buffer[expected_output_length+1];
-	    const int output_length = sprintf_ld(buffer, "%.0Lf", value);
+	    char buffer[expected_output_length + 1];
+	    const int output_length = sprintf_ld(buffer,
+						 expected_output_length + 1,
+						 "%.0Lf", value);
 	    __glibcxx_assert(output_length == expected_output_length);
 	    memcpy(first, buffer, output_length);
 	    return {first + output_length, errc{}};
@@ -1397,9 +1429,10 @@ template<typename T>
 	  __builtin_unreachable();
 
 	// Do the sprintf into the local buffer.
-	char buffer[output_length_upper_bound+1];
+	char buffer[output_length_upper_bound + 1];
 	int output_length
-	  = sprintf_ld(buffer, output_specifier, value, effective_precision);
+	  = sprintf_ld(buffer, output_length_upper_bound + 1, output_specifier,
+		       value, effective_precision);
 	__glibcxx_assert(output_length <= output_length_upper_bound);
 
 	if (effective_precision > 0)
@@ -1799,6 +1832,7 @@ to_chars(char* first, char* last, long d
 }
 
 #ifdef FLOAT128_TO_CHARS
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
 to_chars_result
 to_chars(char* first, char* last, __float128 value) noexcept
 {
@@ -1817,6 +1851,26 @@ to_chars(char* first, char* last, __floa
 {
   return __floating_to_chars_precision(first, last, value, fmt, precision);
 }
+#else
+to_chars_result
+to_chars(char* first, char* last, _Float128 value) noexcept
+{
+  return __floating_to_chars_shortest(first, last, value, chars_format{});
+}
+
+to_chars_result
+to_chars(char* first, char* last, _Float128 value, chars_format fmt) noexcept
+{
+  return __floating_to_chars_shortest(first, last, value, fmt);
+}
+
+to_chars_result
+to_chars(char* first, char* last, _Float128 value, chars_format fmt,
+	 int precision) noexcept
+{
+  return __floating_to_chars_precision(first, last, value, fmt, precision);
+}
+#endif
 #endif
 
 // Entrypoints for 16-bit floats.
--- libstdc++-v3/testsuite/20_util/to_chars/float128_c++23.cc.jj	2022-11-01 17:04:19.895606130 +0100
+++ libstdc++-v3/testsuite/20_util/to_chars/float128_c++23.cc	2022-11-01 20:47:15.254989646 +0100
@@ -0,0 +1,105 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2b" }
+// { dg-do run { target c++23 } }
+// { dg-require-effective-target ieee_floats }
+// { dg-require-effective-target size32plus }
+// { dg-add-options ieee }
+
+#include <charconv>
+#include <stdfloat>
+#include <limits>
+#include <numbers>
+#include <testsuite_hooks.h>
+
+#if defined(__STDCPP_FLOAT128_T__) \
+    && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
+	|| defined(_GLIBCXX_HAVE_FLOAT128_MATH))
+void
+test(std::chars_format fmt = std::chars_format{})
+{
+  std::float128_t tests[] = {
+//    std::numeric_limits<std::float128_t>::denorm_min(),
+    std::numeric_limits<std::float128_t>::min(),
+    0.0f128,
+    -42.0f128,
+    1234.5678912345f128,
+    std::numbers::e_v<std::float128_t>,
+    std::numbers::log2e_v<std::float128_t>,
+    std::numbers::log10e_v<std::float128_t>,
+    std::numbers::pi_v<std::float128_t>,
+    std::numbers::inv_pi_v<std::float128_t>,
+    std::numbers::inv_sqrtpi_v<std::float128_t>,
+    std::numbers::ln2_v<std::float128_t>,
+    std::numbers::ln10_v<std::float128_t>,
+    std::numbers::sqrt2_v<std::float128_t>,
+    std::numbers::sqrt3_v<std::float128_t>,
+    std::numbers::inv_sqrt3_v<std::float128_t>,
+    std::numbers::egamma_v<std::float128_t>,
+    std::numbers::phi_v<std::float128_t>,
+    std::numeric_limits<std::float128_t>::max()
+  };
+  char str1[10000], str2[10000];
+  for (auto u : tests)
+    {
+      auto [ptr1, ec1] = std::to_chars(str1, str1 + sizeof(str1), u, fmt);
+      VERIFY( ec1 == std::errc() );
+//    std::cout << i << ' ' << std::string_view (str1, ptr1) << '\n';
+      if (fmt == std::chars_format::fixed)
+	{
+	  auto [ptr2, ec2] = std::to_chars(str2, str2 + (ptr1 - str1), u, fmt);
+	  VERIFY( ec2 == std::errc() && ptr2 - str2 == ptr1 - str1 );
+	  auto [ptr3, ec3] = std::to_chars(str2, str2 + (ptr1 - str1 - 1), u, fmt);
+	  VERIFY( ec3 != std::errc() );
+	}
+      std::float128_t v;
+      auto [ptr4, ec4] = std::from_chars(str1, ptr1, v,
+					 fmt == std::chars_format{}
+					 ? std::chars_format::general : fmt);
+      VERIFY( ec4 == std::errc() && ptr4 == ptr1 );
+      VERIFY( u == v );
+
+      auto [ptr5, ec5] = std::to_chars(str1, str1 + sizeof(str1), u, fmt, 90);
+      VERIFY( ec5 == std::errc() );
+//    std::cout << i << ' ' << std::string_view (str1, ptr5) << '\n';
+      v = 4.0f128;
+      auto [ptr6, ec6] = std::from_chars(str1, ptr5, v,
+					 fmt == std::chars_format{}
+					 ? std::chars_format::general : fmt);
+      VERIFY( ec6 == std::errc() && ptr6 == ptr5 );
+      if (fmt == std::chars_format::fixed && u > 0.0f128 && u < 0.000001f128)
+	VERIFY( v == 0.0 );
+      else
+	VERIFY( u == v );
+    }
+}
+#endif
+
+int
+main()
+{
+#if defined(__STDCPP_FLOAT128_T__) \
+    && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
+	|| defined(_GLIBCXX_HAVE_FLOAT128_MATH))
+  test();
+  test(std::chars_format::fixed);
+  test(std::chars_format::scientific);
+  test(std::chars_format::general);
+  test(std::chars_format::hex);
+#endif
+}

	Jakub


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-02  9:25 [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc Jakub Jelinek
@ 2022-11-07 13:45 ` Jonathan Wakely
  2022-11-07 16:11 ` Joseph Myers
  1 sibling, 0 replies; 9+ messages in thread
From: Jonathan Wakely @ 2022-11-07 13:45 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Patrick Palka, gcc-patches, libstdc++

On Wed, 2 Nov 2022 at 09:26, Jakub Jelinek <jakub@redhat.com> wrote:
>
> Hi!
>
> The following patch adds std::{to,from}_chars support for std::float128_t
> on glibc 2.26+ for {i?86,x86_64,ia64,powerpc64le}-linux.
> When long double is already IEEE quad, previous changes already handle
> it by using long double overloads in _Float128 overloads.
> The powerpc64le case (with explicit or implicit -mabi=ibmlongdouble)
> is handled by using the __float128/__ieee128 entrypoints which are
> already in the library and used for -mabi=ieeelongdouble.
> For i?86, x86_64 and ia64 this patch adds new library entrypoints,
> mostly by enabling the code that was already there for powerpc64le-linux.
> Those use __float128 or __ieee128, the patch uses _Float128 for the
> exported overloads and internally as template parameter.  While
> powerpc64le-linux uses __sprintfieee128 and __strtoieee128,
> for _Float128 the patch uses the glibc 2.26 strfromf128 and strtof128
> APIs.  So that one can build gcc against older glibc and then compile
> user programs on newer glibc, the patch uses weak references unless
> gcc is compiled against glibc 2.26+.  strfromf128 unfortunately can't
> handle %.0Lf and %.*Le, %.*Lf, %.*Lg format strings sprintf/__sprintfieee128
> use, we need to remove the L from those and replace * with actually
> directly printing the precision into the format string (i.e. it can
> handle %.0f and %.27f (floating point type is implied from the function
> name)).

Wow, nice work juggling all the pieces here.

> Unlike the std::{,b}float16_t support, this one actually exports APIs
> with std::float128_t aka _Float128 in the mangled name, because no
> standard format is superset of it.  On the other side, e.g. on i?86/x86_64
> it doesn't have restrictions like for _Float16/__bf16 which ISAs need
> to be enabled in order to use it.
>
> The denorm_min case in the testcase is temporarily commented out because
> of the ERANGE subnormal issue Patrick posted patch for.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK, thanks!


>
> 2022-11-02  Jakub Jelinek  <jakub@redhat.com>
>
>         * include/std/charconv (from_chars, to_chars): Add _Float128
>         overfloads if _GLIBCXX_HAVE_FLOAT128_MATH is defined.
>         * config/abi/pre/gnu.ver (GLIBCXX_3.4.31): Export
>         _ZSt8to_charsPcS_DF128_, _ZSt8to_charsPcS_DF128_St12chars_format,
>         _ZSt8to_charsPcS_DF128_St12chars_formati and
>         _ZSt10from_charsPKcS0_RDF128_St12chars_format.
>         * src/c++17/floating_from_chars.cc (USE_STRTOF128_FOR_FROM_CHARS):
>         Define if needed.
>         (__strtof128): Declare.
>         (from_chars_impl): Handle _Float128.
>         (from_chars): New _Float128 overload if USE_STRTOF128_FOR_FROM_CHARS
>         is define.
>         * src/c++17/floating_to_chars.cc (__strfromf128): Declare.
>         (FLOAT128_TO_CHARS): Define even when _Float128 is supported and
>         wider than long double.
>         (F128_type): Use _Float128 for that case.
>         (floating_type_traits): Specialize for F128_type rather than
>         __float128.
>         (sprintf_ld): Add length argument.  Handle _Float128.
>         (__floating_to_chars_shortest, __floating_to_chars_precision):
>         Pass length to sprintf_ld.
>         (to_chars): Add _Float128 overloads for the F128_type being
>         _Float128 cases.
>         * testsuite/20_util/to_chars/float128_c++23.cc: New test.
>
> --- libstdc++-v3/include/std/charconv.jj        2022-10-31 22:20:39.475072806 +0100
> +++ libstdc++-v3/include/std/charconv   2022-11-01 16:48:50.693196228 +0100
> @@ -736,6 +736,27 @@ namespace __detail
>        __value = __val;
>      return __res;
>    }
> +#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
> +#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
> +  __extension__ from_chars_result
> +  from_chars(const char* __first, const char* __last, __ieee128& __value,
> +            chars_format __fmt = chars_format::general) noexcept;
> +
> +  inline from_chars_result
> +  from_chars(const char* __first, const char* __last, _Float128& __value,
> +            chars_format __fmt = chars_format::general) noexcept
> +  {
> +    __extension__ __ieee128 __val;
> +    from_chars_result __res = from_chars(__first, __last, __val, __fmt);
> +    if (__res.ec == errc{})
> +      __value = __val;
> +    return __res;
> +  }
> +#else
> +  from_chars_result
> +  from_chars(const char* __first, const char* __last, _Float128& __value,
> +            chars_format __fmt = chars_format::general) noexcept;
> +#endif
>  #endif
>
>  #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32) \
> @@ -851,6 +872,46 @@ namespace __detail
>      return to_chars(__first, __last, static_cast<long double>(__value), __fmt,
>                     __precision);
>    }
> +#elif defined(__STDCPP_FLOAT128_T__) && defined(_GLIBCXX_HAVE_FLOAT128_MATH)
> +#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
> +  __extension__ to_chars_result
> +  to_chars(char* __first, char* __last, __float128 __value) noexcept;
> +  __extension__ to_chars_result
> +  to_chars(char* __first, char* __last, __float128 __value,
> +          chars_format __fmt) noexcept;
> +  __extension__ to_chars_result
> +  to_chars(char* __first, char* __last, __float128 __value,
> +          chars_format __fmt, int __precision) noexcept;
> +
> +  inline to_chars_result
> +  to_chars(char* __first, char* __last, _Float128 __value) noexcept
> +  {
> +    __extension__
> +    return to_chars(__first, __last, static_cast<__float128>(__value));
> +  }
> +  inline to_chars_result
> +  to_chars(char* __first, char* __last, _Float128 __value,
> +          chars_format __fmt) noexcept
> +  {
> +    __extension__
> +    return to_chars(__first, __last, static_cast<__float128>(__value), __fmt);
> +  }
> +  inline to_chars_result
> +  to_chars(char* __first, char* __last, _Float128 __value,
> +          chars_format __fmt, int __precision) noexcept
> +  {
> +    __extension__
> +    return to_chars(__first, __last, static_cast<__float128>(__value), __fmt,
> +                   __precision);
> +  }
> +#else
> +  to_chars_result to_chars(char* __first, char* __last, _Float128 __value)
> +    noexcept;
> +  to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
> +                          chars_format __fmt) noexcept;
> +  to_chars_result to_chars(char* __first, char* __last, _Float128 __value,
> +                          chars_format __fmt, int __precision) noexcept;
> +#endif
>  #endif
>
>  #if defined(__STDCPP_BFLOAT16_T__) && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
> --- libstdc++-v3/config/abi/pre/gnu.ver.jj      2022-10-31 22:20:39.475072806 +0100
> +++ libstdc++-v3/config/abi/pre/gnu.ver 2022-11-01 17:00:57.682346445 +0100
> @@ -2450,6 +2450,10 @@ GLIBCXX_3.4.31 {
>      _ZSt21__to_chars_bfloat16_tPcS_fSt12chars_format;
>      _ZSt22__from_chars_float16_tPKcS0_RfSt12chars_format;
>      _ZSt23__from_chars_bfloat16_tPKcS0_RfSt12chars_format;
> +    _ZSt8to_charsPcS_DF128_;
> +    _ZSt8to_charsPcS_DF128_St12chars_format;
> +    _ZSt8to_charsPcS_DF128_St12chars_formati;
> +    _ZSt10from_charsPKcS0_RDF128_St12chars_format;
>  } GLIBCXX_3.4.30;
>
>  # Symbols in the support library (libsupc++) have their own tag.
> --- libstdc++-v3/src/c++17/floating_from_chars.cc.jj    2022-10-31 22:20:39.476072793 +0100
> +++ libstdc++-v3/src/c++17/floating_from_chars.cc       2022-11-01 16:59:23.999615740 +0100
> @@ -59,6 +59,14 @@
>  #endif
>  // strtold for __ieee128
>  extern "C" __ieee128 __strtoieee128(const char*, char**);
> +#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
> +      && defined(__GLIBC_PREREQ)
> +#define USE_STRTOF128_FOR_FROM_CHARS 1
> +extern "C" _Float128 __strtof128(const char*, char**)
> +#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
> +  __attribute__((__weak__))
> +#endif
> +  __asm ("strtof128");
>  #endif
>
>  #if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
> @@ -618,6 +626,16 @@ namespace
>  # ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
>         else if constexpr (is_same_v<T, __ieee128>)
>           tmpval = __strtoieee128(str, &endptr);
> +# elif defined(USE_STRTOF128_FOR_FROM_CHARS)
> +       else if constexpr (is_same_v<T, _Float128>)
> +         {
> +#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
> +           if (&__strtof128 == nullptr)
> +             tmpval = _Float128(std::strtold(str, &endptr);
> +           else
> +#endif
> +             tmpval = __strtof128(str, &endptr);
> +         }
>  # endif
>  #else
>         tmpval = std::strtod(str, &endptr);
> @@ -1232,6 +1250,14 @@ from_chars(const char* first, const char
>            chars_format fmt) noexcept
>  {
>    // fast_float doesn't support IEEE binary128 format, but we can use strtold.
> +  return from_chars_strtod(first, last, value, fmt);
> +}
> +#elif defined(USE_STRTOF128_FOR_FROM_CHARS)
> +from_chars_result
> +from_chars(const char* first, const char* last, _Float128& value,
> +          chars_format fmt) noexcept
> +{
> +  // fast_float doesn't support IEEE binary128 format, but we can use strtold.
>    return from_chars_strtod(first, last, value, fmt);
>  }
>  #endif
> --- libstdc++-v3/src/c++17/floating_to_chars.cc.jj      2022-11-01 12:16:14.352652455 +0100
> +++ libstdc++-v3/src/c++17/floating_to_chars.cc 2022-11-01 16:25:48.330968909 +0100
> @@ -43,6 +43,13 @@
>  #endif
>  // sprintf for __ieee128
>  extern "C" int __sprintfieee128(char*, const char*, ...);
> +#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
> +      && defined(__GLIBC_PREREQ)
> +extern "C" int __strfromf128(char*, size_t, const char*, _Float128)
> +#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
> +  __attribute__((__weak__))
> +#endif
> +  __asm ("strfromf128");
>  #endif
>
>  // This implementation crucially assumes float/double have the
> @@ -77,10 +84,11 @@ extern "C" int __sprintfieee128(char*, c
>  #if defined _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT && __FLT128_MANT_DIG__ == 113
>  // Define overloads of std::to_chars for __float128.
>  # define FLOAT128_TO_CHARS 1
> -#endif
> -
> -#ifdef FLOAT128_TO_CHARS
>  using F128_type = __float128;
> +#elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
> +      && defined(__GLIBC_PREREQ)
> +# define FLOAT128_TO_CHARS 1
> +using F128_type = _Float128;
>  #else
>  using F128_type = void;
>  #endif
> @@ -252,7 +260,7 @@ namespace
>
>  # ifdef FLOAT128_TO_CHARS
>    template<>
> -    struct floating_type_traits<__float128> : floating_type_traits_binary128
> +    struct floating_type_traits<F128_type> : floating_type_traits_binary128
>      { };
>  # endif
>  #endif
> @@ -1035,7 +1043,8 @@ namespace
>  #pragma GCC diagnostic ignored "-Wabi"
>    template<typename T, typename... Extra>
>    inline int
> -  sprintf_ld(char* buffer, const char* format_string, T value, Extra... args)
> +  sprintf_ld(char* buffer, size_t length __attribute__((unused)),
> +            const char* format_string, T value, Extra... args)
>    {
>      int len;
>
> @@ -1045,10 +1054,31 @@ namespace
>        fesetround(FE_TONEAREST); // We want round-to-nearest behavior.
>  #endif
>
> +#ifdef FLOAT128_TO_CHARS
>  #ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
>      if constexpr (is_same_v<T, __ieee128>)
>        len = __sprintfieee128(buffer, format_string, args..., value);
>      else
> +#else
> +    if constexpr (is_same_v<T, _Float128>)
> +      {
> +#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
> +       if (&__strfromf128 == nullptr)
> +         len = sprintf(buffer, format_string, args..., (long double)value);
> +       else
> +#endif
> +       if constexpr (sizeof...(args) == 0)
> +         len = __strfromf128(buffer, length, "%.0f", value);
> +       else
> +         {
> +           // strfromf128 unfortunately doesn't allow .*
> +           char fmt[3 * sizeof(int) + 6];
> +           sprintf(fmt, "%%.%d%c", args..., int(format_string[4]));
> +           len = __strfromf128(buffer, length, fmt, value);
> +         }
> +      }
> +    else
> +#endif
>  #endif
>      len = sprintf(buffer, format_string, args..., value);
>
> @@ -1206,8 +1236,10 @@ template<typename T>
>             // can avoid this if we use sprintf to write all but the last
>             // digit, and carefully compute and write the last digit
>             // ourselves.
> -           char buffer[expected_output_length+1];
> -           const int output_length = sprintf_ld(buffer, "%.0Lf", value);
> +           char buffer[expected_output_length + 1];
> +           const int output_length = sprintf_ld(buffer,
> +                                                expected_output_length + 1,
> +                                                "%.0Lf", value);
>             __glibcxx_assert(output_length == expected_output_length);
>             memcpy(first, buffer, output_length);
>             return {first + output_length, errc{}};
> @@ -1397,9 +1429,10 @@ template<typename T>
>           __builtin_unreachable();
>
>         // Do the sprintf into the local buffer.
> -       char buffer[output_length_upper_bound+1];
> +       char buffer[output_length_upper_bound + 1];
>         int output_length
> -         = sprintf_ld(buffer, output_specifier, value, effective_precision);
> +         = sprintf_ld(buffer, output_length_upper_bound + 1, output_specifier,
> +                      value, effective_precision);
>         __glibcxx_assert(output_length <= output_length_upper_bound);
>
>         if (effective_precision > 0)
> @@ -1799,6 +1832,7 @@ to_chars(char* first, char* last, long d
>  }
>
>  #ifdef FLOAT128_TO_CHARS
> +#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
>  to_chars_result
>  to_chars(char* first, char* last, __float128 value) noexcept
>  {
> @@ -1817,6 +1851,26 @@ to_chars(char* first, char* last, __floa
>  {
>    return __floating_to_chars_precision(first, last, value, fmt, precision);
>  }
> +#else
> +to_chars_result
> +to_chars(char* first, char* last, _Float128 value) noexcept
> +{
> +  return __floating_to_chars_shortest(first, last, value, chars_format{});
> +}
> +
> +to_chars_result
> +to_chars(char* first, char* last, _Float128 value, chars_format fmt) noexcept
> +{
> +  return __floating_to_chars_shortest(first, last, value, fmt);
> +}
> +
> +to_chars_result
> +to_chars(char* first, char* last, _Float128 value, chars_format fmt,
> +        int precision) noexcept
> +{
> +  return __floating_to_chars_precision(first, last, value, fmt, precision);
> +}
> +#endif
>  #endif
>
>  // Entrypoints for 16-bit floats.
> --- libstdc++-v3/testsuite/20_util/to_chars/float128_c++23.cc.jj        2022-11-01 17:04:19.895606130 +0100
> +++ libstdc++-v3/testsuite/20_util/to_chars/float128_c++23.cc   2022-11-01 20:47:15.254989646 +0100
> @@ -0,0 +1,105 @@
> +// Copyright (C) 2022 Free Software Foundation, Inc.
> +//
> +// This file is part of the GNU ISO C++ Library.  This library is free
> +// software; you can redistribute it and/or modify it under the
> +// terms of the GNU General Public License as published by the
> +// Free Software Foundation; either version 3, or (at your option)
> +// any later version.
> +
> +// This library is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +
> +// You should have received a copy of the GNU General Public License along
> +// with this library; see the file COPYING3.  If not see
> +// <http://www.gnu.org/licenses/>.
> +
> +// { dg-options "-std=gnu++2b" }
> +// { dg-do run { target c++23 } }
> +// { dg-require-effective-target ieee_floats }
> +// { dg-require-effective-target size32plus }
> +// { dg-add-options ieee }
> +
> +#include <charconv>
> +#include <stdfloat>
> +#include <limits>
> +#include <numbers>
> +#include <testsuite_hooks.h>
> +
> +#if defined(__STDCPP_FLOAT128_T__) \
> +    && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
> +       || defined(_GLIBCXX_HAVE_FLOAT128_MATH))
> +void
> +test(std::chars_format fmt = std::chars_format{})
> +{
> +  std::float128_t tests[] = {
> +//    std::numeric_limits<std::float128_t>::denorm_min(),
> +    std::numeric_limits<std::float128_t>::min(),
> +    0.0f128,
> +    -42.0f128,
> +    1234.5678912345f128,
> +    std::numbers::e_v<std::float128_t>,
> +    std::numbers::log2e_v<std::float128_t>,
> +    std::numbers::log10e_v<std::float128_t>,
> +    std::numbers::pi_v<std::float128_t>,
> +    std::numbers::inv_pi_v<std::float128_t>,
> +    std::numbers::inv_sqrtpi_v<std::float128_t>,
> +    std::numbers::ln2_v<std::float128_t>,
> +    std::numbers::ln10_v<std::float128_t>,
> +    std::numbers::sqrt2_v<std::float128_t>,
> +    std::numbers::sqrt3_v<std::float128_t>,
> +    std::numbers::inv_sqrt3_v<std::float128_t>,
> +    std::numbers::egamma_v<std::float128_t>,
> +    std::numbers::phi_v<std::float128_t>,
> +    std::numeric_limits<std::float128_t>::max()
> +  };
> +  char str1[10000], str2[10000];
> +  for (auto u : tests)
> +    {
> +      auto [ptr1, ec1] = std::to_chars(str1, str1 + sizeof(str1), u, fmt);
> +      VERIFY( ec1 == std::errc() );
> +//    std::cout << i << ' ' << std::string_view (str1, ptr1) << '\n';
> +      if (fmt == std::chars_format::fixed)
> +       {
> +         auto [ptr2, ec2] = std::to_chars(str2, str2 + (ptr1 - str1), u, fmt);
> +         VERIFY( ec2 == std::errc() && ptr2 - str2 == ptr1 - str1 );
> +         auto [ptr3, ec3] = std::to_chars(str2, str2 + (ptr1 - str1 - 1), u, fmt);
> +         VERIFY( ec3 != std::errc() );
> +       }
> +      std::float128_t v;
> +      auto [ptr4, ec4] = std::from_chars(str1, ptr1, v,
> +                                        fmt == std::chars_format{}
> +                                        ? std::chars_format::general : fmt);
> +      VERIFY( ec4 == std::errc() && ptr4 == ptr1 );
> +      VERIFY( u == v );
> +
> +      auto [ptr5, ec5] = std::to_chars(str1, str1 + sizeof(str1), u, fmt, 90);
> +      VERIFY( ec5 == std::errc() );
> +//    std::cout << i << ' ' << std::string_view (str1, ptr5) << '\n';
> +      v = 4.0f128;
> +      auto [ptr6, ec6] = std::from_chars(str1, ptr5, v,
> +                                        fmt == std::chars_format{}
> +                                        ? std::chars_format::general : fmt);
> +      VERIFY( ec6 == std::errc() && ptr6 == ptr5 );
> +      if (fmt == std::chars_format::fixed && u > 0.0f128 && u < 0.000001f128)
> +       VERIFY( v == 0.0 );
> +      else
> +       VERIFY( u == v );
> +    }
> +}
> +#endif
> +
> +int
> +main()
> +{
> +#if defined(__STDCPP_FLOAT128_T__) \
> +    && (defined(_GLIBCXX_LDOUBLE_IS_IEEE_BINARY128) \
> +       || defined(_GLIBCXX_HAVE_FLOAT128_MATH))
> +  test();
> +  test(std::chars_format::fixed);
> +  test(std::chars_format::scientific);
> +  test(std::chars_format::general);
> +  test(std::chars_format::hex);
> +#endif
> +}
>
>         Jakub
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-02  9:25 [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc Jakub Jelinek
  2022-11-07 13:45 ` Jonathan Wakely
@ 2022-11-07 16:11 ` Joseph Myers
  2022-11-07 17:48   ` Jonathan Wakely
  1 sibling, 1 reply; 9+ messages in thread
From: Joseph Myers @ 2022-11-07 16:11 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Jonathan Wakely, Patrick Palka, libstdc++, gcc-patches

On Wed, 2 Nov 2022, Jakub Jelinek via Gcc-patches wrote:

> APIs.  So that one can build gcc against older glibc and then compile
> user programs on newer glibc, the patch uses weak references unless
> gcc is compiled against glibc 2.26+.  strfromf128 unfortunately can't

This support for older glibc doesn't actually seem to be working, on an 
older system with glibc 2.19 I'm seeing

/scratch/jmyers/fsf/gcc-mainline/libstdc++-v3/src/c++17/floating_to_chars.cc:52:3: error: expected initializer before '__asm'
   52 |   __asm ("strfromf128");
      |   ^~~~~

and a series of subsequent errors.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-07 16:11 ` Joseph Myers
@ 2022-11-07 17:48   ` Jonathan Wakely
  2022-11-07 17:52     ` Joseph Myers
  2022-11-07 19:13     ` Jakub Jelinek
  0 siblings, 2 replies; 9+ messages in thread
From: Jonathan Wakely @ 2022-11-07 17:48 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jakub Jelinek, Patrick Palka, libstdc++, gcc-patches

On Mon, 7 Nov 2022 at 16:11, Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Wed, 2 Nov 2022, Jakub Jelinek via Gcc-patches wrote:
>
> > APIs.  So that one can build gcc against older glibc and then compile
> > user programs on newer glibc, the patch uses weak references unless
> > gcc is compiled against glibc 2.26+.  strfromf128 unfortunately can't
>
> This support for older glibc doesn't actually seem to be working, on an
> older system with glibc 2.19 I'm seeing
>
> /scratch/jmyers/fsf/gcc-mainline/libstdc++-v3/src/c++17/floating_to_chars.cc:52:3: error: expected initializer before '__asm'
>    52 |   __asm ("strfromf128");
>       |   ^~~~~
>
> and a series of subsequent errors.

This seems to "fix" it (not sure if it's right though):

#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
extern "C" _Float128 __strtof128(const char*, char**)
 __attribute__((__weak__));
#endif
extern "C" _Float128 __strtof128(const char*, char**)
 __asm ("strtof128");


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-07 17:48   ` Jonathan Wakely
@ 2022-11-07 17:52     ` Joseph Myers
  2022-11-07 19:13     ` Jakub Jelinek
  1 sibling, 0 replies; 9+ messages in thread
From: Joseph Myers @ 2022-11-07 17:52 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jakub Jelinek, Patrick Palka, libstdc++, gcc-patches

On Mon, 7 Nov 2022, Jonathan Wakely wrote:

> This seems to "fix" it (not sure if it's right though):
> 
> #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
> extern "C" _Float128 __strtof128(const char*, char**)
>  __attribute__((__weak__));
> #endif
> extern "C" _Float128 __strtof128(const char*, char**)
>  __asm ("strtof128");

Probably putting the __asm before the __attribute__ would also work 
without needing a separate declaration (but might be less convenient for 
the #if conditionals).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-07 17:48   ` Jonathan Wakely
  2022-11-07 17:52     ` Joseph Myers
@ 2022-11-07 19:13     ` Jakub Jelinek
  2022-11-07 22:43       ` Jonathan Wakely
  1 sibling, 1 reply; 9+ messages in thread
From: Jakub Jelinek @ 2022-11-07 19:13 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Joseph Myers, Patrick Palka, libstdc++, gcc-patches

On Mon, Nov 07, 2022 at 05:48:42PM +0000, Jonathan Wakely wrote:
> On Mon, 7 Nov 2022 at 16:11, Joseph Myers <joseph@codesourcery.com> wrote:
> >
> > On Wed, 2 Nov 2022, Jakub Jelinek via Gcc-patches wrote:
> >
> > > APIs.  So that one can build gcc against older glibc and then compile
> > > user programs on newer glibc, the patch uses weak references unless
> > > gcc is compiled against glibc 2.26+.  strfromf128 unfortunately can't
> >
> > This support for older glibc doesn't actually seem to be working, on an
> > older system with glibc 2.19 I'm seeing
> >
> > /scratch/jmyers/fsf/gcc-mainline/libstdc++-v3/src/c++17/floating_to_chars.cc:52:3: error: expected initializer before '__asm'
> >    52 |   __asm ("strfromf128");
> >       |   ^~~~~
> >
> > and a series of subsequent errors.
> 
> This seems to "fix" it (not sure if it's right though):
> 
> #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
> extern "C" _Float128 __strtof128(const char*, char**)
>  __attribute__((__weak__));
> #endif
> extern "C" _Float128 __strtof128(const char*, char**)
>  __asm ("strtof128");

It is, but floating_from_chars.cc has the same problem,
and I think we can avoid the duplication, like this:

2022-11-07  Jakub Jelinek  <jakub@redhat.com>

	* src/c++17/floating_from_chars.cc (__strtof128): Put __asm before
	__attribute__.
	* src/c++17/floating_to_chars.cc (__strfromf128): Likewise.

--- libstdc++-v3/src/c++17/floating_from_chars.cc.jj	2022-11-07 15:15:42.928314819 +0100
+++ libstdc++-v3/src/c++17/floating_from_chars.cc	2022-11-07 20:09:47.267983154 +0100
@@ -63,10 +63,11 @@ extern "C" __ieee128 __strtoieee128(cons
       && defined(__GLIBC_PREREQ)
 #define USE_STRTOF128_FOR_FROM_CHARS 1
 extern "C" _Float128 __strtof128(const char*, char**)
+  __asm ("strtof128")
 #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
   __attribute__((__weak__))
 #endif
-  __asm ("strtof128");
+  ;
 #endif
 
 #if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
--- libstdc++-v3/src/c++17/floating_to_chars.cc.jj	2022-11-07 15:15:42.929314805 +0100
+++ libstdc++-v3/src/c++17/floating_to_chars.cc	2022-11-07 20:10:13.189627684 +0100
@@ -46,10 +46,11 @@ extern "C" int __sprintfieee128(char*, c
 #elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
       && defined(__GLIBC_PREREQ)
 extern "C" int __strfromf128(char*, size_t, const char*, _Float128)
+  __asm ("strfromf128")
 #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
   __attribute__((__weak__))
 #endif
-  __asm ("strfromf128");
+  ;
 #endif
 
 // This implementation crucially assumes float/double have the


	Jakub


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-07 19:13     ` Jakub Jelinek
@ 2022-11-07 22:43       ` Jonathan Wakely
  2022-11-08  1:41         ` Joseph Myers
  0 siblings, 1 reply; 9+ messages in thread
From: Jonathan Wakely @ 2022-11-07 22:43 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Joseph Myers, Patrick Palka, libstdc++, gcc-patches

On Mon, 7 Nov 2022 at 19:13, Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Mon, Nov 07, 2022 at 05:48:42PM +0000, Jonathan Wakely wrote:
> > On Mon, 7 Nov 2022 at 16:11, Joseph Myers <joseph@codesourcery.com> wrote:
> > >
> > > On Wed, 2 Nov 2022, Jakub Jelinek via Gcc-patches wrote:
> > >
> > > > APIs.  So that one can build gcc against older glibc and then compile
> > > > user programs on newer glibc, the patch uses weak references unless
> > > > gcc is compiled against glibc 2.26+.  strfromf128 unfortunately can't
> > >
> > > This support for older glibc doesn't actually seem to be working, on an
> > > older system with glibc 2.19 I'm seeing
> > >
> > > /scratch/jmyers/fsf/gcc-mainline/libstdc++-v3/src/c++17/floating_to_chars.cc:52:3: error: expected initializer before '__asm'
> > >    52 |   __asm ("strfromf128");
> > >       |   ^~~~~
> > >
> > > and a series of subsequent errors.
> >
> > This seems to "fix" it (not sure if it's right though):
> >
> > #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
> > extern "C" _Float128 __strtof128(const char*, char**)
> >  __attribute__((__weak__));
> > #endif
> > extern "C" _Float128 __strtof128(const char*, char**)
> >  __asm ("strtof128");
>
> It is, but floating_from_chars.cc has the same problem,
> and I think we can avoid the duplication, like this:

OK for trunk, thanks.

>
> 2022-11-07  Jakub Jelinek  <jakub@redhat.com>
>
>         * src/c++17/floating_from_chars.cc (__strtof128): Put __asm before
>         __attribute__.
>         * src/c++17/floating_to_chars.cc (__strfromf128): Likewise.
>
> --- libstdc++-v3/src/c++17/floating_from_chars.cc.jj    2022-11-07 15:15:42.928314819 +0100
> +++ libstdc++-v3/src/c++17/floating_from_chars.cc       2022-11-07 20:09:47.267983154 +0100
> @@ -63,10 +63,11 @@ extern "C" __ieee128 __strtoieee128(cons
>        && defined(__GLIBC_PREREQ)
>  #define USE_STRTOF128_FOR_FROM_CHARS 1
>  extern "C" _Float128 __strtof128(const char*, char**)
> +  __asm ("strtof128")
>  #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
>    __attribute__((__weak__))
>  #endif
> -  __asm ("strtof128");
> +  ;
>  #endif
>
>  #if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 \
> --- libstdc++-v3/src/c++17/floating_to_chars.cc.jj      2022-11-07 15:15:42.929314805 +0100
> +++ libstdc++-v3/src/c++17/floating_to_chars.cc 2022-11-07 20:10:13.189627684 +0100
> @@ -46,10 +46,11 @@ extern "C" int __sprintfieee128(char*, c
>  #elif __FLT128_MANT_DIG__ == 113 && __LDBL_MANT_DIG__ != 113 \
>        && defined(__GLIBC_PREREQ)
>  extern "C" int __strfromf128(char*, size_t, const char*, _Float128)
> +  __asm ("strfromf128")
>  #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
>    __attribute__((__weak__))
>  #endif
> -  __asm ("strfromf128");
> +  ;
>  #endif
>
>  // This implementation crucially assumes float/double have the
>
>
>         Jakub
>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-07 22:43       ` Jonathan Wakely
@ 2022-11-08  1:41         ` Joseph Myers
  2022-11-08  8:43           ` Jakub Jelinek
  0 siblings, 1 reply; 9+ messages in thread
From: Joseph Myers @ 2022-11-08  1:41 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: Jakub Jelinek, Patrick Palka, libstdc++, gcc-patches

I've committed this further fix for a syntax error as obvious.

libstdc++: Fix syntax error in old-glibc case in floating_from_chars.cc [PR107562]

	PR libstdc++/107562
	* src/c++17/floating_from_chars.cc (from_chars_impl): Fix syntax
	error.

diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc b/libstdc++-v3/src/c++17/floating_from_chars.cc
index 29eb4634e9d..be1e1051b5c 100644
--- a/libstdc++-v3/src/c++17/floating_from_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
@@ -632,7 +632,7 @@ namespace
 	  {
 #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
 	    if (&__strtof128 == nullptr)
-	      tmpval = _Float128(std::strtold(str, &endptr);
+	      tmpval = _Float128(std::strtold(str, &endptr));
 	    else
 #endif
 	      tmpval = __strtof128(str, &endptr);

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc
  2022-11-08  1:41         ` Joseph Myers
@ 2022-11-08  8:43           ` Jakub Jelinek
  0 siblings, 0 replies; 9+ messages in thread
From: Jakub Jelinek @ 2022-11-08  8:43 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jonathan Wakely, Patrick Palka, libstdc++, gcc-patches

On Tue, Nov 08, 2022 at 01:41:41AM +0000, Joseph Myers wrote:
> I've committed this further fix for a syntax error as obvious.

Thanks and sorry.

> libstdc++: Fix syntax error in old-glibc case in floating_from_chars.cc [PR107562]
> 
> 	PR libstdc++/107562
> 	* src/c++17/floating_from_chars.cc (from_chars_impl): Fix syntax
> 	error.
> 
> diff --git a/libstdc++-v3/src/c++17/floating_from_chars.cc b/libstdc++-v3/src/c++17/floating_from_chars.cc
> index 29eb4634e9d..be1e1051b5c 100644
> --- a/libstdc++-v3/src/c++17/floating_from_chars.cc
> +++ b/libstdc++-v3/src/c++17/floating_from_chars.cc
> @@ -632,7 +632,7 @@ namespace
>  	  {
>  #ifndef _GLIBCXX_HAVE_FLOAT128_MATH
>  	    if (&__strtof128 == nullptr)
> -	      tmpval = _Float128(std::strtold(str, &endptr);
> +	      tmpval = _Float128(std::strtold(str, &endptr));
>  	    else
>  #endif
>  	      tmpval = __strtof128(str, &endptr);

	Jakub


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-11-08  8:43 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-02  9:25 [PATCH] libstdc++: Add _Float128 to_chars/from_chars support for x86, ia64 and ppc64le with glibc Jakub Jelinek
2022-11-07 13:45 ` Jonathan Wakely
2022-11-07 16:11 ` Joseph Myers
2022-11-07 17:48   ` Jonathan Wakely
2022-11-07 17:52     ` Joseph Myers
2022-11-07 19:13     ` Jakub Jelinek
2022-11-07 22:43       ` Jonathan Wakely
2022-11-08  1:41         ` Joseph Myers
2022-11-08  8:43           ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).