[PATCH v2 1/6] x86_64: Conditionally define __sfp_handle_exceptions for compiler-rt
H.J. Lu
hjl.tools@gmail.com
Thu Feb 26 01:05:47 GMT 2026
On Thu, Feb 26, 2026 at 2:32 AM Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
>
> 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
>
LGTM.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
Thanks.
--
H.J.
More information about the Libc-alpha
mailing list