Blame SOURCES/gcc12-pr107468.patch

5e6e6d
libstdc++: Update from latest fast_float [PR107468]
5e6e6d
5e6e6d
The following patch is a cherry-pick from
5e6e6d
https://github.com/fastfloat/fast_float/pull/153
5e6e6d
to restrict fast_float Clinger's fast path to when rounding mode
5e6e6d
is FE_TONEAREST.
5e6e6d
Using std::fegetround showed in benchmarks too slow, so instead
5e6e6d
it uses a check with 2 float additions and comparison to verify
5e6e6d
if rounding is FE_TONEAREST.
5e6e6d
5e6e6d
2022-11-20  Jakub Jelinek  <jakub@redhat.com>
5e6e6d
5e6e6d
	PR libstdc++/107468
5e6e6d
	* src/c++17/fast_float/fast_float.h (detail::rounds_to_nearest): New
5e6e6d
	function, taken from https://github.com/fastfloat/fast_float/pull/153.
5e6e6d
	(from_chars_advanced): Only use Clinger's fast path if
5e6e6d
	detail::rounds_to_nearest().
5e6e6d
	* testsuite/20_util/from_chars/pr107468.cc: New test.
5e6e6d
5e6e6d
--- libstdc++-v3/src/c++17/fast_float/fast_float.h.jj	2022-04-28 15:56:18.315632888 +0200
5e6e6d
+++ libstdc++-v3/src/c++17/fast_float/fast_float.h	2022-11-20 18:53:49.570830249 +0100
5e6e6d
@@ -2842,6 +2842,48 @@ from_chars_result parse_infnan(const cha
5e6e6d
   return answer;
5e6e6d
 }
5e6e6d
 
5e6e6d
+/**
5e6e6d
+ * Returns true if the floating-pointing rounding mode is to 'nearest'.
5e6e6d
+ * It is the default on most system. This function is meant to be inexpensive.
5e6e6d
+ * Credit : @mwalcott3
5e6e6d
+ */
5e6e6d
+fastfloat_really_inline bool rounds_to_nearest() noexcept {
5e6e6d
+  // See
5e6e6d
+  // A fast function to check your floating-point rounding mode
5e6e6d
+  // https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/
5e6e6d
+  //
5e6e6d
+  // This function is meant to be equivalent to :
5e6e6d
+  // prior: #include <cfenv>
5e6e6d
+  //  return fegetround() == FE_TONEAREST;
5e6e6d
+  // However, it is expected to be much faster than the fegetround()
5e6e6d
+  // function call.
5e6e6d
+  //
5e6e6d
+  // The volatile keywoard prevents the compiler from computing the function
5e6e6d
+  // at compile-time.
5e6e6d
+  // There might be other ways to prevent compile-time optimizations (e.g., asm).
5e6e6d
+  // The value does not need to be std::numeric_limits<float>::min(), any small
5e6e6d
+  // value so that 1 + x should round to 1 would do (after accounting for excess
5e6e6d
+  // precision, as in 387 instructions).
5e6e6d
+  static volatile float fmin = std::numeric_limits<float>::min();
5e6e6d
+  float fmini = fmin; // we copy it so that it gets loaded at most once.
5e6e6d
+  //
5e6e6d
+  // Explanation:
5e6e6d
+  // Only when fegetround() == FE_TONEAREST do we have that
5e6e6d
+  // fmin + 1.0f == 1.0f - fmin.
5e6e6d
+  //
5e6e6d
+  // FE_UPWARD:
5e6e6d
+  //  fmin + 1.0f > 1
5e6e6d
+  //  1.0f - fmin == 1
5e6e6d
+  //
5e6e6d
+  // FE_DOWNWARD or  FE_TOWARDZERO:
5e6e6d
+  //  fmin + 1.0f == 1
5e6e6d
+  //  1.0f - fmin < 1
5e6e6d
+  //
5e6e6d
+  // Note: This may fail to be accurate if fast-math has been
5e6e6d
+  // enabled, as rounding conventions may not apply.
5e6e6d
+  return (fmini + 1.0f == 1.0f - fmini);
5e6e6d
+}
5e6e6d
+
5e6e6d
 } // namespace detail
5e6e6d
 
5e6e6d
 template<typename T>
5e6e6d
@@ -2870,7 +2912,7 @@ from_chars_result from_chars_advanced(co
5e6e6d
   answer.ec = std::errc(); // be optimistic
5e6e6d
   answer.ptr = pns.lastmatch;
5e6e6d
   // Next is Clinger's fast path.
5e6e6d
-  if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path() && !pns.too_many_digits) {
5e6e6d
+  if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path() && !pns.too_many_digits && detail::rounds_to_nearest()) {
5e6e6d
     value = T(pns.mantissa);
5e6e6d
     if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
5e6e6d
     else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
5e6e6d
--- libstdc++-v3/testsuite/20_util/from_chars/pr107468.cc.jj
5e6e6d
+++ libstdc++-v3/testsuite/20_util/from_chars/pr107468.cc
5e6e6d
@@ -0,0 +1,42 @@
5e6e6d
+// Copyright (C) 2022 Free Software Foundation, Inc.
5e6e6d
+//
5e6e6d
+// This file is part of the GNU ISO C++ Library.  This library is free
5e6e6d
+// software; you can redistribute it and/or modify it under the
5e6e6d
+// terms of the GNU General Public License as published by the
5e6e6d
+// Free Software Foundation; either version 3, or (at your option)
5e6e6d
+// any later version.
5e6e6d
+
5e6e6d
+// This library is distributed in the hope that it will be useful,
5e6e6d
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
5e6e6d
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5e6e6d
+// GNU General Public License for more details.
5e6e6d
+
5e6e6d
+// You should have received a copy of the GNU General Public License along
5e6e6d
+// with this library; see the file COPYING3.  If not see
5e6e6d
+// <http://www.gnu.org/licenses/>.
5e6e6d
+
5e6e6d
+// { dg-do run { target c++17 } }
5e6e6d
+// { dg-add-options ieee }
5e6e6d
+
5e6e6d
+#include <charconv>
5e6e6d
+#include <string>
5e6e6d
+#include <cfenv>
5e6e6d
+#include <testsuite_hooks.h>
5e6e6d
+
5e6e6d
+int
5e6e6d
+main()
5e6e6d
+{
5e6e6d
+  // FP from_char not available otherwise.
5e6e6d
+#if __cpp_lib_to_chars >= 201611L \
5e6e6d
+    && _GLIBCXX_USE_C99_FENV_TR1 \
5e6e6d
+    && defined(FE_DOWNWARD) \
5e6e6d
+    && defined(_GLIBCXX_FLOAT_IS_IEEE_BINARY32)
5e6e6d
+  // PR libstdc++/107468
5e6e6d
+  float f;
5e6e6d
+  char buf[] = "3.355447e+07";
5e6e6d
+  std::fesetround(FE_DOWNWARD);
5e6e6d
+  auto [ptr, ec] = std::from_chars(buf, buf + sizeof(buf) - 1, f, std::chars_format::scientific);
5e6e6d
+  VERIFY( ec == std::errc() && ptr == buf + sizeof(buf) - 1 );
5e6e6d
+  VERIFY( f == 33554472.0f );
5e6e6d
+#endif
5e6e6d
+}