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 <hjl.tools@gmail.com>
This commit is contained in:
Adhemerval Zanella 2025-12-03 11:31:43 -03:00
parent 83dd79dffb
commit eb03df5404
8 changed files with 162 additions and 4 deletions

View File

@ -222,6 +222,9 @@
/* An integer used to scale the timeout of test programs. */ /* An integer used to scale the timeout of test programs. */
#define TIMEOUTFACTOR 1 #define TIMEOUTFACTOR 1
/* Define if __builtin_fmod/__builtin_remainder is inlined on x86. */
#undef HAVE_X86_INLINE_FMOD
/* /*
*/ */

View File

@ -33,7 +33,7 @@ __fmod (double x, double y)
&& !is_nan (hx))) && !is_nan (hx)))
return __math_invalid (x); return __math_invalid (x);
return __builtin_fmod (x, y); return fmod_inline (x, y);
} }
strong_alias (__fmod, __ieee754_fmod) strong_alias (__fmod, __ieee754_fmod)
libm_alias_finite (__ieee754_fmod, __fmod) libm_alias_finite (__ieee754_fmod, __fmod)

View File

@ -33,7 +33,7 @@ __fmodf (float x, float y)
&& !is_nan (hx))) && !is_nan (hx)))
return __math_invalidf (x); return __math_invalidf (x);
return __builtin_fmodf (x, y); return fmodf_inline (x, y);
} }
strong_alias (__fmodf, __ieee754_fmodf) strong_alias (__fmodf, __ieee754_fmodf)
versioned_symbol (libm, __fmodf, fmodf, GLIBC_2_43); versioned_symbol (libm, __fmodf, fmodf, GLIBC_2_43);

View File

@ -33,7 +33,7 @@ __remainder (double x, double y)
&& !is_nan (hx))) && !is_nan (hx)))
return __math_invalid (x); return __math_invalid (x);
return __builtin_remainder (x, y); return remainder_inline (x, y);
} }
strong_alias (__remainder, __ieee754_remainder) strong_alias (__remainder, __ieee754_remainder)
versioned_symbol (libm, __remainder, remainder, GLIBC_2_43); versioned_symbol (libm, __remainder, remainder, GLIBC_2_43);

View File

@ -33,7 +33,7 @@ __remainderf (float x, float y)
&& !is_nan (hx))) && !is_nan (hx)))
return __math_invalidf (x); return __math_invalidf (x);
return __builtin_remainderf (x, y); return remainderf_inline (x, y);
} }
strong_alias (__remainderf, __ieee754_remainderf) strong_alias (__remainderf, __ieee754_remainderf)
versioned_symbol (libm, __remainderf, remainderf, GLIBC_2_43); versioned_symbol (libm, __remainderf, remainderf, GLIBC_2_43);

48
sysdeps/x86/configure vendored
View File

@ -430,6 +430,54 @@ else
fi 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 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 libc_cv_protected_data=no

View File

@ -240,6 +240,33 @@ else
AC_DEFINE(HAVE_X86_LIBGCC_CMP_RETURN_ATTR, 0) AC_DEFINE(HAVE_X86_LIBGCC_CMP_RETURN_ATTR, 0)
fi 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 If the building compiler enables no direct external data access by
dnl default, access to protected data in shared libraries from executables dnl default, access to protected data in shared libraries from executables

View File

@ -74,4 +74,84 @@ divss_inline_asm (float x, float y)
return x; 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 #endif