From eb03df5404aa8a3c40d3de8d17885d19172c3a9d Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 3 Dec 2025 11:31:43 -0300 Subject: [PATCH] i386: Fix fmod/fmodf/remainder/remainderf for gcc-12 The __builtin_fmod{f} and __builtin_remainder{f} were added on gcc 13, and the minimum supported gcc is 12. This patch adds a configure test to check whether the compiler enables inlining for fmod/remainder, and uses inline assembly if not. Checked on i686-linux-gnu wih gcc-12. Reviewed-by: H.J. Lu --- config.h.in | 3 ++ sysdeps/i386/fpu/e_fmod.c | 2 +- sysdeps/i386/fpu/e_fmodf.c | 2 +- sysdeps/i386/fpu/e_remainder.c | 2 +- sysdeps/i386/fpu/e_remainderf.c | 2 +- sysdeps/x86/configure | 48 +++++++++++++++++++ sysdeps/x86/configure.ac | 27 +++++++++++ sysdeps/x86/fpu/math-inline-asm.h | 80 +++++++++++++++++++++++++++++++ 8 files changed, 162 insertions(+), 4 deletions(-) diff --git a/config.h.in b/config.h.in index 27e140dd5e..abc215850d 100644 --- a/config.h.in +++ b/config.h.in @@ -222,6 +222,9 @@ /* An integer used to scale the timeout of test programs. */ #define TIMEOUTFACTOR 1 +/* Define if __builtin_fmod/__builtin_remainder is inlined on x86. */ +#undef HAVE_X86_INLINE_FMOD + /* */ diff --git a/sysdeps/i386/fpu/e_fmod.c b/sysdeps/i386/fpu/e_fmod.c index 281b23dffc..13cd44c8f5 100644 --- a/sysdeps/i386/fpu/e_fmod.c +++ b/sysdeps/i386/fpu/e_fmod.c @@ -33,7 +33,7 @@ __fmod (double x, double y) && !is_nan (hx))) return __math_invalid (x); - return __builtin_fmod (x, y); + return fmod_inline (x, y); } strong_alias (__fmod, __ieee754_fmod) libm_alias_finite (__ieee754_fmod, __fmod) diff --git a/sysdeps/i386/fpu/e_fmodf.c b/sysdeps/i386/fpu/e_fmodf.c index 5b05d0fd95..63ad7c0c0a 100644 --- a/sysdeps/i386/fpu/e_fmodf.c +++ b/sysdeps/i386/fpu/e_fmodf.c @@ -33,7 +33,7 @@ __fmodf (float x, float y) && !is_nan (hx))) return __math_invalidf (x); - return __builtin_fmodf (x, y); + return fmodf_inline (x, y); } strong_alias (__fmodf, __ieee754_fmodf) versioned_symbol (libm, __fmodf, fmodf, GLIBC_2_43); diff --git a/sysdeps/i386/fpu/e_remainder.c b/sysdeps/i386/fpu/e_remainder.c index ec907ecaf9..1af8b27aa7 100644 --- a/sysdeps/i386/fpu/e_remainder.c +++ b/sysdeps/i386/fpu/e_remainder.c @@ -33,7 +33,7 @@ __remainder (double x, double y) && !is_nan (hx))) return __math_invalid (x); - return __builtin_remainder (x, y); + return remainder_inline (x, y); } strong_alias (__remainder, __ieee754_remainder) versioned_symbol (libm, __remainder, remainder, GLIBC_2_43); diff --git a/sysdeps/i386/fpu/e_remainderf.c b/sysdeps/i386/fpu/e_remainderf.c index 30ca4d3600..a0b97b7c6f 100644 --- a/sysdeps/i386/fpu/e_remainderf.c +++ b/sysdeps/i386/fpu/e_remainderf.c @@ -33,7 +33,7 @@ __remainderf (float x, float y) && !is_nan (hx))) return __math_invalidf (x); - return __builtin_remainderf (x, y); + return remainderf_inline (x, y); } strong_alias (__remainderf, __ieee754_remainderf) versioned_symbol (libm, __remainderf, remainderf, GLIBC_2_43); diff --git a/sysdeps/x86/configure b/sysdeps/x86/configure index e530a18f54..0798f194b6 100644 --- a/sysdeps/x86/configure +++ b/sysdeps/x86/configure @@ -430,6 +430,54 @@ else fi +conftest_code=" +double foo (double x, double y) +{ + return __builtin_fmod (x, y); +} +" + +cat > conftest.c <&5 +printf %s "checking if compiler inlines __builtin_fmod/__builtin_remainder... " >&6; } +if test ${libc_cv_cc_x86_inline_fmod+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $CFLAGS -fno-math-errno -S conftest.c -o conftest 1>&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + +libc_cv_cc_x86_inline_fmod=no +if grep -E -q "fprem" conftest; then + libc_cv_cc_x86_inline_fmod=yes +fi + + else + +echo "failed to check if CC inlines fmod." +rm -f conftest* +exit 1 + + fi ;; +esac +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_cc_x86_inline_fmod" >&5 +printf "%s\n" "$libc_cv_cc_x86_inline_fmod" >&6; } +rm -f conftest* +if test "$libc_cv_cc_x86_inline_fmod" = yes; then + printf "%s\n" "#define HAVE_X86_INLINE_FMOD 1" >>confdefs.h + +else + printf "%s\n" "#define HAVE_X86_INLINE_FMOD 0" >>confdefs.h + +fi if test "${libc_cv_cc_no_direct_extern_access}${libc_cv_test_cc_cflags_no_direct_extern_access}" = yes; then libc_cv_protected_data=no diff --git a/sysdeps/x86/configure.ac b/sysdeps/x86/configure.ac index c440b6bf5c..1e9c4d86db 100644 --- a/sysdeps/x86/configure.ac +++ b/sysdeps/x86/configure.ac @@ -240,6 +240,33 @@ else AC_DEFINE(HAVE_X86_LIBGCC_CMP_RETURN_ATTR, 0) fi +conftest_code=" +double foo (double x, double y) +{ + return __builtin_fmod (x, y); +} +" +dnl Check if CC inlines __builtin_fmod/__builtin_remainder +LIBC_TRY_CC_COMMAND([if compiler inlines __builtin_fmod/__builtin_remainder], + [$conftest_code], + [$CFLAGS -fno-math-errno -S], + libc_cv_cc_x86_inline_fmod, + [ +libc_cv_cc_x86_inline_fmod=no +if grep -E -q "fprem" conftest; then + libc_cv_cc_x86_inline_fmod=yes +fi +], +[ +echo "failed to check if CC inlines fmod." +rm -f conftest* +exit 1 +]) +if test "$libc_cv_cc_x86_inline_fmod" = yes; then + AC_DEFINE(HAVE_X86_INLINE_FMOD, 1) +else + AC_DEFINE(HAVE_X86_INLINE_FMOD, 0) +fi dnl If the building compiler enables no direct external data access by dnl default, access to protected data in shared libraries from executables diff --git a/sysdeps/x86/fpu/math-inline-asm.h b/sysdeps/x86/fpu/math-inline-asm.h index d4588979c0..72c5744291 100644 --- a/sysdeps/x86/fpu/math-inline-asm.h +++ b/sysdeps/x86/fpu/math-inline-asm.h @@ -74,4 +74,84 @@ divss_inline_asm (float x, float y) return x; } +static __always_inline double +fmod_inline (double x, double y) +{ +#if HAVE_X86_INLINE_FMOD + return __builtin_fmod (x, y); +#else + double result; + asm ("1:\n" + "fprem\n" + "fnstsw %%ax\n" + "sahf\n" + "jp 1b\n" + : "=t" (result) + : "0" (x), "u" (y) + : "ax", "cc" + ); + return result; +#endif +} + +static __always_inline float +fmodf_inline (float x, float y) +{ +#if HAVE_X86_INLINE_FMOD + return __builtin_fmodf (x, y); +#else + float result; + asm ("1:\n" + "fprem\n" + "fnstsw %%ax\n" + "sahf\n" + "jp 1b\n" + : "=t" (result) + : "0" (x), "u" (y) + : "ax", "cc" + ); + return result; +#endif +} + +static __always_inline double +remainder_inline (double x, double y) +{ +#if HAVE_X86_INLINE_FMOD + return __builtin_remainder (x, y); +#else + double result; + asm ("1:\n" + "fprem1\n" + "fnstsw %%ax\n" + "sahf\n" + "jp 1b\n" + : "=t" (result) + : "0" (x), "u" (y) + : "ax", "cc" + ); + return result; +#endif +} + +static __always_inline float +remainderf_inline (float x, float y) +{ +#if HAVE_X86_INLINE_FMOD + return __builtin_remainderf (x, y); +#else + float result; + asm ("1:\n" + "fprem1\n" + "fnstsw %%ax\n" + "sahf\n" + "jp 1b\n" + : "=t" (result) + : "0" (x), "u" (y) + : "ax", "cc" + ); + return result; +#endif +} + #endif -- 2.47.3