[gcc r17-2676] libgfortran: Add additional long double math support for hppa64-hpux*
John David Anglin via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:7c89181457dafe48203c0ce31a429c3e887dd378 commit r17-2676-g7c89181457dafe48203c0ce31a429c3e887dd378 Author: John David Anglin <[email protected]> Date: Thu Jul 23 22:06:50 2026 -0400 libgfortran: Add additional long double math support for hppa64-hpux* On hppa-hpux, we lack support for C99 math routines but the long double type conforms to the standard 16-byte IEEE (IEC 60559) specification. This allows us to use the quad routines from libquadmath. 2026-07-22 John David Anglin <[email protected]> libgfortran/ChangeLog: PR libfortran/126305 * c99_protos.h (acosl, acoshl, asinl, asinhl,atan2l, atanl, atanhl, ceill, cosl, coshl, expl, hypotl, logl, sinl, sinhl, sqrtl, tanl, tanhl, truncl, nextafterl, powl, erfl, erfcl): Add declarations. * configure.ac (powl, erfl): Add GCC_CHECK_MATH_FUNCs. * configure: Regenerate. * config.h.in: Regenerate. * intrinsics/c99_functions.c: Include math_imp.h. Move code to manipulate the floating-point type to math_imp.h. (erfl, erfcl, acosl, acoshl, asinl, asinhl, atan2l, atanl, atanhl, ceill, cosl, coshl, expl, floorl, fmodl, hypotl, logl, sinl, sinhl, sqrtl, tanl, tanhl, truncl, nextafterl, powl, log10l): Implement. (frexpl): Move code to intrinsics/frexpl_16.c. (scalbnl): Move code to intrinsics/scalbnl_16.c. * intrinsics/ceill_16.c: New. * intrinsics/floorl_16.c: New. * intrinsics/frexpl_16.c: New. * intrinsics/math_imp.h: New. * intrinsics/nextafterl_16.c: New. * intrinsics/scalbnl_16.c: New. * intrinsics/truncl_16.c: New. * libgfortran.h (USE_LIBQUADLIB): Define on hppa-hpux. Diff: --- libgfortran/c99_protos.h | 122 +++++- libgfortran/config.h.in | 6 + libgfortran/configure | 96 +++++ libgfortran/configure.ac | 2 + libgfortran/intrinsics/c99_functions.c | 674 +++++++++++++++++++-------------- libgfortran/intrinsics/ceill_16.c | 91 +++++ libgfortran/intrinsics/floorl_16.c | 88 +++++ libgfortran/intrinsics/frexpl_16.c | 39 ++ libgfortran/intrinsics/math_imp.h | 170 +++++++++ libgfortran/intrinsics/nextafterl_16.c | 108 ++++++ libgfortran/intrinsics/scalbnl_16.c | 61 +++ libgfortran/intrinsics/truncl_16.c | 50 +++ libgfortran/libgfortran.h | 8 + 13 files changed, 1222 insertions(+), 293 deletions(-) diff --git a/libgfortran/c99_protos.h b/libgfortran/c99_protos.h index 952b251c31ab..a233991b60dc 100644 --- a/libgfortran/c99_protos.h +++ b/libgfortran/c99_protos.h @@ -37,41 +37,84 @@ extern size_t strnlen(const char *, size_t); extern float acosf(float); #endif +/* On HPUX, some long double functions are mapped to functions in + libquadmath, e.g., acosl(x) maps to acosq((__float128)x). */ + +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ACOS)) && !defined(HAVE_ACOSL) +#define HAVE_ACOSL 1 +extern long double acosl(long double); +#endif + #if HAVE_ACOSH && !HAVE_ACOSHF #define HAVE_ACOSHF 1 extern float acoshf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ACOS)) && !defined(HAVE_ACOSHL) +#define HAVE_ACOSHL 1 +extern long double acoshl(long double); +#endif + #ifndef HAVE_ASINF #define HAVE_ASINF 1 extern float asinf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ASIN)) && !defined(HAVE_ASINL) +#define HAVE_ASINL 1 +extern long double asinl(long double); +#endif + #if HAVE_ASINH && !HAVE_ASINHF #define HAVE_ASINHF 1 extern float asinhf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ASINH)) && !defined(HAVE_ASINHL) +#define HAVE_ASINHL 1 +extern long double asinhl(long double); +#endif + #ifndef HAVE_ATAN2F #define HAVE_ATAN2F 1 extern float atan2f(float, float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ATAN2)) && !defined(HAVE_ATAN2L) +#define HAVE_ATAN2L 1 +extern long double atan2l(long double, long double); +#endif + #ifndef HAVE_ATANF #define HAVE_ATANF 1 extern float atanf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ATAN)) && !defined(HAVE_ATANL) +#define HAVE_ATANL 1 +extern long double atanl(long double); +#endif + #if HAVE_ATANH && !HAVE_ATANHF #define HAVE_ATANHF 1 extern float atanhf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ATANH)) && !defined(HAVE_ATANHL) +#define HAVE_ATANHL 1 +extern long double atanhl (long double); +#endif + #ifndef HAVE_CEILF #define HAVE_CEILF 1 extern float ceilf(float); #endif +#if !defined(HAVE_CEILL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) +#define HAVE_CEILL 1 +extern long double ceill(long double); +#endif + #ifndef HAVE_COPYSIGNF #define HAVE_COPYSIGNF 1 extern float copysignf(float, float); @@ -92,16 +135,31 @@ extern long double copysignl(long double, long double); extern float cosf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_COS)) && !defined(HAVE_COSL) +#define HAVE_COSL 1 +extern long double cosl (long double); +#endif + #ifndef HAVE_COSHF #define HAVE_COSHF 1 extern float coshf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_COSH)) && !defined(HAVE_COSHL) +#define HAVE_COSHL 1 +extern long double coshl(long double); +#endif + #ifndef HAVE_EXPF #define HAVE_EXPF 1 extern float expf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_EXP)) && !defined(HAVE_EXPL) +#define HAVE_EXPL 1 +extern long double expl(long double); +#endif + #ifndef HAVE_FABSF #define HAVE_FABSF 1 extern float fabsf(float); @@ -142,7 +200,7 @@ extern long double fmodl (long double x, long double y); extern float frexpf(float, int *); #endif -#ifndef HAVE_FREXPL +#if !defined(HAVE_FREXPL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) #define HAVE_FREXPL 1 extern long double frexpl(long double, int *); #endif @@ -152,11 +210,21 @@ extern long double frexpl(long double, int *); extern float hypotf(float, float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_HYPOT)) && !defined(HAVE_HYPOTL) +#define HAVE_HYPOTL 1 +extern long double hypotl(long double, long double); +#endif + #ifndef HAVE_LOGF #define HAVE_LOGF 1 extern float logf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_LOG)) && !defined(HAVE_LOGL) +#define HAVE_LOGL 1 +extern long double logl(long double); +#endif + #ifndef HAVE_LOG10F #define HAVE_LOG10F 1 extern float log10f(float); @@ -172,7 +240,7 @@ extern double scalbn(double, int); extern float scalbnf(float, int); #endif -#ifndef HAVE_SCALBNL +#if !defined(HAVE_SCALBNL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) #define HAVE_SCALBNL 1 extern long double scalbnl(long double, int); #endif @@ -182,26 +250,51 @@ extern long double scalbnl(long double, int); extern float sinf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_SIN)) && !defined(HAVE_SINL) +#define HAVE_SINL 1 +extern long double sinl(long double); +#endif + #ifndef HAVE_SINHF #define HAVE_SINHF 1 extern float sinhf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_SINH)) && !defined(HAVE_SINHL) +#define HAVE_SINHL 1 +extern long double sinhl(long double); +#endif + #ifndef HAVE_SQRTF #define HAVE_SQRTF 1 extern float sqrtf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_SQRT)) && !defined(HAVE_SQRTL) +#define HAVE_SQRTL 1 +extern long double sqrtl(long double); +#endif + #ifndef HAVE_TANF #define HAVE_TANF 1 extern float tanf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_TAN)) && !defined(HAVE_TANL) +#define HAVE_TANL 1 +extern long double tanl(long double); +#endif + #ifndef HAVE_TANHF #define HAVE_TANHF 1 extern float tanhf(float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_TANH)) && !defined(HAVE_TANHL) +#define HAVE_TANHL 1 +extern long double tanhl(long double); +#endif + #ifndef HAVE_TRUNC #define HAVE_TRUNC 1 extern double trunc(double); @@ -212,16 +305,31 @@ extern double trunc(double); extern float truncf(float); #endif +#if !defined(HAVE_TRUNCL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) +#define HAVE_TRUNCL 1 +extern long double truncl(long double); +#endif + #ifndef HAVE_NEXTAFTERF #define HAVE_NEXTAFTERF 1 extern float nextafterf(float, float); #endif +#if !defined(HAVE_NEXTAFTERL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) +#define HAVE_NEXTAFTERL 1 +extern long double nextafterl(long double, long double); +#endif + #ifndef HAVE_POWF #define HAVE_POWF 1 extern float powf(float, float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_POW)) && !defined(HAVE_POWL) +#define HAVE_POWL 1 +extern long double powl(long double, long double); +#endif + #ifndef HAVE_ROUND #define HAVE_ROUND 1 extern double round(double); @@ -310,11 +418,21 @@ extern float ynf (int, float); extern float erff (float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ERF)) && !defined(HAVE_ERFL) +#define HAVE_ERFL 1 +long double erfl(long double); +#endif + #if defined(HAVE_ERFC) && !defined(HAVE_ERFCF) #define HAVE_ERFCF 1 extern float erfcf (float); #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ERFC)) && !defined(HAVE_ERFCL) +#define HAVE_ERFL 1 +long double erfcl(long double); +#endif + /* log10l is needed on all platforms for decimal I/O */ diff --git a/libgfortran/config.h.in b/libgfortran/config.h.in index 240a1762de32..1d4bbfbb4a9e 100644 --- a/libgfortran/config.h.in +++ b/libgfortran/config.h.in @@ -435,6 +435,9 @@ /* Define to 1 if you have the `erff128' function. */ #undef HAVE_ERFF128 +/* Define to 1 if you have the `erfl' function. */ +#undef HAVE_ERFL + /* Define to 1 if you have the `exp' function. */ #undef HAVE_EXP @@ -810,6 +813,9 @@ /* Define to 1 if you have the `powf128' function. */ #undef HAVE_POWF128 +/* Define to 1 if you have the `powl' function. */ +#undef HAVE_POWL + /* Have PTHREAD_PRIO_INHERIT. */ #undef HAVE_PTHREAD_PRIO_INHERIT diff --git a/libgfortran/configure b/libgfortran/configure index 7820988523e3..6d31fa11be2a 100755 --- a/libgfortran/configure +++ b/libgfortran/configure @@ -22860,6 +22860,54 @@ _ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl" >&5 +$as_echo_n "checking for powl... " >&6; } +if ${gcc_cv_math_func_powl+:} 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 <complex.h> +#endif +#ifdef HAVE_MATH_H +#include <math.h> +#endif + +int (*ptr)() = (int (*)())powl; + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_func_powl=yes +else + gcc_cv_math_func_powl=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_powl" >&5 +$as_echo "$gcc_cv_math_func_powl" >&6; } + if test $gcc_cv_math_func_powl = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_POWL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cpowf" >&5 $as_echo_n "checking for cpowf... " >&6; } if ${gcc_cv_math_func_cpowf+:} false; then : @@ -25260,6 +25308,54 @@ _ACEOF + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erfl" >&5 +$as_echo_n "checking for erfl... " >&6; } +if ${gcc_cv_math_func_erfl+:} 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 <complex.h> +#endif +#ifdef HAVE_MATH_H +#include <math.h> +#endif + +int (*ptr)() = (int (*)())erfl; + +int +main () +{ + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gcc_cv_math_func_erfl=yes +else + gcc_cv_math_func_erfl=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_erfl" >&5 +$as_echo "$gcc_cv_math_func_erfl" >&6; } + if test $gcc_cv_math_func_erfl = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_ERFL 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for erfcf" >&5 $as_echo_n "checking for erfcf... " >&6; } if ${gcc_cv_math_func_erfcf+:} false; then : diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac index 9acb323469e7..c5f84a031cd3 100644 --- a/libgfortran/configure.ac +++ b/libgfortran/configure.ac @@ -470,6 +470,7 @@ GCC_CHECK_MATH_FUNC([nextafter]) GCC_CHECK_MATH_FUNC([nextafterl]) GCC_CHECK_MATH_FUNC([powf]) GCC_CHECK_MATH_FUNC([pow]) +GCC_CHECK_MATH_FUNC([powl]) GCC_CHECK_MATH_FUNC([cpowf]) GCC_CHECK_MATH_FUNC([cpow]) GCC_CHECK_MATH_FUNC([cpowl]) @@ -520,6 +521,7 @@ GCC_CHECK_MATH_FUNC([trunc]) GCC_CHECK_MATH_FUNC([truncl]) GCC_CHECK_MATH_FUNC([erff]) GCC_CHECK_MATH_FUNC([erf]) +GCC_CHECK_MATH_FUNC([erfl]) GCC_CHECK_MATH_FUNC([erfcf]) GCC_CHECK_MATH_FUNC([erfc]) GCC_CHECK_MATH_FUNC([erfcl]) diff --git a/libgfortran/intrinsics/c99_functions.c b/libgfortran/intrinsics/c99_functions.c index 28acadb5f9f0..ab3920702b95 100644 --- a/libgfortran/intrinsics/c99_functions.c +++ b/libgfortran/intrinsics/c99_functions.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define C99_PROTOS_H WE_DONT_WANT_PROTOS_NOW #include "libgfortran.h" +#include "math_imp.h" /* On a C99 system "I" (with I*I = -1) should be defined in complex.h; if not, we define a fallback version here. */ @@ -48,138 +49,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* Prototypes are included to silence -Wstrict-prototypes -Wmissing-prototypes. */ -/* Main union type we use to manipulate the floating-point type. */ -typedef union -{ - long double value; - - struct -#ifdef __MINGW32__ - /* On mingw targets the ms-bitfields option is active by default. - Therefore enforce gnu-bitfield style. */ - __attribute__ ((gcc_struct)) -#endif - { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - unsigned negative:1; - unsigned exponent:15; - unsigned mantissa0:16; - unsigned mantissa1:32; - unsigned mantissa2:32; - unsigned mantissa3:32; -#else - unsigned mantissa3:32; - unsigned mantissa2:32; - unsigned mantissa1:32; - unsigned mantissa0:16; - unsigned exponent:15; - unsigned negative:1; -#endif - } ieee; - - struct - { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint64_t high; - uint64_t low; -#else - uint64_t low; - uint64_t high; -#endif - } words64; - - struct - { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - uint32_t w0; - uint32_t w1; - uint32_t w2; - uint32_t w3; -#else - uint32_t w3; - uint32_t w2; - uint32_t w1; - uint32_t w0; -#endif - } words32; - - struct -#ifdef __MINGW32__ - /* Make sure we are using gnu-style bitfield handling. */ - __attribute__ ((gcc_struct)) -#endif - { -#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - unsigned negative:1; - unsigned exponent:15; - unsigned quiet_nan:1; - unsigned mantissa0:15; - unsigned mantissa1:32; - unsigned mantissa2:32; - unsigned mantissa3:32; -#else - unsigned mantissa3:32; - unsigned mantissa2:32; - unsigned mantissa1:32; - unsigned mantissa0:15; - unsigned quiet_nan:1; - unsigned exponent:15; - unsigned negative:1; -#endif - } ieee_nan; - -} ieee754_long_double; - - -/* Get two 64 bit ints from a long double. */ -#define GET_LDOUBLE_WORDS64(ix0,ix1,d) \ -do { \ - ieee754_long_double u; \ - u.value = (d); \ - (ix0) = u.words64.high; \ - (ix1) = u.words64.low; \ -} while (0) - -/* Set a long double from two 64 bit ints. */ -#define SET_LDOUBLE_WORDS64(d,ix0,ix1) \ -do { \ - ieee754_long_double u; \ - u.words64.high = (ix0); \ - u.words64.low = (ix1); \ - (d) = u.value; \ -} while (0) - -/* Get the more significant 64 bits of a long double mantissa. */ -#define GET_LDOUBLE_MSW64(v,d) \ -do { \ - ieee754_long_double u; \ - u.value = (d); \ - (v) = u.words64.high; \ -} while (0) - -/* Set the more significant 64 bits of a long double mantissa from an int. */ -#define SET_LDOUBLE_MSW64(d,v) \ -do { \ - ieee754_long_double u; \ - u.value = (d); \ - u.words64.high = (v); \ - (d) = u.value; \ -} while (0) - -/* Get the least significant 64 bits of a long double mantissa. */ -#define GET_LDOUBLE_LSW64(v,d) \ -do { \ - ieee754_long_double u; \ - u.value = (d); \ - (v) = u.words64.low; \ -} while (0) - -static const long double -two114 = 2.0769187434139310514121985316880384E+34L, /* 0x4071000000000000, 0 */ -twom114 = 4.8148248609680896326399448564623183E-35L, /* 0x3F8D000000000000, 0 */ -huge = 1.0E+4900L, -tiny = 1.0E-4900L; - /* Wrapper for systems without strnlen function. */ #ifndef HAVE_STRNLEN @@ -276,6 +145,25 @@ erff (float x) } #endif +/* On HPUX, some long double functions are mapped to functions in + libquadmath, e.g., erfl(x) maps to erfq((__float128)x). */ + +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ERF)) && !defined(HAVE_ERFL) +#define HAVE_ERFL 1 +long double erfl (long double); + +long double +erfl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) erfq ((__float128) x); +#else + return (long double) erf ((double) x); +#endif +} +#endif + + #if defined(HAVE_ERFC) && !defined(HAVE_ERFCF) #define HAVE_ERFCF 1 float erfcf (float); @@ -287,6 +175,21 @@ erfcf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ERFC)) && !defined(HAVE_ERFCL) +#define HAVE_ERFCL 1 +long double erfcl (long double); + +long double +erfcl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) erfcq ((__float128) x); +#else + return (long double) erfc ((double) x); +#endif +} +#endif + #ifndef HAVE_ACOSF #define HAVE_ACOSF 1 @@ -299,6 +202,21 @@ acosf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ACOS)) && !defined(HAVE_ACOSL) +#define HAVE_ACOSL 1 +long double acosl (long double); + +long double +acosl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) acosq ((__float128) x); +#else + return (long double) acos ((double) x); +#endif +} +#endif + #if HAVE_ACOSH && !HAVE_ACOSHF float acoshf (float x); @@ -309,6 +227,21 @@ acoshf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ACOS)) && !defined(HAVE_ACOSHL) +#define HAVE_ACOSHL 1 +long double acoshl (long double); + +long double +acoshl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) acoshq ((__float128) x); +#else + return (long double) acosh ((double) x); +#endif +} +#endif + #ifndef HAVE_ASINF #define HAVE_ASINF 1 float asinf (float x); @@ -320,6 +253,21 @@ asinf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ASIN)) && !defined(HAVE_ASINL) +#define HAVE_ASINL 1 +long double asinl(long double); + +long double +asinl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) asinq ((__float128) x); +#else + return (long double) asin ((double) x); +#endif +} +#endif + #if HAVE_ASINH && !HAVE_ASINHF float asinhf (float x); @@ -330,6 +278,21 @@ asinhf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ASINH)) && !defined(HAVE_ASINHL) +#define HAVE_ASINHL 1 +long double asinhl(long double); + +long double +asinhl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) asinhq ((__float128) x); +#else + return (long double) asinh ((double) x); +#endif +} +#endif + #ifndef HAVE_ATAN2F #define HAVE_ATAN2F 1 float atan2f (float y, float x); @@ -341,6 +304,21 @@ atan2f (float y, float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ATAN2)) && !defined(HAVE_ATAN2L) +#define HAVE_ATAN2L 1 +long double atan2l(long double, long double); + +long double +atan2l (long double x, long double y) +{ +#if defined(USE_LIBQUADLIB) + return (long double) atan2q ((__float128) x, (__float128) y); +#else + return (long double) atan2 ((double) x, (double) y); +#endif +} +#endif + #ifndef HAVE_ATANF #define HAVE_ATANF 1 float atanf (float x); @@ -352,6 +330,21 @@ atanf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ATAN)) && !defined(HAVE_ATANL) +#define HAVE_ATANL 1 +long double atanl (long double); + +long double +atanl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) atanq ((__float128) x); +#else + return (long double) atan ((double) x); +#endif +} +#endif + #if HAVE_ATANH && !HAVE_ATANHF float atanhf (float x); @@ -362,6 +355,21 @@ atanhf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_ATANH)) && !defined(HAVE_ATANHL) +#define HAVE_ATANHL 1 +long double atanhl (long double); + +long double +atanhl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) atanhq ((__float128) x); +#else + return (long double) atanh ((double) x); +#endif +} +#endif + #ifndef HAVE_CEILF #define HAVE_CEILF 1 float ceilf (float x); @@ -373,6 +381,13 @@ ceilf (float x) } #endif +#if !defined(HAVE_CEILL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) +#define HAVE_CEILL 1 +long double ceill (long double); +#include "ceill_16.c" +#endif + + #if !defined(HAVE_COPYSIGN) && defined(HAVE_INLINE_BUILTIN_COPYSIGN) #define HAVE_COPYSIGN 1 double copysign (double x, double y); @@ -417,6 +432,21 @@ cosf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_COS)) && !defined(HAVE_COSL) +#define HAVE_COSL 1 +long double cosl (long double); + +long double +cosl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) cosq ((__float128) x); +#else + return (long double) cos ((double) x); +#endif +} +#endif + #ifndef HAVE_COSHF #define HAVE_COSHF 1 float coshf (float x); @@ -428,6 +458,21 @@ coshf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_COSH)) && !defined(HAVE_COSHL) +#define HAVE_COSHL 1 +long double coshl (long double); + +long double +coshl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) coshq ((__float128) x); +#else + return (long double) cosh ((double) x); +#endif +} +#endif + #ifndef HAVE_EXPF #define HAVE_EXPF 1 float expf (float x); @@ -439,6 +484,21 @@ expf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_EXP)) && !defined(HAVE_EXPL) +#define HAVE_EXPL 1 +long double expl (long double); + +long double +expl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) expq ((__float128) x); +#else + return (long double) exp ((double) x); +#endif +} +#endif + #if !defined(HAVE_FABS) && defined(HAVE_INLINE_BUILTIN_FABS) #define HAVE_FABS 1 double fabs (double x); @@ -483,6 +543,37 @@ floorf (float x) } #endif +#if !defined(HAVE_FLOORL) +#define HAVE_FLOORL 1 +long double floorl (long double); + +#if (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) +#include "floorl_16.c" +#else +long double +floorl (long double x); +{ + /* Zero, possibly signed. */ + if (x == 0) + return x; + + /* Large magnitude. */ + if (x > DBL_MAX || x < (-DBL_MAX)) + return x; + + /* Small positive values. */ + if (x >= 0 && x < DBL_MIN) + return 0; + + /* Small negative values. */ + if (x < 0 && x > (-DBL_MIN)) + return -1; + + return floor (x); +} +#endif +#endif + #ifndef HAVE_FMODF #define HAVE_FMODF 1 float fmodf (float x, float y); @@ -494,6 +585,26 @@ fmodf (float x, float y) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_FLOORL)) && !defined(HAVE_FMODL) +#define HAVE_FMODL 1 +long double fmodl (long double, long double); + +long double +fmodl (long double x, long double y) +{ +#if defined(USE_LIBQUADLIB) + return (long double) fmodq ((__float128) x, (__float128) y); +#else + if (y == 0.0L) + return 0.0L; + + /* Need to check that the result has the same sign as x and magnitude + less than the magnitude of y. */ + return x - floorl (x / y) * y; +#endif +} +#endif + #ifndef HAVE_FREXPF #define HAVE_FREXPF 1 float frexpf (float x, int *exp); @@ -505,55 +616,10 @@ frexpf (float x, int *exp) } #endif -#if !defined(HAVE_FREXPL) +#if !defined(HAVE_FREXPL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) #define HAVE_FREXPL 1 -long double frexpl (long double x, int *eptr); - -/* s_frexpl.c -- long double version of s_frexp.c. - * Conversion to IEEE quad long double by Jakub Jelinek, [email protected]. - */ - -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -long double -frexpl (long double x, int *eptr) -{ - if (sizeof (long double) == 16) - { - uint64_t hx, lx, ix; - - GET_LDOUBLE_WORDS64(hx,lx,x); - ix = 0x7fffffffffffffffULL&hx; - *eptr = 0; - if(ix >= 0x7fff000000000000ULL || ((ix|lx) == 0)) - /* 0,inf,nan */ - return x + x; - if (ix < 0x0001000000000000ULL) - { - /* subnormal */ - x *= two114; - GET_LDOUBLE_MSW64(hx,x); - ix = hx & 0x7fffffffffffffffULL; - *eptr = -114; - } - *eptr += (ix>>48) - 16382; - hx = (hx & 0x8000ffffffffffffULL) | 0x3ffe000000000000ULL; - SET_LDOUBLE_MSW64(x,hx); - return x; - } - else - /* Intel 80 bit */ - abort(); -} +long double frexpl (long double, int *); +#include "frexpl_16.c" #endif #ifndef HAVE_HYPOTF @@ -567,6 +633,21 @@ hypotf (float x, float y) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_HYPOT)) && !defined(HAVE_HYPOTL) +#define HAVE_HYPOTL 1 +long double hypotl (long double, long double); + +long double +hypotl (long double x, long double y) +{ +#if defined(USE_LIBQUADLIB) + return (long double) hypotq ((__float128) x, (__float128) y); +#else + return (long double) hypot ((double) x, (double) y); +#endif +} +#endif + #ifndef HAVE_LOGF #define HAVE_LOGF 1 float logf (float x); @@ -578,6 +659,21 @@ logf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_LOG)) && !defined(HAVE_LOGL) +#define HAVE_LOGL 1 +long double logl (long double); + +long double +logl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) logq ((__float128) x); +#else + return (long double) log ((double) x); +#endif +} +#endif + #ifndef HAVE_LOG10F #define HAVE_LOG10F 1 float log10f (float x); @@ -615,74 +711,10 @@ scalbnf (float x, int y) } #endif -#if !defined(HAVE_SCALBNL) +#if !defined(HAVE_SCALBNL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) #define HAVE_SCALBNL 1 -long double scalbnl (long double x, int n); - -/* s_scalbnl.c -- long double version of s_scalbn.c. - * Conversion to IEEE quad long double by Jakub Jelinek, [email protected]. - */ - -/* @(#)s_scalbn.c 5.1 93/09/24 */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -long double -scalbnl (long double x, int n) -{ - if (sizeof (long double) == 16) - { - int64_t k, hx, lx; - - GET_LDOUBLE_WORDS64(hx,lx,x); - - /* extract exponent */ - k = (hx >> 48) & 0x7fff; - if (k == 0) - { - /* 0 or subnormal x */ - if ((lx | (hx & 0x7fffffffffffffffULL)) == 0) - return x; /* +-0 */ - x *= two114; - GET_LDOUBLE_MSW64(hx,x); - k = ((hx >> 48) & 0x7fff) - 114; - } - if (k == 0x7fff) - /* NaN or Inf */ - return x+x; - if (n < -50000) - /*underflow*/ - return tiny * copysignl (tiny, x); - if (n > 50000 || k + n > 0x7ffe) - /* overflow */ - return huge * copysignl (huge, x); - /* Now k and n are bounded we know that k = k+n does not overflow. */ - k = k + n; - if (k > 0) - { - /* normal result */ - SET_LDOUBLE_MSW64(x,(hx&0x8000ffffffffffffULL)|(k<<48)); - return x; - } - if (k <= -114) - /*underflow*/ - return tiny * copysignl (tiny, x); - k += 114; /* subnormal result */ - SET_LDOUBLE_MSW64(x,(hx&0x8000ffffffffffffULL)|(k<<48)); - return x * twom114; - } - else - /* Intel 80 bit */ - abort(); -} +long double scalbnl (long double, int); +#include "scalbnl_16.c" #endif #ifndef HAVE_SINF @@ -696,6 +728,21 @@ sinf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_SIN)) && !defined(HAVE_SINL) +#define HAVE_SINL 1 +long double sinl(long double); + +long double +sinl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) sinq ((__float128) x); +#else + return (long double) sin ((double) x); +#endif +} +#endif + #ifndef HAVE_SINHF #define HAVE_SINHF 1 float sinhf (float x); @@ -707,6 +754,21 @@ sinhf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_SINH)) && !defined(HAVE_SINHL) +#define HAVE_SINHL 1 +long double sinhl(long double); + +long double +sinhl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) sinhq ((__float128) x); +#else + return (long double) sinh ((double) x); +#endif +} +#endif + #ifndef HAVE_SQRTF #define HAVE_SQRTF 1 float sqrtf (float x); @@ -718,6 +780,21 @@ sqrtf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_SQRT)) && !defined(HAVE_SQRTL) +#define HAVE_SQRTL 1 +long double sqrtl(long double); + +long double +sqrtl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) sqrtq ((__float128) x); +#else + return (long double) sqrt ((double) x); +#endif +} +#endif + #ifndef HAVE_TANF #define HAVE_TANF 1 float tanf (float x); @@ -729,6 +806,21 @@ tanf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_TAN)) && !defined(HAVE_TANL) +#define HAVE_TANL 1 +long double tanl(long double); + +long double +tanl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) tanq ((__float128) x); +#else + return (long double) tan ((double) x); +#endif +} +#endif + #ifndef HAVE_TANHF #define HAVE_TANHF 1 float tanhf (float x); @@ -740,6 +832,21 @@ tanhf (float x) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_TANH)) && !defined(HAVE_TANHL) +#define HAVE_TANHL 1 +long double tanhl(long double); + +long double +tanhl (long double x) +{ +#if defined(USE_LIBQUADLIB) + return (long double) tanhq ((__float128) x); +#else + return (long double) tanh ((double) x); +#endif +} +#endif + #ifndef HAVE_TRUNC #define HAVE_TRUNC 1 double trunc (double x); @@ -768,6 +875,12 @@ truncf (float x) } #endif +#if !defined(HAVE_TRUNCL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) +#define HAVE_TRUNCL 1 +long double truncl(long double); +#include "truncl_16.c" +#endif + #ifndef HAVE_NEXTAFTERF #define HAVE_NEXTAFTERF 1 /* This is a portable implementation of nextafterf that is intended to be @@ -833,6 +946,11 @@ nextafterf (float x, float y) } #endif +#if !defined(HAVE_NEXTAFTERL) && (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) +#define HAVE_NEXTAFTERL 1 +long double nextafterl (long double, long double); +#include "nextafterl_16.c" +#endif #ifndef HAVE_POWF #define HAVE_POWF 1 @@ -845,6 +963,21 @@ powf (float x, float y) } #endif +#if (defined(USE_LIBQUADLIB) || defined(HAVE_POW)) && !defined(HAVE_POWL) +#define HAVE_POWL 1 +long double powl (long double, long double); + +long double +powl (long double x, long double y) +{ +#if defined(USE_LIBQUADLIB) + return (long double) powq ((__float128) x, (__float128) y); +#else + return (long double) pow ((double) x, (double) y); +#endif +} +#endif + #ifndef HAVE_ROUND #define HAVE_ROUND 1 @@ -1041,6 +1174,9 @@ long double log10l (long double x); long double log10l (long double x) { +#if defined(USE_LIBQUADLIB) + return (long double) log10q ((__float128) x); +#else #if LDBL_MAX_EXP > DBL_MAX_EXP if (x > DBL_MAX) { @@ -1070,51 +1206,7 @@ log10l (long double x) } #endif return log10 (x); -} #endif - - -#ifndef HAVE_FLOORL -#define HAVE_FLOORL 1 -long double floorl (long double x); - -long double -floorl (long double x) -{ - /* Zero, possibly signed. */ - if (x == 0) - return x; - - /* Large magnitude. */ - if (x > DBL_MAX || x < (-DBL_MAX)) - return x; - - /* Small positive values. */ - if (x >= 0 && x < DBL_MIN) - return 0; - - /* Small negative values. */ - if (x < 0 && x > (-DBL_MIN)) - return -1; - - return floor (x); -} -#endif - - -#ifndef HAVE_FMODL -#define HAVE_FMODL 1 -long double fmodl (long double x, long double y); - -long double -fmodl (long double x, long double y) -{ - if (y == 0.0L) - return 0.0L; - - /* Need to check that the result has the same sign as x and magnitude - less than the magnitude of y. */ - return x - floorl (x / y) * y; } #endif diff --git a/libgfortran/intrinsics/ceill_16.c b/libgfortran/intrinsics/ceill_16.c new file mode 100644 index 000000000000..40dd1fa09a6b --- /dev/null +++ b/libgfortran/intrinsics/ceill_16.c @@ -0,0 +1,91 @@ +/* s_ceill.c -- long double version of s_ceil.c. + * Conversion to IEEE quad long double by Jakub Jelinek, [email protected]. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * ceill(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + */ + +long double +ceill (long double x) +{ + int64_t i0, i1, j0; + uint64_t i, j; + + GET_LDOUBLE_WORDS64 (i0 ,i1 ,x); + j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; + if (j0 < 48) + { + if (j0 < 0) + { + /* return 0*sign(x) if |x|<1 */ + if (i0 < 0) + { + i0 = 0x8000000000000000ULL; + i1 = 0; + } + else if ((i0|i1) != 0) + { + i0 = 0x3fff000000000000ULL; + i1 = 0; + } + } + else + { + i = (0x0000ffffffffffffULL) >> j0; + if (((i0 & i) | i1) == 0) + /* x is integral */ + return x; + if (i0 > 0) + i0 += (0x0001000000000000LL) >> j0; + i0 &= (~i); + i1 = 0; + } + } + else if (j0 > 111) + { + if (j0 == 0x4000) + /* inf or NaN */ + return x+x; + else + /* x is integral */ + return x; + } + else + { + i = -1ULL >> (j0 - 48); + if ((i1 & i) == 0) + /* x is integral */ + return x; + if (i0 > 0) + { + if (j0 == 48) + i0 += 1; + else + { + j = i1 + (1LL << (112 - j0)); + if ((int64_t) j < i1) + /* got a carry */ + i0 += 1; + i1 = j; + } + } + i1 &= (~i); + } + SET_LDOUBLE_WORDS64 (x, i0, i1); + return x; +} diff --git a/libgfortran/intrinsics/floorl_16.c b/libgfortran/intrinsics/floorl_16.c new file mode 100644 index 000000000000..d07fee1dc077 --- /dev/null +++ b/libgfortran/intrinsics/floorl_16.c @@ -0,0 +1,88 @@ +/* s_floorl.c -- long double version of s_floor.c. + * Conversion to IEEE quad long double by Jakub Jelinek, [email protected]. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * floorl(x) + * Return x rounded toward -inf to integral value + * Method: + * Bit twiddling. + */ + +long double +floorl (long double x) +{ + int64_t i0, i1, j0; + uint64_t i, j; + + GET_LDOUBLE_WORDS64 (i0, i1, x); + j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; + if (j0 < 48) + { + if (j0 < 0) + { + /* return 0*sign(x) if |x|<1 */ + if (i0 >= 0) + i0 = i1 = 0; + else if (((i0 & 0x7fffffffffffffffLL) | i1) != 0) + { + i0 = 0xbfff000000000000ULL; + i1 = 0; + } + } + else + { + i = (0x0000ffffffffffffULL) >> j0; + if (((i0 & i) | i1) == 0) + /* x is integral */ + return x; + if (i0 < 0) + i0 += (0x0001000000000000LL) >> j0; + i0 &= (~i); + i1 = 0; + } + } + else if (j0 > 111) + { + if (j0 == 0x4000) + /* inf or NaN */ + return x + x; + else + /* x is integral */ + return x; + } + else + { + i = -1ULL >> (j0 - 48); + if ((i1 & i) == 0) + /* x is integral */ + return x; + if (i0 < 0) + { + if (j0 == 48) + i0 += 1; + else + { + j = i1 + (1LL << (112 - j0)); + if ((int64_t) j < i1) + /* got a carry */ + i0 += 1; + i1 = j; + } + } + i1 &= (~i); + } + SET_LDOUBLE_WORDS64 (x, i0, i1); + return x; +} diff --git a/libgfortran/intrinsics/frexpl_16.c b/libgfortran/intrinsics/frexpl_16.c new file mode 100644 index 000000000000..7f6bcc97f6bf --- /dev/null +++ b/libgfortran/intrinsics/frexpl_16.c @@ -0,0 +1,39 @@ +/* s_frexpl.c -- long double version of s_frexp.c. + * Conversion to IEEE quad long double by Jakub Jelinek, [email protected]. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +long double +frexpl (long double x, int *eptr) +{ + uint64_t hx, lx, ix; + + GET_LDOUBLE_WORDS64 (hx, lx, x); + ix = 0x7fffffffffffffffULL&hx; + *eptr = 0; + if (ix >= 0x7fff000000000000ULL || ((ix | lx) == 0)) + /* 0,inf,nan */ + return x + x; + if (ix < 0x0001000000000000ULL) + { + /* subnormal */ + x *= two114; + GET_LDOUBLE_MSW64 (hx, x); + ix = hx & 0x7fffffffffffffffULL; + *eptr = -114; + } + *eptr += (ix >> 48) - 16382; + hx = (hx & 0x8000ffffffffffffULL) | 0x3ffe000000000000ULL; + SET_LDOUBLE_MSW64 (x, hx); + return x; +} diff --git a/libgfortran/intrinsics/math_imp.h b/libgfortran/intrinsics/math_imp.h new file mode 100644 index 000000000000..fe55648dfdec --- /dev/null +++ b/libgfortran/intrinsics/math_imp.h @@ -0,0 +1,170 @@ +/* Header file for bit manipulation of long double type + Copyright (C) 2004-2026 Free Software Foundation, Inc. + +This file is part of the GNU Fortran 95 runtime library (libgfortran). + +Libgfortran is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +Libgfortran is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#ifndef LIBGFORTRAN_MATH_IMP_H +#define LIBGFORTRAN_MATH_IMP_H + +#if (__SIZEOF_LONG_DOUBLE__ == 16) && (__LDBL_IS_IEC_60559__ > 0) + +/* Main union type we use to manipulate the floating-point type. */ +typedef union +{ + long double value; + + struct +#ifdef __MINGW32__ + /* On mingw targets the ms-bitfields option is active by default. + Therefore enforce gnu-bitfield style. */ + __attribute__ ((gcc_struct)) +#endif + { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + unsigned negative:1; + unsigned exponent:15; + unsigned mantissa0:16; + unsigned mantissa1:32; + unsigned mantissa2:32; + unsigned mantissa3:32; +#else + unsigned mantissa3:32; + unsigned mantissa2:32; + unsigned mantissa1:32; + unsigned mantissa0:16; + unsigned exponent:15; + unsigned negative:1; +#endif + } ieee; + + struct + { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint64_t high; + uint64_t low; +#else + uint64_t low; + uint64_t high; +#endif + } words64; + + struct + { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uint32_t w0; + uint32_t w1; + uint32_t w2; + uint32_t w3; +#else + uint32_t w3; + uint32_t w2; + uint32_t w1; + uint32_t w0; +#endif + } words32; + + struct +#ifdef __MINGW32__ + /* Make sure we are using gnu-style bitfield handling. */ + __attribute__ ((gcc_struct)) +#endif + { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + unsigned negative:1; + unsigned exponent:15; + unsigned quiet_nan:1; + unsigned mantissa0:15; + unsigned mantissa1:32; + unsigned mantissa2:32; + unsigned mantissa3:32; +#else + unsigned mantissa3:32; + unsigned mantissa2:32; + unsigned mantissa1:32; + unsigned mantissa0:15; + unsigned quiet_nan:1; + unsigned exponent:15; + unsigned negative:1; +#endif + } ieee_nan; + +} ieee754_long_double; + + +/* Get two 64 bit ints from a long double. */ +#define GET_LDOUBLE_WORDS64(ix0,ix1,d) \ +do { \ + ieee754_long_double u; \ + u.value = (d); \ + (ix0) = u.words64.high; \ + (ix1) = u.words64.low; \ +} while (0) + +/* Set a long double from two 64 bit ints. */ +#define SET_LDOUBLE_WORDS64(d,ix0,ix1) \ +do { \ + ieee754_long_double u; \ + u.words64.high = (ix0); \ + u.words64.low = (ix1); \ + (d) = u.value; \ +} while (0) + +/* Get the more significant 64 bits of a long double mantissa. */ +#define GET_LDOUBLE_MSW64(v,d) \ +do { \ + ieee754_long_double u; \ + u.value = (d); \ + (v) = u.words64.high; \ +} while (0) + +/* Set the more significant 64 bits of a long double mantissa from an int. */ +#define SET_LDOUBLE_MSW64(d,v) \ +do { \ + ieee754_long_double u; \ + u.value = (d); \ + u.words64.high = (v); \ + (d) = u.value; \ +} while (0) + +/* Get the least significant 64 bits of a long double mantissa. */ +#define GET_LDOUBLE_LSW64(v,d) \ +do { \ + ieee754_long_double u; \ + u.value = (d); \ + (v) = u.words64.low; \ +} while (0) + +static const long double __attribute__ ((unused)) +two114 = 2.0769187434139310514121985316880384E+34L, /* 0x4071000000000000, 0 */ +twom114 = 4.8148248609680896326399448564623183E-35L, /* 0x3F8D000000000000, 0 */ +huge = 1.0E+4900L, +tiny = 1.0E-4900L; +#endif + +#ifndef math_opt_barrier +# define math_opt_barrier(x) \ +({ __typeof (x) __x = (x); __asm ("" : "+m" (__x)); __x; }) +# define math_force_eval(x) \ +({ __typeof (x) __x = (x); __asm __volatile__ ("" : : "m" (__x)); }) +#endif + +#endif /* LIBGFORTRAN_MATH_IMP_H */ diff --git a/libgfortran/intrinsics/nextafterl_16.c b/libgfortran/intrinsics/nextafterl_16.c new file mode 100644 index 000000000000..8334da5e3e71 --- /dev/null +++ b/libgfortran/intrinsics/nextafterl_16.c @@ -0,0 +1,108 @@ +/* s_nextafterl.c -- long double version of s_nextafter.c. + * Conversion to IEEE quad long double by Jakub Jelinek, [email protected]. + */ + +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* IEEE functions + * nextafterl(x,y) + * return the next machine floating-point number of x in the + * direction toward y. + * Special cases: + */ + +long double +nextafterl (long double x, long double y) +{ + int64_t hx, hy, ix, iy; + uint64_t lx, ly; + + GET_LDOUBLE_WORDS64 (hx, lx, x); + GET_LDOUBLE_WORDS64 (hy, ly, y); + ix = hx & 0x7fffffffffffffffLL; /* |x| */ + iy = hy & 0x7fffffffffffffffLL; /* |y| */ + + if (((ix >= 0x7fff000000000000LL) && ((ix - 0x7fff000000000000LL) | lx) != 0) + || ((iy >= 0x7fff000000000000LL) && ((iy - 0x7fff000000000000LL) | ly) != 0)) + /* x or y is nan */ + return x + y; + if (x == y) + /* x=y, return y */ + return y; + if ((ix | lx) == 0) + { + /* x == 0 */ + long double u; + + /* return +-minsubnormal */ + SET_LDOUBLE_WORDS64 (x, hy & 0x8000000000000000ULL, 1); + u = math_opt_barrier (x); + u = u * u; + /* raise underflow flag */ + math_force_eval (u); + return x; + } + if (hx >= 0) + { + /* x > 0 */ + if (hx > hy || ((hx == hy) && (lx > ly))) + { + /* x > y, x -= ulp */ + if (lx == 0) + hx--; + lx--; + } + else + { + /* x < y, x += ulp */ + lx++; + if (lx == 0) + hx++; + } + } + else + { + /* x < 0 */ + if (hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))) + { + /* x < y, x -= ulp */ + if (lx == 0) + hx--; + lx--; + } + else + { + /* x > y, x += ulp */ + lx++; + if (lx == 0) + hx++; + } + } + hy = hx & 0x7fff000000000000LL; + if (hy == 0x7fff000000000000LL) + { + /* overflow */ + long double u = x + x; + math_force_eval (u); + errno = ERANGE; + } + if (hy == 0) + { + /* underflow */ + long double u = x * x; + /* raise underflow flag */ + math_force_eval (u); + errno = ERANGE; + } + SET_LDOUBLE_WORDS64 (x, hx, lx); + return x; +} diff --git a/libgfortran/intrinsics/scalbnl_16.c b/libgfortran/intrinsics/scalbnl_16.c new file mode 100644 index 000000000000..717f4d6a148c --- /dev/null +++ b/libgfortran/intrinsics/scalbnl_16.c @@ -0,0 +1,61 @@ +/* s_scalbnl.c -- long double version of s_scalbn.c. + * Conversion to IEEE quad long double by Jakub Jelinek, [email protected]. + */ + +/* @(#)s_scalbn.c 5.1 93/09/24 */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +long double +scalbnl (long double x, int n) +{ + int64_t k, hx, lx; + + GET_LDOUBLE_WORDS64 (hx, lx, x); + + /* extract exponent */ + k = (hx >> 48) & 0x7fff; + if (k == 0) + { + /* 0 or subnormal x */ + if ((lx | (hx & 0x7fffffffffffffffULL)) == 0) + return x; /* +-0 */ + x *= two114; + GET_LDOUBLE_MSW64 (hx, x); + k = ((hx >> 48) & 0x7fff) - 114; + } + if (k == 0x7fff) + /* NaN or Inf */ + return x + x; + if (n < -50000) + /*underflow*/ + return tiny * copysignl (tiny, x); + if (n > 50000 || k + n > 0x7ffe) + /* overflow */ + return huge * copysignl (huge, x); + + /* Now k and n are bounded we know that k = k + n does not overflow. */ + k = k + n; + if (k > 0) + { + /* normal result */ + SET_LDOUBLE_MSW64 (x, (hx&0x8000ffffffffffffULL) | (k << 48)); + return x; + } + if (k <= -114) + /* underflow */ + return tiny * copysignl (tiny, x); + + /* subnormal result */ + k += 114; + SET_LDOUBLE_MSW64 (x, (hx & 0x8000ffffffffffffULL) | (k << 48)); + return x * twom114; +} diff --git a/libgfortran/intrinsics/truncl_16.c b/libgfortran/intrinsics/truncl_16.c new file mode 100644 index 000000000000..5632f69bd316 --- /dev/null +++ b/libgfortran/intrinsics/truncl_16.c @@ -0,0 +1,50 @@ +/* Truncate argument to nearest integral value not larger than the argument. + Copyright (C) 1997-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <[email protected]>, 1997 and + Jakub Jelinek <[email protected]>, 1999. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +long double +truncl (long double x) +{ + int32_t j0; + uint64_t i0, i1, sx; + + GET_LDOUBLE_WORDS64 (i0, i1, x); + sx = i0 & 0x8000000000000000ULL; + j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; + if (j0 < 48) + { + if (j0 < 0) + /* The magnitude of the number is < 1 so the result is +-0. */ + SET_LDOUBLE_WORDS64 (x, sx, 0); + else + SET_LDOUBLE_WORDS64 (x, i0 & ~(0x0000ffffffffffffLL >> j0), 0); + } + else if (j0 > 111) + { + if (j0 == 0x4000) + /* x is inf or NaN. */ + return x + x; + } + else + { + SET_LDOUBLE_WORDS64 (x, i0, i1 & ~(0xffffffffffffffffULL >> (j0 - 48))); + } + + return x; +} diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index 8381cbd7cd48..3613b5d68c08 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -59,6 +59,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include <string.h> #endif +/* Use libquadlib math routines. HP-UX on PA-RISC uses the 16-byte +IEEE format for long double but doesn't implement any of the standard +mathmetical routines. However, since the long double and __float128 +types are identical, we can use the routines in libquadmath. */ +#if defined(__hpux__) && defined(__hppa__) +#define USE_LIBQUADLIB +#endif + #if HAVE_COMPLEX_H /* Must appear before math.h on VMS systems. */ # include <complex.h>