diff options
Diffstat (limited to 'libgfortran/config/fpu-sysv.h')
-rw-r--r-- | libgfortran/config/fpu-sysv.h | 350 |
1 files changed, 291 insertions, 59 deletions
diff --git a/libgfortran/config/fpu-sysv.h b/libgfortran/config/fpu-sysv.h index e7ba88f4a9..e7a7fac04a 100644 --- a/libgfortran/config/fpu-sysv.h +++ b/libgfortran/config/fpu-sysv.h @@ -1,5 +1,5 @@ /* SysV FPU-related code (for systems not otherwise supported). - Copyright (C) 2005-2014 Free Software Foundation, Inc. + Copyright (C) 2005-2015 Free Software Foundation, Inc. Contributed by Francois-Xavier Coudert <coudert@clipper.ens.fr> This file is part of the GNU Fortran runtime library (libgfortran). @@ -25,73 +25,174 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* FPU-related code for SysV platforms with fpsetmask(). */ +/* BSD and Solaris systems have slightly different types and functions + naming. We deal with these here, to simplify the code below. */ + +#if HAVE_FP_EXCEPT +# define FP_EXCEPT_TYPE fp_except +#elif HAVE_FP_EXCEPT_T +# define FP_EXCEPT_TYPE fp_except_t +#else + choke me +#endif + +#if HAVE_FP_RND +# define FP_RND_TYPE fp_rnd +#elif HAVE_FP_RND_T +# define FP_RND_TYPE fp_rnd_t +#else + choke me +#endif + +#if HAVE_FPSETSTICKY +# define FPSETSTICKY fpsetsticky +#elif HAVE_FPRESETSTICKY +# define FPSETSTICKY fpresetsticky +#else + choke me +#endif + + void -set_fpu (void) +set_fpu_trap_exceptions (int trap, int notrap) { - int cw = 0; + FP_EXCEPT_TYPE cw = fpgetmask(); - if (options.fpe & GFC_FPE_INVALID) #ifdef FP_X_INV + if (trap & GFC_FPE_INVALID) cw |= FP_X_INV; -#else + if (notrap & GFC_FPE_INVALID) + cw &= ~FP_X_INV; +#endif + +#ifdef FP_X_DNML + if (trap & GFC_FPE_DENORMAL) + cw |= FP_X_DNML; + if (notrap & GFC_FPE_DENORMAL) + cw &= ~FP_X_DNML; +#endif + +#ifdef FP_X_DZ + if (trap & GFC_FPE_ZERO) + cw |= FP_X_DZ; + if (notrap & GFC_FPE_ZERO) + cw &= ~FP_X_DZ; +#endif + +#ifdef FP_X_OFL + if (trap & GFC_FPE_OVERFLOW) + cw |= FP_X_OFL; + if (notrap & GFC_FPE_OVERFLOW) + cw &= ~FP_X_OFL; +#endif + +#ifdef FP_X_UFL + if (trap & GFC_FPE_UNDERFLOW) + cw |= FP_X_UFL; + if (notrap & GFC_FPE_UNDERFLOW) + cw &= ~FP_X_UFL; +#endif + +#ifdef FP_X_IMP + if (trap & GFC_FPE_INEXACT) + cw |= FP_X_IMP; + if (notrap & GFC_FPE_INEXACT) + cw &= ~FP_X_IMP; +#endif + + fpsetmask(cw); +} + + +int +get_fpu_trap_exceptions (void) +{ + int res = 0; + FP_EXCEPT_TYPE cw = fpgetmask(); + +#ifdef FP_X_INV + if (cw & FP_X_INV) res |= GFC_FPE_INVALID; +#endif + +#ifdef FP_X_DNML + if (cw & FP_X_DNML) res |= GFC_FPE_DENORMAL; +#endif + +#ifdef FP_X_DZ + if (cw & FP_X_DZ) res |= GFC_FPE_ZERO; +#endif + +#ifdef FP_X_OFL + if (cw & FP_X_OFL) res |= GFC_FPE_OVERFLOW; +#endif + +#ifdef FP_X_UFL + if (cw & FP_X_UFL) res |= GFC_FPE_UNDERFLOW; +#endif + +#ifdef FP_X_IMP + if (cw & FP_X_IMP) res |= GFC_FPE_INEXACT; +#endif + + return res; +} + + +int +support_fpu_trap (int flag) +{ + return support_fpu_flag (flag); +} + + +void +set_fpu (void) +{ +#ifndef FP_X_INV + if (options.fpe & GFC_FPE_INVALID) estr_write ("Fortran runtime warning: IEEE 'invalid operation' " "exception not supported.\n"); #endif +#ifndef FP_X_DNML if (options.fpe & GFC_FPE_DENORMAL) -#ifdef FP_X_DNML - cw |= FP_X_DNML; -#else estr_write ("Fortran runtime warning: Floating point 'denormal operand' " "exception not supported.\n"); #endif +#ifndef FP_X_DZ if (options.fpe & GFC_FPE_ZERO) -#ifdef FP_X_DZ - cw |= FP_X_DZ; -#else estr_write ("Fortran runtime warning: IEEE 'division by zero' " "exception not supported.\n"); #endif +#ifndef FP_X_OFL if (options.fpe & GFC_FPE_OVERFLOW) -#ifdef FP_X_OFL - cw |= FP_X_OFL; -#else estr_write ("Fortran runtime warning: IEEE 'overflow' " "exception not supported.\n"); #endif +#ifndef FP_X_UFL if (options.fpe & GFC_FPE_UNDERFLOW) -#ifdef FP_X_UFL - cw |= FP_X_UFL; -#else estr_write ("Fortran runtime warning: IEEE 'underflow' " "exception not supported.\n"); #endif +#ifndef FP_X_IMP if (options.fpe & GFC_FPE_INEXACT) -#ifdef FP_X_IMP - cw |= FP_X_IMP; -#else estr_write ("Fortran runtime warning: IEEE 'inexact' " "exception not supported.\n"); #endif - fpsetmask(cw); + set_fpu_trap_exceptions (options.fpe, 0); } + int get_fpu_except_flags (void) { int result; -#if HAVE_FP_EXCEPT - fp_except set_excepts; -#elif HAVE_FP_EXCEPT_T - fp_except_t set_excepts; -#else - choke me -#endif + FP_EXCEPT_TYPE set_excepts; result = 0; set_excepts = fpgetsticky (); @@ -130,32 +231,118 @@ get_fpu_except_flags (void) } +void +set_fpu_except_flags (int set, int clear) +{ + FP_EXCEPT_TYPE flags; + + flags = fpgetsticky (); + +#ifdef FP_X_INV + if (set & GFC_FPE_INVALID) + flags |= FP_X_INV; + if (clear & GFC_FPE_INVALID) + flags &= ~FP_X_INV; +#endif + +#ifdef FP_X_DZ + if (set & GFC_FPE_ZERO) + flags |= FP_X_DZ; + if (clear & GFC_FPE_ZERO) + flags &= ~FP_X_DZ; +#endif + +#ifdef FP_X_OFL + if (set & GFC_FPE_OVERFLOW) + flags |= FP_X_OFL; + if (clear & GFC_FPE_OVERFLOW) + flags &= ~FP_X_OFL; +#endif + +#ifdef FP_X_UFL + if (set & GFC_FPE_UNDERFLOW) + flags |= FP_X_UFL; + if (clear & GFC_FPE_UNDERFLOW) + flags &= ~FP_X_UFL; +#endif + +#ifdef FP_X_DNML + if (set & GFC_FPE_DENORMAL) + flags |= FP_X_DNML; + if (clear & GFC_FPE_DENORMAL) + flags &= ~FP_X_DNML; +#endif + +#ifdef FP_X_IMP + if (set & GFC_FPE_INEXACT) + flags |= FP_X_IMP; + if (clear & GFC_FPE_INEXACT) + flags &= ~FP_X_IMP; +#endif + + FPSETSTICKY (flags); +} + + +int +support_fpu_flag (int flag) +{ + if (flag & GFC_FPE_INVALID) + { +#ifndef FP_X_INV + return 0; +#endif + } + else if (flag & GFC_FPE_ZERO) + { +#ifndef FP_X_DZ + return 0; +#endif + } + else if (flag & GFC_FPE_OVERFLOW) + { +#ifndef FP_X_OFL + return 0; +#endif + } + else if (flag & GFC_FPE_UNDERFLOW) + { +#ifndef FP_X_UFL + return 0; +#endif + } + else if (flag & GFC_FPE_DENORMAL) + { +#ifndef FP_X_DNML + return 0; +#endif + } + else if (flag & GFC_FPE_INEXACT) + { +#ifndef FP_X_IMP + return 0; +#endif + } + + return 1; +} + + int get_fpu_rounding_mode (void) { switch (fpgetround ()) { -#ifdef FP_RN case FP_RN: return GFC_FPE_TONEAREST; -#endif - -#ifdef FP_RP case FP_RP: return GFC_FPE_UPWARD; -#endif - -#ifdef FP_RM case FP_RM: return GFC_FPE_DOWNWARD; -#endif - -#ifdef FP_RZ case FP_RZ: return GFC_FPE_TOWARDZERO; -#endif default: - return GFC_FPE_INVALID; + return 0; /* Should be unreachable. */ } } @@ -163,41 +350,86 @@ get_fpu_rounding_mode (void) void set_fpu_rounding_mode (int mode) { -#if HAVE_FP_RND - fp_rnd rnd_mode; -#elif HAVE_FP_RND_T - fp_rnd_t rnd_mode; -#else - choke me -#endif + FP_RND_TYPE rnd_mode; switch (mode) { -#ifdef FP_RN case GFC_FPE_TONEAREST: rnd_mode = FP_RN; break; -#endif - -#ifdef FP_RP case GFC_FPE_UPWARD: rnd_mode = FP_RP; break; -#endif - -#ifdef FP_RM case GFC_FPE_DOWNWARD: rnd_mode = FP_RM; break; -#endif - -#ifdef FP_RZ case GFC_FPE_TOWARDZERO: rnd_mode = FP_RZ; break; -#endif default: - return; + return; /* Should be unreachable. */ } fpsetround (rnd_mode); } + + +int +support_fpu_rounding_mode (int mode __attribute__((unused))) +{ + return 1; +} + + +typedef struct +{ + FP_EXCEPT_TYPE mask; + FP_EXCEPT_TYPE sticky; + FP_RND_TYPE round; +} fpu_state_t; + + +/* Check we can actually store the FPU state in the allocated size. */ +_Static_assert (sizeof(fpu_state_t) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE, + "GFC_FPE_STATE_BUFFER_SIZE is too small"); + + +void +get_fpu_state (void *s) +{ + fpu_state_t *state = s; + + state->mask = fpgetmask (); + state->sticky = fpgetsticky (); + state->round = fpgetround (); +} + +void +set_fpu_state (void *s) +{ + fpu_state_t *state = s; + + fpsetmask (state->mask); + FPSETSTICKY (state->sticky); + fpsetround (state->round); +} + + +int +support_fpu_underflow_control (int kind __attribute__((unused))) +{ + return 0; +} + + +int +get_fpu_underflow_mode (void) +{ + return 0; +} + + +void +set_fpu_underflow_mode (int gradual __attribute__((unused))) +{ +} + |