[PATCH 1/5] x86_64: Conditionally define __sfp_handle_exceptions for compiler-rt
Adhemerval Zanella
adhemerval.zanella@linaro.org
Wed Feb 11 18:55:28 GMT 2026
The LLVM compiler-rt builtins library does not currently provide an
implementation for __sfp_handle_exceptions. On x86_64, this causes
unresolved symbol errors when building glibc in environments that
exclude libgcc.
This patch implements __sfp_handle_exceptions specifically for x86_64,
bridging the gap for non-GNU compiler runtimes.
The implementation is used conditionally, only if the compiler does
not already provide the symbol.
NB: the implementation is based on libgcc and raises bosh SSE and i387
exceptions (different that the one from 460ee50de054396cc9791ff4)
---
config.h.in | 3 ++
configure | 82 ++++++++++++++++++++++++++++++++
configure.ac | 13 +++++
sysdeps/x86/fpu/Makefile | 5 +-
sysdeps/x86/fpu/sfp-exceptions.c | 74 ++++++++++++++++++++++++++++
5 files changed, 176 insertions(+), 1 deletion(-)
create mode 100644 sysdeps/x86/fpu/sfp-exceptions.c
diff --git a/config.h.in b/config.h.in
index 2cd8c90eb6..125532ec6b 100644
--- a/config.h.in
+++ b/config.h.in
@@ -228,6 +228,9 @@
/* Set to 1 if 64 bit atomics are supported. */
#undef HAVE_64B_ATOMICS
+/* Define to 1 if compiler runtime provides __sfp_handle_exceptions */
+#undef HAVE_SFP_HANDLE_EXCEPTIONS
+
/*
*/
diff --git a/configure b/configure
index 0cd2269859..2b9425232e 100755
--- a/configure
+++ b/configure
@@ -9368,6 +9368,88 @@ printf "%s\n" "$libc_cv_have_libgcc_s" >&6; }
config_vars="$config_vars
have-libgcc_s = $libc_cv_have_libgcc_s"
+# Check if compiler runtime library provides __sfp_handle_exceptions
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __sfp_handle_exceptions support" >&5
+printf %s "checking for __sfp_handle_exceptions support... " >&6; }
+if test ${libc_cv_sfp_handle_exceptions+y}
+then :
+ printf %s "(cached) " >&6
+else case e in #(
+ e)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+void __sfp_handle_exceptions (int); __sfp_handle_exceptions (0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ libc_cv_sfp_handle_exceptions=yes
+else case e in #(
+ e) libc_cv_sfp_handle_exceptions=no ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_sfp_handle_exceptions" >&5
+printf "%s\n" "$libc_cv_sfp_handle_exceptions" >&6; }
+if test "$TEST_CC" = "$CC"; then
+ libc_cv_test_sfp_handle_exceptions=$libc_cv_sfp_handle_exceptions
+else
+
+saved_CC="$CC"
+CC="$TEST_CC"
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __sfp_handle_exceptions support in testing" >&5
+printf %s "checking for __sfp_handle_exceptions support in testing... " >&6; }
+if test ${libc_cv_test_sfp_handle_exceptions+y}
+then :
+ printf %s "(cached) " >&6
+else case e in #(
+ e)
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main (void)
+{
+void __sfp_handle_exceptions (int); __sfp_handle_exceptions (0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+ libc_cv_test_sfp_handle_exceptions=yes
+else case e in #(
+ e) libc_cv_test_sfp_handle_exceptions=no ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext conftest.$ac_ext
+ ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_sfp_handle_exceptions" >&5
+printf "%s\n" "$libc_cv_test_sfp_handle_exceptions" >&6; }
+
+CC="$saved_CC"
+
+fi
+
+if test $libc_cv_sfp_handle_exceptions = yes; then
+ printf "%s\n" "#define HAVE_SFP_HANDLE_EXCEPTIONS 1" >>confdefs.h
+
+fi
+
# Support configure.ac under sysdeps.
diff --git a/configure.ac b/configure.ac
index 3e4a601c01..39d32ecf7f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2134,6 +2134,19 @@ AC_CACHE_CHECK([whether $CC can link against -lgcc_s], libc_cv_have_libgcc_s, [d
LIBS="$old_LIBS"])
LIBC_CONFIG_VAR([have-libgcc_s], [$libc_cv_have_libgcc_s])
+# Check if compiler runtime library provides __sfp_handle_exceptions
+LIBC_TRY_CC_AND_TEST_LINK([for __sfp_handle_exceptions support],
+ [void __sfp_handle_exceptions (int); __sfp_handle_exceptions (0)],
+ libc_cv_sfp_handle_exceptions,
+ [libc_cv_sfp_handle_exceptions=yes],
+ [libc_cv_sfp_handle_exceptions=no],
+ libc_cv_test_sfp_handle_exceptions,
+ [libc_cv_test_sfp_handle_exceptions=yes],
+ [libc_cv_test_sfp_handle_exceptions=no])
+if test $libc_cv_sfp_handle_exceptions = yes; then
+ AC_DEFINE([HAVE_SFP_HANDLE_EXCEPTIONS])
+fi
+
# Support configure.ac under sysdeps.
AC_SUBST(libc_cv_test_cc_mprefer_vector_width)
AC_SUBST(test_enable_cet)
diff --git a/sysdeps/x86/fpu/Makefile b/sysdeps/x86/fpu/Makefile
index 91b2444f3a..d847be5c34 100644
--- a/sysdeps/x86/fpu/Makefile
+++ b/sysdeps/x86/fpu/Makefile
@@ -2,7 +2,10 @@ ifeq ($(subdir),math)
# sqrtf128 requires soft-fp.
CPPFLAGS += -I../soft-fp
-libm-support += powl_helper
+libm-support += \
+ powl_helper \
+ sfp-exceptions \
+ # libm-support
tests += \
test-fenv-clear-sse \
test-fenv-sse \
diff --git a/sysdeps/x86/fpu/sfp-exceptions.c b/sysdeps/x86/fpu/sfp-exceptions.c
new file mode 100644
index 0000000000..385294912b
--- /dev/null
+++ b/sysdeps/x86/fpu/sfp-exceptions.c
@@ -0,0 +1,74 @@
+/* x86_64 soft-fp exception handling for _Float128.
+ 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 HAVE_SFP_HANDLE_EXCEPTIONS
+#include <fenv.h>
+#include <float.h>
+#include <soft-fp.h>
+
+#ifdef __SSE_MATH__
+# define __math_force_eval_div(x, y) \
+ do { asm ("" : "+x" (x)); asm volatile ("" : : "x" (x / y)); } while (0)
+#else
+# define __math_force_eval_div(x, y) \
+ do { asm ("" : "+t" (x)); asm volatile ("" : : "f" (x / y)); } while (0)
+#endif
+
+void
+__sfp_handle_exceptions (int _fex)
+{
+ fenv_t temp;
+
+ if (_fex & FP_EX_INVALID)
+ {
+ float f = 0.0f;
+ __math_force_eval_div (f, f);
+ }
+ if (_fex & FP_EX_DENORM)
+ {
+ asm volatile ("fnstenv\t%0" : "=m" (temp));
+ temp.__status_word |= FP_EX_DENORM;
+ asm volatile ("fldenv\t%0" : : "m" (temp));
+ asm volatile ("fwait");
+ }
+ if (_fex & FP_EX_DIVZERO)
+ {
+ float f = 1.0f, g = 0.0f;
+ __math_force_eval_div (f, g);
+ }
+ if (_fex & FP_EX_OVERFLOW)
+ {
+ asm volatile ("fnstenv\t%0" : "=m" (temp));
+ temp.__status_word |= FP_EX_OVERFLOW;
+ asm volatile ("fldenv\t%0" : : "m" (temp));
+ asm volatile ("fwait");
+ }
+ if (_fex & FP_EX_UNDERFLOW)
+ {
+ asm volatile ("fnstenv\t%0" : "=m" (temp));
+ temp.__status_word |= FP_EX_UNDERFLOW;
+ asm volatile ("fldenv\t%0" : : "m" (temp));
+ asm volatile ("fwait");
+ }
+ if (_fex & FP_EX_INEXACT)
+ {
+ float f = 1.0f, g = 3.0f;
+ __math_force_eval_div (f, g);
+ }
+}
+#endif
--
2.43.0
More information about the Libc-alpha
mailing list