[3/4] math: signal underflow for fmaf results that are tiny before rounding

Message ID 20260803235509.3532030-4-mattst88@gmail.com (mailing list archive)
State Dropped
Headers
Series Fix underflow signalling for narrowing operations on Alpha |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed

Commit Message

Matt Turner Aug. 3, 2026, 11:55 p.m. UTC
  fmaf computes the exact result as a double and lets the return convert
it to float, so that conversion is the operation's single rounding and
is what has to signal underflow.  Where the exact result is tiny but
rounds up to the smallest normal float, architectures determining
tininess after rounding do not signal it, because the value they examine
is no longer tiny.

Route the returns through a helper that applies CHECK_NARROW_TINY, which
already decides this by rounding with an unbounded exponent range.  The
raise is redundant on architectures that signal such results themselves.
---
 sysdeps/ieee754/dbl-64/s_fmaf.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)
  

Comments

Joseph Myers Aug. 4, 2026, 12:37 a.m. UTC | #1
On Mon, 3 Aug 2026, Matt Turner wrote:

> fmaf computes the exact result as a double and lets the return convert
> it to float, so that conversion is the operation's single rounding and
> is what has to signal underflow.  Where the exact result is tiny but
> rounds up to the smallest normal float, architectures determining
> tininess after rounding do not signal it, because the value they examine
> is no longer tiny.

As with the previous patch, is this general for after-rounding 
architectures, or specific to an Alpha hardware bug?  In either case, I'd 
expect changes to be appropriately conditional to avoid executing 
unnecessary code on unaffected targets.
  
Matt Turner Aug. 4, 2026, 2:10 a.m. UTC | #2
On Tue, 4 Aug 2026, Joseph Myers wrote:

> As with the previous patch, is this general for after-rounding
> architectures, or specific to an Alpha hardware bug?

Specific to Alpha.  On x86_64 without this patch

  fmaf (-0x8p-152, 0x8.8p-4, -0x3.fffff8p-128) -> -0x1p-126

raises underflow already.  I answered this at more length on 2/4, which
has the worked example.

Please drop this one too.  It will come back conditional, along with 2/4.

Matt
  

Patch

diff --git ./sysdeps/ieee754/dbl-64/s_fmaf.c ./sysdeps/ieee754/dbl-64/s_fmaf.c
index 639c273486..dc78e9453a 100644
--- ./sysdeps/ieee754/dbl-64/s_fmaf.c
+++ ./sysdeps/ieee754/dbl-64/s_fmaf.c
@@ -20,9 +20,24 @@ 
 #include <math.h>
 #include <fenv.h>
 #include <libm-alias-float.h>
+#include <math-narrow.h>
 #include <math-use-builtins.h>
 #include "math_config.h"
 
+#if !USE_FMAF_BUILTIN
+/* Narrow the double result to float.  The exact result of the fma is
+   representable as a double, so the conversion is the operation's single
+   rounding and it is what must signal underflow; help it where the
+   architecture does not.  */
+static inline float
+narrow_fmaf_result (double d)
+{
+  float ret = (float) d;
+  CHECK_NARROW_TINY (ret, d, __FLT_MIN__);
+  return ret;
+}
+#endif
+
 float
 __fmaf (float x, float y, float z)
 {
@@ -37,17 +52,17 @@  __fmaf (float x, float y, float z)
   /* If not exact or at round to even boundary, the result is correct in
      all rounding modes.  */
   if (__glibc_likely ((u & 0xfffffff) != 0))
-    return result;
+    return narrow_fmaf_result (result);
 
   /* Also check if the double result appears exact when it might not be and
      thus it will not set the underflow flag if denormal.  */
   if ((u & 0x10000000) == 0
       && ((u >> MANTISSA_WIDTH) & 0x7ff) > EXPONENT_BIAS - 126)
-    return result;
+    return narrow_fmaf_result (result);
 
   /* Return if result is exact in all rounding modes.  */
   if (result - xy == z && result - z == xy)
-    return result;
+    return narrow_fmaf_result (result);
 
   /* This is where 'double-rouding' might return a wrong value, and thus
      needs adjusting the low-order bits in the direction of the error.  */
@@ -62,7 +77,7 @@  __fmaf (float x, float y, float z)
     u++;
   else
     u--;
-  return asdouble (u);
+  return narrow_fmaf_result (asdouble (u));
 #endif /* ! USE_FMAF_BUILTIN  */
 }
 #ifndef __fmaf