[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