]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
i386: Fix fmod/fmodf/remainder/remainderf for gcc-12
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 3 Dec 2025 14:31:43 +0000 (11:31 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Thu, 4 Dec 2025 16:12:50 +0000 (13:12 -0300)
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 <hjl.tools@gmail.com>
config.h.in
sysdeps/i386/fpu/e_fmod.c
sysdeps/i386/fpu/e_fmodf.c
sysdeps/i386/fpu/e_remainder.c
sysdeps/i386/fpu/e_remainderf.c
sysdeps/x86/configure
sysdeps/x86/configure.ac
sysdeps/x86/fpu/math-inline-asm.h

index 27e140dd5e886e3089044a2eb9fac5fb0d4325cb..abc215850d00da8d8d101b699f13d996af8a60c1 100644 (file)
 /* 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
+
 /*
 \f */
 
index 281b23dffc095e72923362912a6ac40b1fe5fb19..13cd44c8f5ad872808b43e6dc47e96595f2bda91 100644 (file)
@@ -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)
index 5b05d0fd95865f071d83375a05d7918988e3f0e5..63ad7c0c0a54cffe673a267366acfeb7d572f0ad 100644 (file)
@@ -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);
index ec907ecaf985d20165d7c4ec05fab34139ed1260..1af8b27aa77e616e3097eab199eba11cd394fa93 100644 (file)
@@ -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);
index 30ca4d3600b170c99168a4df0b306083f5b5f24d..a0b97b7c6f913765d6d411fffc117ad25cfeca9e 100644 (file)
@@ -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);
index e530a18f548f2e3c3908020b221ed9d9166492e7..0798f194b6584491ebb5d529f670d5609038ef7b 100644 (file)
@@ -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
index c440b6bf5ca9a4d7777295d7906e206526c33d90..1e9c4d86dbe106254fca1ff998cc0d41d8c3234f 100644 (file)
@@ -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
index d4588979c0ca1876125b263a02c0d2f90c4a41b9..72c5744291b0cdda65e008333ce5b80999cd235a 100644 (file)
@@ -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