Message ID | 20201221165838.1741387-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | libstdc++: Gracefully disable floating-point to_chars on unsupported targets | expand |
On 21/12/20 11:58 -0500, Patrick Palka via Libstdc++ wrote: >This patch conditionally disables the floating-point std::to_chars >implementation on targets whose float/double are not IEEE binary32 and >binary64 respectively, until a proper fallback can be added for such >targets. This fixes a bootstrap failure on non-IEEE-754 FP targets such >as vax-netbsdelf. > >The preprocessor conditions that define the new internal libstdc++ >macros for detecting the binary32 and binary64 formats were copied from >the test gcc/testsuite/gcc.dg/float-exact-1.c. > >Tested on x86_64-pc-linux-gnu, with and without -m32, and also when >artifically undefining the below new macros. Does this look OK for >trunk? > >libstdc++-v3/ChangeLog: > > * include/bits/c++config (_GLIBCXX_FLOAT_IS_IEEE_BINARY_32): > Define this macro. > (_GLIBCXX_DOUBLE_IS_IEEE_BINARY_64): Likewise. > * include/std/charconv (to_chars): Use the macros to > conditionally hide the overloads for floating-point types. > * src/c++17/floating_to_chars.cc: Use the macros to > conditionally disable this file. > (floating_type_traits<float>): Remove redundant static assert. > (floating_type_traits<double>): Likewise. > * testsuite/20_util/to_chars/double.cc: Use the macros to > conditionally disable this test. > * testsuite/20_util/to_chars/float.cc: Likewise. > * testsuite/20_util/to_chars/long_double.cc: Likewise. Adjust > dg-do directives so that we don't execute this test on targets > with a large long double type and without int128. >--- > libstdc++-v3/include/bits/c++config | 14 ++++++++++++++ > libstdc++-v3/include/std/charconv | 2 ++ > libstdc++-v3/src/c++17/floating_to_chars.cc | 9 +++++---- > .../testsuite/20_util/to_chars/double.cc | 2 ++ > .../testsuite/20_util/to_chars/float.cc | 2 ++ > .../testsuite/20_util/to_chars/long_double.cc | 17 +++++++++++++---- > 6 files changed, 38 insertions(+), 8 deletions(-) > >diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config >index 8cce88aa87b..f54074a2c04 100644 >--- a/libstdc++-v3/include/bits/c++config >+++ b/libstdc++-v3/include/bits/c++config >@@ -688,6 +688,20 @@ namespace std > # endif > #endif > >+// Define if float has the IEEE binary32 format. >+#if __FLT_MANT_DIG__ == 24 \ >+ && __FLT_MIN_EXP__ == -125 \ >+ && __FLT_MAX_EXP == 128 >+# define _GLIBCXX_FLOAT_IS_IEEE_BINARY32 1 >+#endif >+ >+// Define if double has the IEEE binary64 format. >+#if __DBL_MANT_DIG__ == 53 \ >+ && __DBL_MIN_EXP__ == -1021 \ >+ && __DBL_MAX_EXP__ == 1024 >+# define _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 1 >+#endif >+ > #ifdef __has_builtin > # ifdef __is_identifier > // Intel and older Clang require !__is_identifier for some built-ins: >diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv >index b57b0a16db2..1f005be47b1 100644 >--- a/libstdc++-v3/include/std/charconv >+++ b/libstdc++-v3/include/std/charconv >@@ -704,6 +704,7 @@ namespace __detail > > // Floating-point std::to_chars > >+#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 > // Overloads for float. > to_chars_result to_chars(char* __first, char* __last, float __value) noexcept; > to_chars_result to_chars(char* __first, char* __last, float __value, >@@ -725,6 +726,7 @@ namespace __detail > chars_format __fmt) noexcept; > to_chars_result to_chars(char* __first, char* __last, long double __value, > chars_format __fmt, int __precision) noexcept; >+#endif > > _GLIBCXX_END_NAMESPACE_VERSION > } // namespace std >diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc b/libstdc++-v3/src/c++17/floating_to_chars.cc >index b7c31c746cc..6d94d46cc0a 100644 >--- a/libstdc++-v3/src/c++17/floating_to_chars.cc >+++ b/libstdc++-v3/src/c++17/floating_to_chars.cc >@@ -22,6 +22,10 @@ > // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see > // <http://www.gnu.org/licenses/>. > >+// This implementation crucially assumes float/double have the >+// IEEE binary32/binary64 formats. >+#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 >+ > // Activate __glibcxx_assert within this file to shake out any bugs. > #define _GLIBCXX_ASSERTIONS 1 > >@@ -109,8 +113,6 @@ namespace > template<> > struct floating_type_traits<float> > { >- // We (and Ryu) assume float has the IEEE binary32 format. >- static_assert(__FLT_MANT_DIG__ == 24); > static constexpr int mantissa_bits = 23; > static constexpr int exponent_bits = 8; > static constexpr bool has_implicit_leading_bit = true; >@@ -124,8 +126,6 @@ namespace > template<> > struct floating_type_traits<double> > { >- // We (and Ryu) assume double has the IEEE binary64 format. >- static_assert(__DBL_MANT_DIG__ == 53); > static constexpr int mantissa_bits = 52; > static constexpr int exponent_bits = 11; > static constexpr bool has_implicit_leading_bit = true; >@@ -1565,3 +1565,4 @@ _ZSt8to_charsPcS_eSt12chars_formati(char* first, char* last, double value, > > _GLIBCXX_END_NAMESPACE_VERSION > } // namespace std >+#endif // _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 >diff --git a/libstdc++-v3/testsuite/20_util/to_chars/double.cc b/libstdc++-v3/testsuite/20_util/to_chars/double.cc >index 9d1f37d3026..a52d7e7cd61 100644 >--- a/libstdc++-v3/testsuite/20_util/to_chars/double.cc >+++ b/libstdc++-v3/testsuite/20_util/to_chars/double.cc >@@ -56952,6 +56952,7 @@ inline constexpr double_to_chars_testcase double_hex_precision_to_chars_test_cas > void > test01() > { >+#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 > auto handle_testcases = [] (const auto& testcases) { > for (const auto [value,fmt,precision,correct] : testcases) > { >@@ -56991,6 +56992,7 @@ test01() > handle_testcases(double_general_precision_to_chars_test_cases); > > handle_testcases(double_hex_precision_to_chars_test_cases); >+#endif If I'm reading this right, the compiler is going to churn through 50000 lines defining arrays of numbers, and then do nothing with them. This would mean you could { dg-require-effective-targets ieee-floats } so the whole testcase is skipped: --- a/libstdc++-v3/testsuite/lib/libstdc++.exp +++ b/libstdc++-v3/testsuite/lib/libstdc++.exp @@ -1323,6 +1323,14 @@ proc check_effective_target_futex { } { }] } +# Return 1 if float and double have the IEEE binary32 and binary64 formats. +proc check_effective_target_ieee-floats { } { + return [check_v3_target_prop_cached et_ieee_floats { + set cond "_GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64" + return [v3_check_preprocessor_condition ieee_floats $cond] + }] +} + set additional_prunes "" if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \ If something like that works, please do that. OK for trunk with that if it works, and as in your patch otherwise.
On Mon, 21 Dec 2020, Jonathan Wakely wrote: > On 21/12/20 11:58 -0500, Patrick Palka via Libstdc++ wrote: > > This patch conditionally disables the floating-point std::to_chars > > implementation on targets whose float/double are not IEEE binary32 and > > binary64 respectively, until a proper fallback can be added for such > > targets. This fixes a bootstrap failure on non-IEEE-754 FP targets such > > as vax-netbsdelf. > > > > The preprocessor conditions that define the new internal libstdc++ > > macros for detecting the binary32 and binary64 formats were copied from > > the test gcc/testsuite/gcc.dg/float-exact-1.c. > > > > Tested on x86_64-pc-linux-gnu, with and without -m32, and also when > > artifically undefining the below new macros. Does this look OK for > > trunk? > > > > libstdc++-v3/ChangeLog: > > > > * include/bits/c++config (_GLIBCXX_FLOAT_IS_IEEE_BINARY_32): > > Define this macro. > > (_GLIBCXX_DOUBLE_IS_IEEE_BINARY_64): Likewise. > > * include/std/charconv (to_chars): Use the macros to > > conditionally hide the overloads for floating-point types. > > * src/c++17/floating_to_chars.cc: Use the macros to > > conditionally disable this file. > > (floating_type_traits<float>): Remove redundant static assert. > > (floating_type_traits<double>): Likewise. > > * testsuite/20_util/to_chars/double.cc: Use the macros to > > conditionally disable this test. > > * testsuite/20_util/to_chars/float.cc: Likewise. > > * testsuite/20_util/to_chars/long_double.cc: Likewise. Adjust > > dg-do directives so that we don't execute this test on targets > > with a large long double type and without int128. > > --- > > libstdc++-v3/include/bits/c++config | 14 ++++++++++++++ > > libstdc++-v3/include/std/charconv | 2 ++ > > libstdc++-v3/src/c++17/floating_to_chars.cc | 9 +++++---- > > .../testsuite/20_util/to_chars/double.cc | 2 ++ > > .../testsuite/20_util/to_chars/float.cc | 2 ++ > > .../testsuite/20_util/to_chars/long_double.cc | 17 +++++++++++++---- > > 6 files changed, 38 insertions(+), 8 deletions(-) > > > > diff --git a/libstdc++-v3/include/bits/c++config > > b/libstdc++-v3/include/bits/c++config > > index 8cce88aa87b..f54074a2c04 100644 > > --- a/libstdc++-v3/include/bits/c++config > > +++ b/libstdc++-v3/include/bits/c++config > > @@ -688,6 +688,20 @@ namespace std > > # endif > > #endif > > > > +// Define if float has the IEEE binary32 format. > > +#if __FLT_MANT_DIG__ == 24 \ > > + && __FLT_MIN_EXP__ == -125 \ > > + && __FLT_MAX_EXP == 128 > > +# define _GLIBCXX_FLOAT_IS_IEEE_BINARY32 1 > > +#endif > > + > > +// Define if double has the IEEE binary64 format. > > +#if __DBL_MANT_DIG__ == 53 \ > > + && __DBL_MIN_EXP__ == -1021 \ > > + && __DBL_MAX_EXP__ == 1024 > > +# define _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 1 > > +#endif > > + > > #ifdef __has_builtin > > # ifdef __is_identifier > > // Intel and older Clang require !__is_identifier for some built-ins: > > diff --git a/libstdc++-v3/include/std/charconv > > b/libstdc++-v3/include/std/charconv > > index b57b0a16db2..1f005be47b1 100644 > > --- a/libstdc++-v3/include/std/charconv > > +++ b/libstdc++-v3/include/std/charconv > > @@ -704,6 +704,7 @@ namespace __detail > > > > // Floating-point std::to_chars > > > > +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 > > // Overloads for float. > > to_chars_result to_chars(char* __first, char* __last, float __value) > > noexcept; > > to_chars_result to_chars(char* __first, char* __last, float __value, > > @@ -725,6 +726,7 @@ namespace __detail > > chars_format __fmt) noexcept; > > to_chars_result to_chars(char* __first, char* __last, long double __value, > > chars_format __fmt, int __precision) noexcept; > > +#endif > > > > _GLIBCXX_END_NAMESPACE_VERSION > > } // namespace std > > diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc > > b/libstdc++-v3/src/c++17/floating_to_chars.cc > > index b7c31c746cc..6d94d46cc0a 100644 > > --- a/libstdc++-v3/src/c++17/floating_to_chars.cc > > +++ b/libstdc++-v3/src/c++17/floating_to_chars.cc > > @@ -22,6 +22,10 @@ > > // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see > > // <http://www.gnu.org/licenses/>. > > > > +// This implementation crucially assumes float/double have the > > +// IEEE binary32/binary64 formats. > > +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 > > + > > // Activate __glibcxx_assert within this file to shake out any bugs. > > #define _GLIBCXX_ASSERTIONS 1 > > > > @@ -109,8 +113,6 @@ namespace > > template<> > > struct floating_type_traits<float> > > { > > - // We (and Ryu) assume float has the IEEE binary32 format. > > - static_assert(__FLT_MANT_DIG__ == 24); > > static constexpr int mantissa_bits = 23; > > static constexpr int exponent_bits = 8; > > static constexpr bool has_implicit_leading_bit = true; > > @@ -124,8 +126,6 @@ namespace > > template<> > > struct floating_type_traits<double> > > { > > - // We (and Ryu) assume double has the IEEE binary64 format. > > - static_assert(__DBL_MANT_DIG__ == 53); > > static constexpr int mantissa_bits = 52; > > static constexpr int exponent_bits = 11; > > static constexpr bool has_implicit_leading_bit = true; > > @@ -1565,3 +1565,4 @@ _ZSt8to_charsPcS_eSt12chars_formati(char* first, char* > > last, double value, > > > > _GLIBCXX_END_NAMESPACE_VERSION > > } // namespace std > > +#endif // _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && > > _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 > > diff --git a/libstdc++-v3/testsuite/20_util/to_chars/double.cc > > b/libstdc++-v3/testsuite/20_util/to_chars/double.cc > > index 9d1f37d3026..a52d7e7cd61 100644 > > --- a/libstdc++-v3/testsuite/20_util/to_chars/double.cc > > +++ b/libstdc++-v3/testsuite/20_util/to_chars/double.cc > > @@ -56952,6 +56952,7 @@ inline constexpr double_to_chars_testcase > > double_hex_precision_to_chars_test_cas > > void > > test01() > > { > > +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 > > auto handle_testcases = [] (const auto& testcases) { > > for (const auto [value,fmt,precision,correct] : testcases) > > { > > @@ -56991,6 +56992,7 @@ test01() > > handle_testcases(double_general_precision_to_chars_test_cases); > > > > handle_testcases(double_hex_precision_to_chars_test_cases); > > +#endif > > If I'm reading this right, the compiler is going to churn through > 50000 lines defining arrays of numbers, and then do nothing with them. > > This would mean you could { dg-require-effective-targets ieee-floats } > so the whole testcase is skipped: > > --- a/libstdc++-v3/testsuite/lib/libstdc++.exp > +++ b/libstdc++-v3/testsuite/lib/libstdc++.exp > @@ -1323,6 +1323,14 @@ proc check_effective_target_futex { } { > }] > } > > +# Return 1 if float and double have the IEEE binary32 and binary64 formats. > +proc check_effective_target_ieee-floats { } { > + return [check_v3_target_prop_cached et_ieee_floats { > + set cond "_GLIBCXX_FLOAT_IS_IEEE_BINARY32 && > _GLIBCXX_DOUBLE_IS_IEEE_BINARY64" > + return [v3_check_preprocessor_condition ieee_floats $cond] > + }] > +} > + > set additional_prunes "" > > if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \ > > If something like that works, please do that. > > OK for trunk with that if it works, and as in your patch otherwise. Thanks a lot, this cleaner approach using a new effective target seems to work well. Here's what I've committed after another round of testing on x86_64-pc-linux-gnu: -- >8 -- Subject: [PATCH] libstdc++: Disable floating-point std::to_chars on unsupported targets This patch conditionally disables the floating-point std::to_chars implementation on targets whose float and double aren't IEEE binary32 and binary64, until a proper fallback can be added for such targets. This fixes a bootstrap failure on non-IEEE-754 FP targets such as vax-netbsdelf. The new preprocessor tests in c++config that detect the binary32 and binary64 formats were copied from gcc/testsuite/gcc.dg/float-exact-1.c. libstdc++-v3/ChangeLog: * include/bits/c++config (_GLIBCXX_FLOAT_IS_IEEE_BINARY_32): Define this macro. (_GLIBCXX_DOUBLE_IS_IEEE_BINARY_64): Likewise. * include/std/charconv (to_chars): Use these macros to conditionally hide the overloads for floating-point types. * src/c++17/floating_to_chars.cc: Use the macros to conditionally disable this file. (floating_type_traits<float>): Remove redundant static assert. (floating_type_traits<double>): Likewise. * testsuite/20_util/to_chars/double.cc: Run this test only on ieee-floats effective targets. * testsuite/20_util/to_chars/float.cc: Likewise. * testsuite/20_util/to_chars/long_double.cc: Likewise. * testsuite/lib/libstdc++.exp (check_effective_target_ieee-floats): Define new proc for detecting whether float and double have the IEEE binary32 and binary64 formats. --- libstdc++-v3/include/bits/c++config | 14 ++++++++++++++ libstdc++-v3/include/std/charconv | 2 ++ libstdc++-v3/src/c++17/floating_to_chars.cc | 10 ++++++---- libstdc++-v3/testsuite/20_util/to_chars/double.cc | 1 + libstdc++-v3/testsuite/20_util/to_chars/float.cc | 1 + .../testsuite/20_util/to_chars/long_double.cc | 1 + libstdc++-v3/testsuite/lib/libstdc++.exp | 8 ++++++++ 7 files changed, 33 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 8cce88aa87b..be0961a9d9e 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -688,6 +688,20 @@ namespace std # endif #endif +// Define if float has the IEEE binary32 format. +#if __FLT_MANT_DIG__ == 24 \ + && __FLT_MIN_EXP__ == -125 \ + && __FLT_MAX_EXP__ == 128 +# define _GLIBCXX_FLOAT_IS_IEEE_BINARY32 1 +#endif + +// Define if double has the IEEE binary64 format. +#if __DBL_MANT_DIG__ == 53 \ + && __DBL_MIN_EXP__ == -1021 \ + && __DBL_MAX_EXP__ == 1024 +# define _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 1 +#endif + #ifdef __has_builtin # ifdef __is_identifier // Intel and older Clang require !__is_identifier for some built-ins: diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index b57b0a16db2..c6e80693aad 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -702,6 +702,7 @@ namespace __detail chars_format __fmt = chars_format::general) noexcept; #endif +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 // Floating-point std::to_chars // Overloads for float. @@ -725,6 +726,7 @@ namespace __detail chars_format __fmt) noexcept; to_chars_result to_chars(char* __first, char* __last, long double __value, chars_format __fmt, int __precision) noexcept; +#endif _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc b/libstdc++-v3/src/c++17/floating_to_chars.cc index b7c31c746cc..6e154365aee 100644 --- a/libstdc++-v3/src/c++17/floating_to_chars.cc +++ b/libstdc++-v3/src/c++17/floating_to_chars.cc @@ -40,6 +40,10 @@ #include <string_view> #include <type_traits> +// This implementation crucially assumes float/double have the +// IEEE binary32/binary64 formats. +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 + // Determine the binary format of 'long double'. // We support the binary64, float80 (i.e. x86 80-bit extended precision), @@ -109,8 +113,6 @@ namespace template<> struct floating_type_traits<float> { - // We (and Ryu) assume float has the IEEE binary32 format. - static_assert(__FLT_MANT_DIG__ == 24); static constexpr int mantissa_bits = 23; static constexpr int exponent_bits = 8; static constexpr bool has_implicit_leading_bit = true; @@ -124,8 +126,6 @@ namespace template<> struct floating_type_traits<double> { - // We (and Ryu) assume double has the IEEE binary64 format. - static_assert(__DBL_MANT_DIG__ == 53); static constexpr int mantissa_bits = 52; static constexpr int exponent_bits = 11; static constexpr bool has_implicit_leading_bit = true; @@ -1565,3 +1565,5 @@ _ZSt8to_charsPcS_eSt12chars_formati(char* first, char* last, double value, _GLIBCXX_END_NAMESPACE_VERSION } // namespace std + +#endif // _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 diff --git a/libstdc++-v3/testsuite/20_util/to_chars/double.cc b/libstdc++-v3/testsuite/20_util/to_chars/double.cc index 9d1f37d3026..bb6f74424ed 100644 --- a/libstdc++-v3/testsuite/20_util/to_chars/double.cc +++ b/libstdc++-v3/testsuite/20_util/to_chars/double.cc @@ -32,6 +32,7 @@ // DEALINGS IN THE SOFTWARE. // { dg-do run { target c++17 } } +// { dg-require-effective-target ieee-floats } #include <charconv> diff --git a/libstdc++-v3/testsuite/20_util/to_chars/float.cc b/libstdc++-v3/testsuite/20_util/to_chars/float.cc index b8901063ea0..0c8dd4f66df 100644 --- a/libstdc++-v3/testsuite/20_util/to_chars/float.cc +++ b/libstdc++-v3/testsuite/20_util/to_chars/float.cc @@ -32,6 +32,7 @@ // DEALINGS IN THE SOFTWARE. // { dg-do run { target c++17 } } +// { dg-require-effective-target ieee-floats } #include <charconv> diff --git a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc index 12ac8ae7822..f89daa2c665 100644 --- a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc +++ b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc @@ -19,6 +19,7 @@ // hexadecimal floating-point literals. // { dg-do run { target c++17 } } // { dg-xfail-run-if "Ryu needs __int128" { large_long_double && { ! int128 } } } +// { dg-require-effective-target ieee-floats } #include <charconv> diff --git a/libstdc++-v3/testsuite/lib/libstdc++.exp b/libstdc++-v3/testsuite/lib/libstdc++.exp index b7d7b906de4..6e5634ef1d2 100644 --- a/libstdc++-v3/testsuite/lib/libstdc++.exp +++ b/libstdc++-v3/testsuite/lib/libstdc++.exp @@ -1323,6 +1323,14 @@ proc check_effective_target_futex { } { }] } +# Return 1 if float and double have the IEEE binary32 and binary64 formats. +proc check_effective_target_ieee-floats { } { + return [check_v3_target_prop_cached et_ieee_floats { + set cond "_GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64" + return [v3_check_preprocessor_condition ieee_floats $cond] + }] +} + set additional_prunes "" if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \
On Mon, 21 Dec 2020, Patrick Palka via Gcc-patches wrote: > This patch conditionally disables the floating-point std::to_chars > implementation on targets whose float and double aren't IEEE binary32 > and binary64, until a proper fallback can be added for such targets. > This fixes a bootstrap failure on non-IEEE-754 FP targets such as > vax-netbsdelf. And I have actually verified this change as posted makes `vax-netbsdelf' GCC build again. I haven't run any regression testing though. Thanks for the fix and the short RTT! Maciej
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 8cce88aa87b..f54074a2c04 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -688,6 +688,20 @@ namespace std # endif #endif +// Define if float has the IEEE binary32 format. +#if __FLT_MANT_DIG__ == 24 \ + && __FLT_MIN_EXP__ == -125 \ + && __FLT_MAX_EXP == 128 +# define _GLIBCXX_FLOAT_IS_IEEE_BINARY32 1 +#endif + +// Define if double has the IEEE binary64 format. +#if __DBL_MANT_DIG__ == 53 \ + && __DBL_MIN_EXP__ == -1021 \ + && __DBL_MAX_EXP__ == 1024 +# define _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 1 +#endif + #ifdef __has_builtin # ifdef __is_identifier // Intel and older Clang require !__is_identifier for some built-ins: diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv index b57b0a16db2..1f005be47b1 100644 --- a/libstdc++-v3/include/std/charconv +++ b/libstdc++-v3/include/std/charconv @@ -704,6 +704,7 @@ namespace __detail // Floating-point std::to_chars +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 // Overloads for float. to_chars_result to_chars(char* __first, char* __last, float __value) noexcept; to_chars_result to_chars(char* __first, char* __last, float __value, @@ -725,6 +726,7 @@ namespace __detail chars_format __fmt) noexcept; to_chars_result to_chars(char* __first, char* __last, long double __value, chars_format __fmt, int __precision) noexcept; +#endif _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/src/c++17/floating_to_chars.cc b/libstdc++-v3/src/c++17/floating_to_chars.cc index b7c31c746cc..6d94d46cc0a 100644 --- a/libstdc++-v3/src/c++17/floating_to_chars.cc +++ b/libstdc++-v3/src/c++17/floating_to_chars.cc @@ -22,6 +22,10 @@ // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. +// This implementation crucially assumes float/double have the +// IEEE binary32/binary64 formats. +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 + // Activate __glibcxx_assert within this file to shake out any bugs. #define _GLIBCXX_ASSERTIONS 1 @@ -109,8 +113,6 @@ namespace template<> struct floating_type_traits<float> { - // We (and Ryu) assume float has the IEEE binary32 format. - static_assert(__FLT_MANT_DIG__ == 24); static constexpr int mantissa_bits = 23; static constexpr int exponent_bits = 8; static constexpr bool has_implicit_leading_bit = true; @@ -124,8 +126,6 @@ namespace template<> struct floating_type_traits<double> { - // We (and Ryu) assume double has the IEEE binary64 format. - static_assert(__DBL_MANT_DIG__ == 53); static constexpr int mantissa_bits = 52; static constexpr int exponent_bits = 11; static constexpr bool has_implicit_leading_bit = true; @@ -1565,3 +1565,4 @@ _ZSt8to_charsPcS_eSt12chars_formati(char* first, char* last, double value, _GLIBCXX_END_NAMESPACE_VERSION } // namespace std +#endif // _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 diff --git a/libstdc++-v3/testsuite/20_util/to_chars/double.cc b/libstdc++-v3/testsuite/20_util/to_chars/double.cc index 9d1f37d3026..a52d7e7cd61 100644 --- a/libstdc++-v3/testsuite/20_util/to_chars/double.cc +++ b/libstdc++-v3/testsuite/20_util/to_chars/double.cc @@ -56952,6 +56952,7 @@ inline constexpr double_to_chars_testcase double_hex_precision_to_chars_test_cas void test01() { +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 auto handle_testcases = [] (const auto& testcases) { for (const auto [value,fmt,precision,correct] : testcases) { @@ -56991,6 +56992,7 @@ test01() handle_testcases(double_general_precision_to_chars_test_cases); handle_testcases(double_hex_precision_to_chars_test_cases); +#endif } int diff --git a/libstdc++-v3/testsuite/20_util/to_chars/float.cc b/libstdc++-v3/testsuite/20_util/to_chars/float.cc index b8901063ea0..25fa4defaa9 100644 --- a/libstdc++-v3/testsuite/20_util/to_chars/float.cc +++ b/libstdc++-v3/testsuite/20_util/to_chars/float.cc @@ -4105,6 +4105,7 @@ inline constexpr float_to_chars_testcase float_hex_precision_to_chars_test_cases void test01() { +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 auto handle_testcases = [] (const auto& testcases) { for (const auto [value,fmt,precision,correct] : testcases) { @@ -4133,6 +4134,7 @@ test01() handle_testcases(float_fixed_precision_to_chars_test_cases); handle_testcases(float_general_precision_to_chars_test_cases); handle_testcases(float_hex_precision_to_chars_test_cases); +#endif } int diff --git a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc index 12ac8ae7822..e34c6c052cf 100644 --- a/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc +++ b/libstdc++-v3/testsuite/20_util/to_chars/long_double.cc @@ -15,10 +15,15 @@ // with this library; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. -// <charconv> is supported in C++14 as a GNU extension, but this test uses C++17 -// hexadecimal floating-point literals. -// { dg-do run { target c++17 } } -// { dg-xfail-run-if "Ryu needs __int128" { large_long_double && { ! int128 } } } +// Although <charconv> is supported in C++14 as a GNU extension, this +// testcase requires C++17 due to its use hexadecimal floating-point literals. +// { dg-require-effective-target c++17 } + +// On targets with a large long double type and without int128, we forward +// the long double to_chars overloads to the double to_chars overloads, +// which leads to a loss in precision in the output relative to printf. +// { dg-do run { target { { ! large_long_double } || int128 } } } +// { dg-do compile { target { large_long_double && { ! int128 } } } } #include <charconv> @@ -38,6 +43,7 @@ using namespace std; void test01() { +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 const long double hex_testcases[] = { nextdownl(numeric_limits<long double>::max()), nextupl(numeric_limits<long double>::min()), @@ -124,12 +130,14 @@ test01() VERIFY( !strcmp(to_chars_buffer, printf_buffer+strlen("0x")) ); } } +#endif } // Test the rest of the formatting modes, which go through printf. void test02() { +#if _GLIBCXX_FLOAT_IS_IEEE_BINARY32 && _GLIBCXX_DOUBLE_IS_IEEE_BINARY64 const long double growth_factor = 1.442695040888963407359924681001892137L; for (chars_format fmt : {chars_format::fixed, chars_format::scientific, chars_format::general}) @@ -189,6 +197,7 @@ test02() VERIFY( strcmp(to_chars_buffer, nearby_buffer) != 0 ); } } +#endif } int