[PATCH 0/4] Fix underflow signalling for narrowing operations on Alpha

Matt Turner <[email protected]> Mon, 3 Aug 2026 19:55:05 -0400
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
Four fixes found while getting the math testsuite to pass on Alpha.  Two
are generic and two are Alpha specific.

Patches 2 and 3 are the generic ones.  A narrowing operation rounds the
exact result once to the narrower type, so it underflows whenever that
result is both tiny and inexact, and two cases were not being signalled.

The first is a result that rounds up to exactly the smallest normal value
of the narrower type.  It is not tiny any more once rounded, so an
architecture that determines tininess after rounding does not signal
underflow for it, even though the exact result was tiny.  Whether
underflow is due is decided by rounding the round-to-odd value with an
unbounded exponent range, which is what the definition of tininess after
rounding asks for.

The second is a subnormal result, which is tiny by inspection.  Its
underflow is normally signalled by the narrowing conversion itself, but
is lost where that conversion is carried out in more than one step: an
intermediate type wide enough to keep the double rounding harmless for
the value can still round to a number the narrower type represents
exactly, leaving the final step exact.  This is what happens on Alpha,
where the compiler converts long double to float via double.

Both raises are redundant on architectures that already signal these, and
harmless there.  fmaf needs the same treatment, since it computes the
exact result as a double and lets the return convert it.

Patch 1 fixes FE_NOMASK_ENV on Alpha, which omitted the denormal trap
enable bit, so fegetexcept() did not return FE_ALL_EXCEPT.  Patch 4 marks
a test as expected to fail, for a case the hardware gets wrong and no
software layer can correct; it depends on patch 2 to fail for the reason
the comment describes.

Tested with a full make check on x86_64, i686, powerpc64, powerpc64le and
sparc64.  x86_64 and i686 show no failures at all.  powerpc64 and
powerpc64le have one or two failures in malloc and nptl that are
unrelated.  sparc64 has one math failure, test-float64x-float128-mul,
which is present identically on an unpatched build of the same commit.

On Alpha the math testsuite goes from 832 failures to 3, though most of
that is due to kernel fixes posted separately to linux-alpha; the two
generic patches here account for 28 of them and fmaf for two more.  The
three that remain are a GCC bug: a long double to float cast on Alpha is
lowered as quad to double to float, but C requires it to round once, and
the intermediate can land on a float halfway point.

The ibm128 long double configuration was not tested.  The generated test
data carries underflow-ok:arg-ibm128 markers in the cases these patches
touch, so that configuration is worth a look from someone who has one.

Matt Turner (4):
  alpha: add the denormal trap enable bit to FE_NOMASK_ENV
  math: signal underflow for narrowing results that are tiny before
    rounding
  math: signal underflow for fmaf results that are tiny before rounding
  alpha: expect test-float32x-float64-div to fail

 math/math-narrow.h                       | 130 ++++++++++++++++++-----
 sysdeps/alpha/Makefile                   |  14 +++
 sysdeps/alpha/fpu/bits/fenv.h            |   2 +-
 sysdeps/i386/fpu/s_f32xdivf64.c          |   3 +-
 sysdeps/i386/fpu/s_f32xmulf64.c          |   3 +-
 sysdeps/ieee754/dbl-64/s_fadd.c          |   3 +-
 sysdeps/ieee754/dbl-64/s_fdiv.c          |   4 +-
 sysdeps/ieee754/dbl-64/s_ffma.c          |   4 +-
 sysdeps/ieee754/dbl-64/s_fmaf.c          |  23 +++-
 sysdeps/ieee754/dbl-64/s_fmul.c          |   4 +-
 sysdeps/ieee754/dbl-64/s_fsub.c          |   3 +-
 sysdeps/ieee754/ldbl-128/s_daddl.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_ddivl.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_dfmal.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_dmull.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_dsubl.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_f64xaddf128.c |   4 +-
 sysdeps/ieee754/ldbl-128/s_f64xdivf128.c |   5 +-
 sysdeps/ieee754/ldbl-128/s_f64xfmaf128.c |   5 +-
 sysdeps/ieee754/ldbl-128/s_f64xmulf128.c |   5 +-
 sysdeps/ieee754/ldbl-128/s_f64xsubf128.c |   4 +-
 sysdeps/ieee754/ldbl-128/s_faddl.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_fdivl.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_ffmal.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_fmull.c       |   4 +-
 sysdeps/ieee754/ldbl-128/s_fsubl.c       |   4 +-
 sysdeps/ieee754/ldbl-96/s_daddl.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_ddivl.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_dfmal.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_dmull.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_dsubl.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_faddl.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_fdivl.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_ffmal.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_fmull.c        |   4 +-
 sysdeps/ieee754/ldbl-96/s_fsubl.c        |   4 +-
 sysdeps/x86/fpu/s_ffma.c                 |   4 +-
 37 files changed, 206 insertions(+), 94 deletions(-)

-- 
2.54.0