From 1868599f8daf7798018ce8a8f314015f5a2ac520 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Wed, 22 Apr 2020 19:17:15 +0200 Subject: libgfortran: Provide some further math library fallbacks [PR94694] The following patch provides some further math library fallbacks. fmaf can be implemented using fma if available, fma and fmal can use x * y + z as fallback, it is not perfect, but e.g. glibc on various arches has been using that as fallback for many years, and copysign/copysignl/fabs/fabsl can be implemented using corresponding __builtin_* if we make sure that gcc expands it inline instead of using a library call (these days it is expanded inline on most targets). 2020-04-22 Jakub Jelinek PR libfortran/94694 PR libfortran/94586 * configure.ac: Add math func checks for fmaf, fma and fmal. Add HAVE_INLINE_BUILTIN_COPYSIGN check. * c99_protos.h (copysign, fmaf, fma, fmal): Provide fallback prototypes. (HAVE_COPYSIGN, HAVE_FMAF, HAVE_FMA, HAVE_FMAL): Define if not defined and fallback version is provided. * intrinsics/c99_functions.c (copysign, fmaf, fma, fmal): Provide fallback implementations if possible * configure: Regenerated. * config.h.in: Regenerated. * math.m4 (GCC_CHECK_MATH_INLINE_BUILTIN_FALLBACK1, GCC_CHECK_MATH_INLINE_BUILTIN_FALLBACK2): New. --- libgfortran/ChangeLog | 15 ++ libgfortran/c99_protos.h | 34 ++++ libgfortran/config.h.in | 21 +++ libgfortran/configure | 325 +++++++++++++++++++++++++++++++++ libgfortran/configure.ac | 8 + libgfortran/intrinsics/c99_functions.c | 77 ++++++++ 6 files changed, 480 insertions(+) (limited to 'libgfortran') diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 2ca75f190bc..e4d3756f0ca 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,18 @@ +2020-04-22 Jakub Jelinek + + PR libfortran/94694 + PR libfortran/94586 + * configure.ac: Add math func checks for fmaf, fma and fmal. Add + HAVE_INLINE_BUILTIN_COPYSIGN check. + * c99_protos.h (copysign, fmaf, fma, fmal): Provide fallback + prototypes. + (HAVE_COPYSIGN, HAVE_FMAF, HAVE_FMA, HAVE_FMAL): Define if not + defined and fallback version is provided. + * intrinsics/c99_functions.c (copysign, fmaf, fma, fmal): Provide + fallback implementations if possible + * configure: Regenerated. + * config.h.in: Regenerated. + 2020-04-19 Uroš Bizjak * config/fpu-387.h (local_feraiseexcept) [__SSE_MATH__]: diff --git a/libgfortran/c99_protos.h b/libgfortran/c99_protos.h index 7b0bc720de3..1ffc645cfeb 100644 --- a/libgfortran/c99_protos.h +++ b/libgfortran/c99_protos.h @@ -71,6 +71,16 @@ extern float ceilf(float); extern float copysignf(float, float); #endif +#if !defined(HAVE_COPYSIGN) && defined(HAVE_INLINE_BUILTIN_COPYSIGN) +#define HAVE_COPYSIGN 1 +extern double copysign(double, double); +#endif + +#if !defined(HAVE_COPYSIGNL) && defined(HAVE_INLINE_BUILTIN_COPYSIGNL) +#define HAVE_COPYSIGNL 1 +extern long double copysignl(long double, long double); +#endif + #ifndef HAVE_COSF #define HAVE_COSF 1 extern float cosf(float); @@ -91,6 +101,16 @@ extern float expf(float); extern float fabsf(float); #endif +#if !defined(HAVE_FABS) && defined(HAVE_INLINE_BUILTIN_FABS) +#define HAVE_FABS 1 +extern double fabs(double); +#endif + +#if !defined(HAVE_FABSL) && defined(HAVE_INLINE_BUILTIN_FABSL) +#define HAVE_FABSL 1 +extern long double fabsl(long double); +#endif + #ifndef HAVE_FLOORF #define HAVE_FLOORF 1 extern float floorf(float); @@ -628,6 +648,20 @@ extern float tgammaf (float); extern float lgammaf (float); #endif +#ifndef HAVE_FMA +#define HAVE_FMA 1 +extern double fma(double, double, double); +#endif + +#ifndef HAVE_FMAF +#define HAVE_FMAF 1 +extern float fmaf(float, float, float); +#endif + +#ifndef HAVE_FMAL +#define HAVE_FMAL 1 +extern long double fmal(long double, long double, long double); +#endif #endif /* C99_PROTOS_H */ diff --git a/libgfortran/config.h.in b/libgfortran/config.h.in index 44786399987..2d58188e50c 100644 --- a/libgfortran/config.h.in +++ b/libgfortran/config.h.in @@ -381,12 +381,21 @@ /* Define to 1 if you have the `floorl' function. */ #undef HAVE_FLOORL +/* Define to 1 if you have the `fma' function. */ +#undef HAVE_FMA + /* Define if FMA3 instructions can be compiled. */ #undef HAVE_FMA3 /* Define if FMA4 instructions can be compiled. */ #undef HAVE_FMA4 +/* Define to 1 if you have the `fmaf' function. */ +#undef HAVE_FMAF + +/* Define to 1 if you have the `fmal' function. */ +#undef HAVE_FMAL + /* Define to 1 if you have the `fmod' function. */ #undef HAVE_FMOD @@ -504,6 +513,18 @@ /* Define to 1 if you have the header file. */ #undef HAVE_IEEEFP_H +/* Define to 1 if `__builtin_copysign' is expanded inline. */ +#undef HAVE_INLINE_BUILTIN_COPYSIGN + +/* Define to 1 if `__builtin_copysignl' is expanded inline. */ +#undef HAVE_INLINE_BUILTIN_COPYSIGNL + +/* Define to 1 if `__builtin_fabs' is expanded inline. */ +#undef HAVE_INLINE_BUILTIN_FABS + +/* Define to 1 if `__builtin_fabsl' is expanded inline. */ +#undef HAVE_INLINE_BUILTIN_FABSL + /* Define to 1 if the system has the type `intptr_t'. */ #undef HAVE_INTPTR_T diff --git a/libgfortran/configure b/libgfortran/configure index d01654e7c4b..b4cf854ddb3 100755 --- a/libgfortran/configure +++ b/libgfortran/configure @@ -19848,6 +19848,150 @@ _ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmaf" >&5 +$as_echo_n "checking for fmaf... " >&6; } +if ${gcc_cv_math_func_fmaf+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_COMPLEX_H +#include +#endif +#ifdef HAVE_MATH_H +#include +#endif + +int (*ptr)() = (int (*)())fmaf; + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_func_fmaf=yes +else + gcc_cv_math_func_fmaf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_math_func_fmaf" >&5 +$as_echo "$gcc_cv_math_func_fmaf" >&6; } + if test $gcc_cv_math_func_fmaf = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_FMAF 1 +_ACEOF + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fma" >&5 +$as_echo_n "checking for fma... " >&6; } +if ${gcc_cv_math_func_fma+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_COMPLEX_H +#include +#endif +#ifdef HAVE_MATH_H +#include +#endif + +int (*ptr)() = (int (*)())fma; + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_func_fma=yes +else + gcc_cv_math_func_fma=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_math_func_fma" >&5 +$as_echo "$gcc_cv_math_func_fma" >&6; } + if test $gcc_cv_math_func_fma = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_FMA 1 +_ACEOF + + fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmal" >&5 +$as_echo_n "checking for fmal... " >&6; } +if ${gcc_cv_math_func_fmal+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#ifdef HAVE_COMPLEX_H +#include +#endif +#ifdef HAVE_MATH_H +#include +#endif + +int (*ptr)() = (int (*)())fmal; + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_func_fmal=yes +else + gcc_cv_math_func_fmal=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_math_func_fmal" >&5 +$as_echo "$gcc_cv_math_func_fmal" >&6; } + if test $gcc_cv_math_func_fmal = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_FMAL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodf" >&5 $as_echo_n "checking for fmodf... " >&6; } if ${gcc_cv_math_func_fmodf+:} false; then : @@ -25559,6 +25703,187 @@ $as_echo "#define HAVE_CLOG 1" >>confdefs.h fi + + +if test $gcc_cv_math_func_copysign = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline __builtin_copysign" >&5 +$as_echo_n "checking for inline __builtin_copysign... " >&6; } +if ${gcc_cv_math_inline_builtin_copysign+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +double +copysign_fallback (double x, double y) +{ + return __builtin_copysign (x, y); +} + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_inline_builtin_copysign=yes +else + gcc_cv_math_inline_builtin_copysign=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_math_inline_builtin_copysign" >&5 +$as_echo "$gcc_cv_math_inline_builtin_copysign" >&6; } + if test $gcc_cv_math_inline_builtin_copysign = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_INLINE_BUILTIN_COPYSIGN 1 +_ACEOF + + fi +fi + + +if test $gcc_cv_math_func_copysignl = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline __builtin_copysignl" >&5 +$as_echo_n "checking for inline __builtin_copysignl... " >&6; } +if ${gcc_cv_math_inline_builtin_copysignl+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +long double +copysignl_fallback (long double x, long double y) +{ + return __builtin_copysignl (x, y); +} + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_inline_builtin_copysignl=yes +else + gcc_cv_math_inline_builtin_copysignl=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_math_inline_builtin_copysignl" >&5 +$as_echo "$gcc_cv_math_inline_builtin_copysignl" >&6; } + if test $gcc_cv_math_inline_builtin_copysignl = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_INLINE_BUILTIN_COPYSIGNL 1 +_ACEOF + + fi +fi + + +if test $gcc_cv_math_func_fabs = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline __builtin_fabs" >&5 +$as_echo_n "checking for inline __builtin_fabs... " >&6; } +if ${gcc_cv_math_inline_builtin_fabs+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +double +fabs_fallback (double x) +{ + return __builtin_fabs (x); +} + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_inline_builtin_fabs=yes +else + gcc_cv_math_inline_builtin_fabs=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_math_inline_builtin_fabs" >&5 +$as_echo "$gcc_cv_math_inline_builtin_fabs" >&6; } + if test $gcc_cv_math_inline_builtin_fabs = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_INLINE_BUILTIN_FABS 1 +_ACEOF + + fi +fi + + +if test $gcc_cv_math_func_fabsl = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline __builtin_fabsl" >&5 +$as_echo_n "checking for inline __builtin_fabsl... " >&6; } +if ${gcc_cv_math_inline_builtin_fabsl+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test x$gcc_no_link = xyes; then + as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +long double +fabsl_fallback (long double x) +{ + return __builtin_fabsl (x); +} + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_inline_builtin_fabsl=yes +else + gcc_cv_math_inline_builtin_fabsl=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_math_inline_builtin_fabsl" >&5 +$as_echo "$gcc_cv_math_inline_builtin_fabsl" >&6; } + if test $gcc_cv_math_inline_builtin_fabsl = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_INLINE_BUILTIN_FABSL 1 +_ACEOF + + fi +fi + # Check whether the system has a working stat() { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the target stat is reliable" >&5 diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac index b2b9ee994aa..711dc60ff78 100644 --- a/libgfortran/configure.ac +++ b/libgfortran/configure.ac @@ -392,6 +392,9 @@ GCC_CHECK_MATH_FUNC([cabsl]) GCC_CHECK_MATH_FUNC([floorf]) GCC_CHECK_MATH_FUNC([floor]) GCC_CHECK_MATH_FUNC([floorl]) +GCC_CHECK_MATH_FUNC([fmaf]) +GCC_CHECK_MATH_FUNC([fma]) +GCC_CHECK_MATH_FUNC([fmal]) GCC_CHECK_MATH_FUNC([fmodf]) GCC_CHECK_MATH_FUNC([fmod]) GCC_CHECK_MATH_FUNC([fmodl]) @@ -516,6 +519,11 @@ GCC_CHECK_MATH_FUNC([catanl]) # On AIX, clog is present in libm as __clog AC_CHECK_LIB([m],[__clog],[AC_DEFINE([HAVE_CLOG],[1],[libm includes clog])]) +GCC_CHECK_MATH_INLINE_BUILTIN_FALLBACK2([copysign], [double]) +GCC_CHECK_MATH_INLINE_BUILTIN_FALLBACK2([copysignl], [long double]) +GCC_CHECK_MATH_INLINE_BUILTIN_FALLBACK1([fabs], [double]) +GCC_CHECK_MATH_INLINE_BUILTIN_FALLBACK1([fabsl], [long double]) + # Check whether the system has a working stat() LIBGFOR_CHECK_WORKING_STAT diff --git a/libgfortran/intrinsics/c99_functions.c b/libgfortran/intrinsics/c99_functions.c index 3ec5aeb8e05..b75d1777c4c 100644 --- a/libgfortran/intrinsics/c99_functions.c +++ b/libgfortran/intrinsics/c99_functions.c @@ -229,6 +229,17 @@ ceilf (float x) } #endif +#if !defined(HAVE_COPYSIGN) && defined(HAVE_INLINE_BUILTIN_COPYSIGN) +#define HAVE_COPYSIGN 1 +double copysign (double x, double y); + +double +copysign (double x, double y) +{ + return __builtin_copysign (x, y); +} +#endif + #ifndef HAVE_COPYSIGNF #define HAVE_COPYSIGNF 1 float copysignf (float x, float y); @@ -240,6 +251,17 @@ copysignf (float x, float y) } #endif +#if !defined(HAVE_COPYSIGNL) && defined(HAVE_INLINE_BUILTIN_COPYSIGNL) +#define HAVE_COPYSIGNL 1 +long double copysignl (long double x, long double y); + +long double +copysignl (long double x, long double y) +{ + return __builtin_copysignl (x, y); +} +#endif + #ifndef HAVE_COSF #define HAVE_COSF 1 float cosf (float x); @@ -273,6 +295,17 @@ expf (float x) } #endif +#if !defined(HAVE_FABS) && defined(HAVE_INLINE_BUILTIN_FABS) +#define HAVE_FABS 1 +double fabs (double x); + +double +fabs (double x) +{ + return __builtin_fabs (x); +} +#endif + #ifndef HAVE_FABSF #define HAVE_FABSF 1 float fabsf (float x); @@ -284,6 +317,17 @@ fabsf (float x) } #endif +#if !defined(HAVE_FABSL) && defined(HAVE_INLINE_BUILTIN_FABSL) +#define HAVE_FABSL 1 +long double fabsl (long double x); + +long double +fabsl (long double x) +{ + return __builtin_fabsl (x); +} +#endif + #ifndef HAVE_FLOORF #define HAVE_FLOORF 1 float floorf (float x); @@ -2112,3 +2156,36 @@ lgammaf (float x) return (float) lgamma ((double) x); } #endif + +#ifndef HAVE_FMA +#define HAVE_FMA 1 +double fma (double, double, double); + +double +fma (double x, double y, double z) +{ + return x * y + z; +} +#endif + +#ifndef HAVE_FMAF +#define HAVE_FMAF 1 +float fmaf (float, float, float); + +float +fmaf (float x, float y, float z) +{ + return fma (x, y, z); +} +#endif + +#ifndef HAVE_FMAL +#define HAVE_FMAL 1 +long double fmal (long double, long double, long double); + +long double +fmal (long double x, long double y, long double z) +{ + return x * y + z; +} +#endif -- cgit v1.2.3