[PATCH v2] i386: Fix fmod/fmodf/remainder/remainderf for gcc-12
Adhemerval Zanella
adhemerval.zanella@linaro.org
Wed Dec 3 14:31:43 GMT 2025
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.
---
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 <<EOF
+$conftest_code
+EOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler inlines __builtin_fmod/__builtin_remainder" >&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.43.0
More information about the Libc-alpha
mailing list