[v2] Remap __GLIBC_FLT_EVAL_METHOD to 0 if __FLT_EVAL_METHOD__ is -1

Message ID 20230314151948.12892-1-kito.cheng@sifive.com
State Committed
Commit a225cb3ee9a22021312ae25c37595cd9d1995a1f
Headers
Series [v2] Remap __GLIBC_FLT_EVAL_METHOD to 0 if __FLT_EVAL_METHOD__ is -1 |

Checks

Context Check Description
dj/TryBot-apply_patch success Patch applied to master at the time it was sent
dj/TryBot-32bit success Build for i686

Commit Message

Kito Cheng March 14, 2023, 3:19 p.m. UTC
  __GLIBC_FLT_EVAL_METHOD will effect the definition of float_t and
double_t, currently we'll set __GLIBC_FLT_EVAL_METHOD to 2 when
__FLT_EVAL_METHOD__ is -1, that means we'll define float_t and double_t
to long double.

However some target isn't natively (HW) support long double like AArch64 and
RISC-V, they defined long double as 128-bits IEEE 754 floating point type.

That means setting __GLIBC_FLT_EVAL_METHOD to 2 will cause very inefficient
code gen for those target who didn't provide native support for long
double, and that's violate the spirit float_t and double_t - most efficient
types at least as wide as float and double.

So this patch propose to remap __GLIBC_FLT_EVAL_METHOD to 0 rather than
2 when __FLT_EVAL_METHOD__ is -1, which means we'll use float/double
rather than long double for float_t and double_t.

Note: __FLT_EVAL_METHOD__ == -1 means the precision is indeterminable,
      which means compiler might using indeterminable precision during
      optimization/code gen, clang will set this value to -1 when fast
      math is enabled.

Note: Default definition float_t and double_t in current glibc:
      |  __GLIBC_FLT_EVAL_METHOD | float_t     | double_t
      |               0 or 16    | float       | double
      |               1          | double      | doulbe
      |               2          | long double | long double
      More complete list see math/math.h

Note: RISC-V has defined ISA extension to support 128-bits IEEE 754
      floating point operations, but only rare RISC-V core will implement that.

Related link:

[1] LLVM issue (__FLT_EVAL_METHOD__ is set to -1 with Ofast. #60781):
    https://github.com/llvm/llvm-project/issues/60781
[2] Last version of this patch: https://sourceware.org/pipermail/libc-alpha/2023-February/145622.html

Acked-by: Palmer Dabbelt <palmer@rivosinc.com> # RISC-V

---

v2 Changes:

- Tweak comment.
- Tweak commit log: Separating commit log, discussion and c99 spec
  reference.

We were intending to update RISC-V's setting only, but after discussion
with Wilco Dijkstra, we decide to change the generic one instead of RISC-V only
since it also fix inefficient issue for float_t and double_t.

Ref:

[1] Definition of FLT_EVAL_METHOD from C99 spec:
C99 Spec draft: (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)

Except for assignment and cast (which remove all extra range and precision), the values
of operations with floating operands and values subject to the usual arithmetic
conversions and of floating constants are evaluated to a format whose range and precision
may be greater than required by the type. The use of evaluation formats is characterized
by the implementation-defined value of FLT_EVAL_METHOD:
19)

  -1 indeterminable;
  0 evaluate all operations and constants just to the range and precision of the
    type;
  1 evaluate operations and constants of type float and double to the
    range and precision of the double type, evaluate long double
    operations and constants to the range and precision of the long double
    type;
  2 evaluate all operations and constants to the range and precision of the
    long double type.

All other negative values for FLT_EVAL_METHOD characterize implementation-defined
behavior.

[2] Definition of float_t and double_t in C99 spec:

C99 Spec draft: (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf)

7.12

...

The types
float_t
double_t
are floating types at least as wide as float and double, respectively, and such that
double_t is at least as wide as float_t. If FLT_EVAL_METHOD equals 0,
float_t and double_t are float and double, respectively; if
FLT_EVAL_METHOD equals 1, they are both double; if FLT_EVAL_METHOD equals
2, they are both long double; and for other values of FLT_EVAL_METHOD, they are
otherwise implementation-defined.199)

199) The types float_t and double_t are intended to be the implementation’s most efficient types at
least as wide as float and double, respectively. For FLT_EVAL_METHOD equal 0, 1, or 2, the
type float_t is the narrowest type used by the implementation to
evaluate floating expressions.
---
 bits/flt-eval-method.h | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)
  

Comments

Wilco Dijkstra March 16, 2023, 6:42 p.m. UTC | #1
Hi Kito,

Thanks for the update, this looks good now.

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>

Cheers,
Wilco


---
 bits/flt-eval-method.h | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/bits/flt-eval-method.h b/bits/flt-eval-method.h
index 75f57b9a0e..f9262d7d0b 100644
--- a/bits/flt-eval-method.h
+++ b/bits/flt-eval-method.h
@@ -26,14 +26,12 @@
    -1.  */
 
 /* In the default version of this header, follow __FLT_EVAL_METHOD__.
-   -1 is mapped to 2 (considering evaluation as long double to be a
-   conservatively safe assumption), and if __FLT_EVAL_METHOD__ is not
-   defined then assume there is no excess precision and use the value
-   0.  */
+   If __FLT_EVAL_METHOD__ is not defined or set to -1, assume there is no
+   excess precision and use the value 0 (this is correct for most targets). */
 
 #ifdef __FLT_EVAL_METHOD__
 # if __FLT_EVAL_METHOD__ == -1
-#  define __GLIBC_FLT_EVAL_METHOD      2
+#  define __GLIBC_FLT_EVAL_METHOD      0
 # else
 #  define __GLIBC_FLT_EVAL_METHOD       __FLT_EVAL_METHOD__
 # endif
  

Patch

diff --git a/bits/flt-eval-method.h b/bits/flt-eval-method.h
index 75f57b9a0e..f9262d7d0b 100644
--- a/bits/flt-eval-method.h
+++ b/bits/flt-eval-method.h
@@ -26,14 +26,12 @@ 
    -1.  */
 
 /* In the default version of this header, follow __FLT_EVAL_METHOD__.
-   -1 is mapped to 2 (considering evaluation as long double to be a
-   conservatively safe assumption), and if __FLT_EVAL_METHOD__ is not
-   defined then assume there is no excess precision and use the value
-   0.  */
+   If __FLT_EVAL_METHOD__ is not defined or set to -1, assume there is no
+   excess precision and use the value 0 (this is correct for most targets). */
 
 #ifdef __FLT_EVAL_METHOD__
 # if __FLT_EVAL_METHOD__ == -1
-#  define __GLIBC_FLT_EVAL_METHOD	2
+#  define __GLIBC_FLT_EVAL_METHOD	0
 # else
 #  define __GLIBC_FLT_EVAL_METHOD	__FLT_EVAL_METHOD__
 # endif