[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