[PATCH 3/3] alpha: classify floating-point values without comparing

Matt Turner mattst88@gmail.com
Thu Sep 10 02:47:12 GMT 2026


The Alpha floating-point comparison instructions raise a denormal-operand
exception for a subnormal operand.  Unless the compiler arranges for software
completion (it only does so for -mieee, which is not the default), the
outcome depends on the FPCR denormal-operand-disable bit: either the operand
is flushed to zero, which makes a subnormal indistinguishable from a zero,
or the trap is delivered with no completion information, which is fatal.

GCC expands the classification builtins into such comparisons, so

  printf ("%d\n", fpclassify (0x1p-1050));

either prints FP_ZERO or dies with SIGFPE, depending on the trap mode.
iszero has the same problem without any builtin being involved, because it
expands to a comparison against zero written out in the header.

Add an Alpha bits/fpclassify.h that uses the out-of-line implementations,
which examine the encoding in an integer register.  Classifying out of line
means fpclassify, isnormal, issubnormal and iszero now need libm on Alpha,
since __fpclassify is exported from libm alone, unlike __isnan, __finite and
__isinf, which libc exports too.

This fixes C only.  libstdc++ undefines these macros in <cmath> and uses the
builtins itself, so C++ still classifies by comparing.

The new test is built with -mfp-trap-mode=n because glibc itself is built
with -mieee, which would hide the problem.  Without the Alpha header it fails
with

  Didn't expect signal from child: got `Floating point exception'

GCC PR target/127298 tracks expanding the classification builtins without
comparisons in the Alpha back end; once a release containing that fix exists,
the definitions in the Alpha header can be made conditional on the compiler
predating it.
---
 math/Makefile                   |  1 +
 math/test-classify-subnormal.c  | 63 +++++++++++++++++++++++++++++++++
 sysdeps/alpha/Makefile          |  6 ++++
 sysdeps/alpha/bits/fpclassify.h | 37 +++++++++++++++++++
 4 files changed, 107 insertions(+)
 create mode 100644 math/test-classify-subnormal.c
 create mode 100644 sysdeps/alpha/bits/fpclassify.h

diff --git ./math/Makefile ./math/Makefile
index d9b17a8277..44c882063c 100644
--- ./math/Makefile
+++ ./math/Makefile
@@ -538,6 +538,7 @@ tests = \
   bug-nextafter \
   bug-nexttoward \
   test-ceil-except-2 \
+  test-classify-subnormal \
   test-femode \
   test-femode-traps \
   test-fenv basic-test \
diff --git ./math/test-classify-subnormal.c ./math/test-classify-subnormal.c
new file mode 100644
index 0000000000..eb874d00cc
--- /dev/null
+++ ./math/test-classify-subnormal.c
@@ -0,0 +1,63 @@
+/* Test classification macros with subnormal arguments.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+/* The classification macros must distinguish a subnormal from a zero,
+   and must not trap.  */
+
+#include <bits/floatn.h>
+#include <float.h>
+#include <math.h>
+#include <support/check.h>
+
+#define TEST(TYPE, TRUE_MIN)						\
+  do									\
+    {									\
+      volatile TYPE sub = (TRUE_MIN);					\
+      TEST_VERIFY (fpclassify (sub) == FP_SUBNORMAL);			\
+      TEST_VERIFY (issubnormal (sub));					\
+      TEST_VERIFY (isfinite (sub));					\
+      TEST_VERIFY (!isnormal (sub));					\
+      TEST_VERIFY (!isnan (sub));					\
+      TEST_VERIFY (!isinf (sub));					\
+      TEST_VERIFY (!iszero (sub));					\
+      TEST_VERIFY (!signbit (sub));					\
+      TEST_VERIFY (fpclassify (-sub) == FP_SUBNORMAL);			\
+      TEST_VERIFY (signbit (-sub));					\
+    }									\
+  while (0)
+
+static int
+do_test (void)
+{
+  TEST (float, FLT_TRUE_MIN);
+  TEST (double, DBL_TRUE_MIN);
+  TEST (long double, LDBL_TRUE_MIN);
+#if __HAVE_DISTINCT_FLOAT128
+  TEST (_Float128, __FLT128_DENORM_MIN__);
+#endif
+
+  /* A zero must still classify as FP_ZERO.  */
+  volatile double zero = 0.0;
+  TEST_VERIFY (fpclassify (zero) == FP_ZERO);
+  TEST_VERIFY (iszero (zero));
+  TEST_VERIFY (!issubnormal (zero));
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git ./sysdeps/alpha/Makefile ./sysdeps/alpha/Makefile
index faa59ab27a..825c2351d2 100644
--- ./sysdeps/alpha/Makefile
+++ ./sysdeps/alpha/Makefile
@@ -54,6 +54,12 @@ CFLAGS-test-misc.c += -mieee-with-inexact
 # Avoid "conflicting types for built-in function" warnings
 CFLAGS-s_isnan.c += -fno-builtin-isnanf
 
+# glibc is built with -mieee (see below), which makes comparisons safe for
+# a subnormal operand; ordinary code is not, so test the default trap mode.
+# This must override the -mieee in sysdep-CFLAGS, so it has to come last on
+# the command line.
+CFLAGS-test-classify-subnormal.c += -mfp-trap-mode=n
+
 # _Float32x and _Float64 are both binary64 on Alpha, so this narrowing
 # divide is a plain divide and the hardware alone decides whether to
 # signal underflow.  IEEE 754 determines tininess after rounding from the
diff --git ./sysdeps/alpha/bits/fpclassify.h ./sysdeps/alpha/bits/fpclassify.h
new file mode 100644
index 0000000000..6efb1aee4a
--- /dev/null
+++ ./sysdeps/alpha/bits/fpclassify.h
@@ -0,0 +1,37 @@
+/* Define floating-point classification macros.  Alpha version.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _MATH_H
+# error "Never use <bits/fpclassify.h> directly; include <math.h> instead."
+#endif
+
+/* The Alpha floating-point comparison instructions raise a
+   denormal-operand exception for a subnormal operand.  With the default
+   trap mode the operand is either flushed to zero, which makes a
+   subnormal indistinguishable from a zero, or the trap is fatal.  Use
+   the out-of-line implementations, which examine the encoding in an
+   integer register, rather than the builtins, which compare.  GCC PR
+   target/127298 tracks expanding the builtins without comparisons.  */
+
+#define __MATH_CLASSIFY_NO_COMPARE 1
+
+#define fpclassify(x) __MATH_TG ((x), __fpclassify, (x))
+#define isfinite(x) __MATH_TG ((x), __finite, (x))
+#define isnormal(x) (fpclassify (x) == FP_NORMAL)
+#define isnan(x) __MATH_TG ((x), __isnan, (x))
+#define isinf(x) __MATH_TG ((x), __isinf, (x))
-- 
2.54.0



More information about the Libc-alpha mailing list