[PATCH] libstdc++: Gracefully disable floating-point to_chars on unsupported targets

Jonathan Wakely jwakely@redhat.com
Mon Dec 21 18:32:20 GMT 2020


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.




More information about the Libstdc++ mailing list