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. */
#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)))
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)

View 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);

View 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);

View 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);

48
sysdeps/x86/configure vendored
View 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

View 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

View 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