summaryrefslogtreecommitdiff
path: root/libstdc++-v3/src/c++17/floating_to_chars.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/src/c++17/floating_to_chars.cc')
-rw-r--r--libstdc++-v3/src/c++17/floating_to_chars.cc73
1 files changed, 64 insertions, 9 deletions
diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc b/libstdc++-v3/src/c++17/floating_to_chars.cc
index a253ee42416..afce8d74c12 100644
--- a/libstdc++-v3/src/c++17/floating_to_chars.cc
+++ b/libstdc++-v3/src/c++17/floating_to_chars.cc
@@ -43,6 +43,14 @@
#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)
+ __asm ("strfromf128")
+#ifndef _GLIBCXX_HAVE_FLOAT128_MATH
+ __attribute__((__weak__))
+#endif
+ ;
#endif
// This implementation crucially assumes float/double have the
@@ -77,10 +85,11 @@ extern "C" int __sprintfieee128(char*, const char*, ...);
#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 +261,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
@@ -1034,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;
@@ -1044,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);
@@ -1205,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{}};
@@ -1396,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)
@@ -1798,6 +1832,7 @@ to_chars(char* first, char* last, long double value, chars_format fmt,
}
#ifdef FLOAT128_TO_CHARS
+#ifdef _GLIBCXX_LONG_DOUBLE_ALT128_COMPAT
to_chars_result
to_chars(char* first, char* last, __float128 value) noexcept
{
@@ -1816,6 +1851,26 @@ to_chars(char* first, char* last, __float128 value, chars_format fmt,
{
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.