Home | History | Annotate | Line # | Download | only in config
      1      1.1  mrg /* SysV FPU-related code (for systems not otherwise supported).
      2  1.1.1.4  mrg    Copyright (C) 2005-2024 Free Software Foundation, Inc.
      3      1.1  mrg    Contributed by Francois-Xavier Coudert <coudert (at) clipper.ens.fr>
      4      1.1  mrg 
      5      1.1  mrg This file is part of the GNU Fortran runtime library (libgfortran).
      6      1.1  mrg 
      7      1.1  mrg Libgfortran is free software; you can redistribute it and/or
      8      1.1  mrg modify it under the terms of the GNU General Public
      9      1.1  mrg License as published by the Free Software Foundation; either
     10      1.1  mrg version 3 of the License, or (at your option) any later version.
     11      1.1  mrg 
     12      1.1  mrg Libgfortran is distributed in the hope that it will be useful,
     13      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15      1.1  mrg GNU General Public License for more details.
     16      1.1  mrg 
     17      1.1  mrg Under Section 7 of GPL version 3, you are granted additional
     18      1.1  mrg permissions described in the GCC Runtime Library Exception, version
     19      1.1  mrg 3.1, as published by the Free Software Foundation.
     20      1.1  mrg 
     21      1.1  mrg You should have received a copy of the GNU General Public License and
     22      1.1  mrg a copy of the GCC Runtime Library Exception along with this program;
     23      1.1  mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24      1.1  mrg <http://www.gnu.org/licenses/>.  */
     25      1.1  mrg 
     26      1.1  mrg /* FPU-related code for SysV platforms with fpsetmask().  */
     27      1.1  mrg 
     28      1.1  mrg /* BSD and Solaris systems have slightly different types and functions
     29      1.1  mrg    naming.  We deal with these here, to simplify the code below.  */
     30      1.1  mrg 
     31      1.1  mrg #if HAVE_FP_EXCEPT
     32      1.1  mrg # define FP_EXCEPT_TYPE fp_except
     33      1.1  mrg #elif HAVE_FP_EXCEPT_T
     34      1.1  mrg # define FP_EXCEPT_TYPE fp_except_t
     35      1.1  mrg #else
     36      1.1  mrg   choke me
     37      1.1  mrg #endif
     38      1.1  mrg 
     39      1.1  mrg #if HAVE_FP_RND
     40      1.1  mrg # define FP_RND_TYPE fp_rnd
     41      1.1  mrg #elif HAVE_FP_RND_T
     42      1.1  mrg # define FP_RND_TYPE fp_rnd_t
     43      1.1  mrg #else
     44      1.1  mrg   choke me
     45      1.1  mrg #endif
     46      1.1  mrg 
     47      1.1  mrg #if HAVE_FPSETSTICKY
     48      1.1  mrg # define FPSETSTICKY fpsetsticky
     49      1.1  mrg #elif HAVE_FPRESETSTICKY
     50      1.1  mrg # define FPSETSTICKY fpresetsticky
     51      1.1  mrg #else
     52      1.1  mrg   choke me
     53      1.1  mrg #endif
     54      1.1  mrg 
     55      1.1  mrg 
     56      1.1  mrg void
     57      1.1  mrg set_fpu_trap_exceptions (int trap, int notrap)
     58      1.1  mrg {
     59      1.1  mrg   FP_EXCEPT_TYPE cw = fpgetmask();
     60      1.1  mrg 
     61      1.1  mrg #ifdef FP_X_INV
     62      1.1  mrg   if (trap & GFC_FPE_INVALID)
     63      1.1  mrg     cw |= FP_X_INV;
     64      1.1  mrg   if (notrap & GFC_FPE_INVALID)
     65      1.1  mrg     cw &= ~FP_X_INV;
     66      1.1  mrg #endif
     67      1.1  mrg 
     68      1.1  mrg #ifdef FP_X_DNML
     69      1.1  mrg   if (trap & GFC_FPE_DENORMAL)
     70      1.1  mrg     cw |= FP_X_DNML;
     71      1.1  mrg   if (notrap & GFC_FPE_DENORMAL)
     72      1.1  mrg     cw &= ~FP_X_DNML;
     73      1.1  mrg #endif
     74      1.1  mrg 
     75      1.1  mrg #ifdef FP_X_DZ
     76      1.1  mrg   if (trap & GFC_FPE_ZERO)
     77      1.1  mrg     cw |= FP_X_DZ;
     78      1.1  mrg   if (notrap & GFC_FPE_ZERO)
     79      1.1  mrg     cw &= ~FP_X_DZ;
     80      1.1  mrg #endif
     81      1.1  mrg 
     82      1.1  mrg #ifdef FP_X_OFL
     83      1.1  mrg   if (trap & GFC_FPE_OVERFLOW)
     84      1.1  mrg     cw |= FP_X_OFL;
     85      1.1  mrg   if (notrap & GFC_FPE_OVERFLOW)
     86      1.1  mrg     cw &= ~FP_X_OFL;
     87      1.1  mrg #endif
     88      1.1  mrg 
     89      1.1  mrg #ifdef FP_X_UFL
     90      1.1  mrg   if (trap & GFC_FPE_UNDERFLOW)
     91      1.1  mrg     cw |= FP_X_UFL;
     92      1.1  mrg   if (notrap & GFC_FPE_UNDERFLOW)
     93      1.1  mrg     cw &= ~FP_X_UFL;
     94      1.1  mrg #endif
     95      1.1  mrg 
     96      1.1  mrg #ifdef FP_X_IMP
     97      1.1  mrg   if (trap & GFC_FPE_INEXACT)
     98      1.1  mrg     cw |= FP_X_IMP;
     99      1.1  mrg   if (notrap & GFC_FPE_INEXACT)
    100      1.1  mrg     cw &= ~FP_X_IMP;
    101      1.1  mrg #endif
    102      1.1  mrg 
    103      1.1  mrg   fpsetmask(cw);
    104      1.1  mrg }
    105      1.1  mrg 
    106      1.1  mrg 
    107      1.1  mrg int
    108      1.1  mrg get_fpu_trap_exceptions (void)
    109      1.1  mrg {
    110      1.1  mrg   int res = 0;
    111      1.1  mrg   FP_EXCEPT_TYPE cw = fpgetmask();
    112      1.1  mrg 
    113      1.1  mrg #ifdef FP_X_INV
    114      1.1  mrg   if (cw & FP_X_INV) res |= GFC_FPE_INVALID;
    115      1.1  mrg #endif
    116      1.1  mrg 
    117      1.1  mrg #ifdef FP_X_DNML
    118      1.1  mrg   if (cw & FP_X_DNML) res |= GFC_FPE_DENORMAL;
    119      1.1  mrg #endif
    120      1.1  mrg 
    121      1.1  mrg #ifdef FP_X_DZ
    122      1.1  mrg   if (cw & FP_X_DZ) res |= GFC_FPE_ZERO;
    123      1.1  mrg #endif
    124      1.1  mrg 
    125      1.1  mrg #ifdef FP_X_OFL
    126      1.1  mrg   if (cw & FP_X_OFL) res |= GFC_FPE_OVERFLOW;
    127      1.1  mrg #endif
    128      1.1  mrg 
    129      1.1  mrg #ifdef FP_X_UFL
    130      1.1  mrg   if (cw & FP_X_UFL) res |= GFC_FPE_UNDERFLOW;
    131      1.1  mrg #endif
    132      1.1  mrg 
    133      1.1  mrg #ifdef FP_X_IMP
    134      1.1  mrg   if (cw & FP_X_IMP) res |= GFC_FPE_INEXACT;
    135      1.1  mrg #endif
    136      1.1  mrg 
    137      1.1  mrg   return res;
    138      1.1  mrg }
    139      1.1  mrg 
    140      1.1  mrg 
    141      1.1  mrg int
    142      1.1  mrg support_fpu_trap (int flag)
    143      1.1  mrg {
    144      1.1  mrg   return support_fpu_flag (flag);
    145      1.1  mrg }
    146      1.1  mrg 
    147      1.1  mrg 
    148      1.1  mrg void
    149      1.1  mrg set_fpu (void)
    150      1.1  mrg {
    151      1.1  mrg #ifndef FP_X_INV
    152      1.1  mrg   if (options.fpe & GFC_FPE_INVALID)
    153      1.1  mrg     estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
    154      1.1  mrg 	        "exception not supported.\n");
    155      1.1  mrg #endif
    156      1.1  mrg 
    157      1.1  mrg #ifndef FP_X_DNML
    158      1.1  mrg   if (options.fpe & GFC_FPE_DENORMAL)
    159      1.1  mrg     estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
    160      1.1  mrg 	        "exception not supported.\n");
    161      1.1  mrg #endif
    162      1.1  mrg 
    163      1.1  mrg #ifndef FP_X_DZ
    164      1.1  mrg   if (options.fpe & GFC_FPE_ZERO)
    165      1.1  mrg     estr_write ("Fortran runtime warning: IEEE 'division by zero' "
    166      1.1  mrg 	        "exception not supported.\n");
    167      1.1  mrg #endif
    168      1.1  mrg 
    169      1.1  mrg #ifndef FP_X_OFL
    170      1.1  mrg   if (options.fpe & GFC_FPE_OVERFLOW)
    171      1.1  mrg     estr_write ("Fortran runtime warning: IEEE 'overflow' "
    172      1.1  mrg 	        "exception not supported.\n");
    173      1.1  mrg #endif
    174      1.1  mrg 
    175      1.1  mrg #ifndef FP_X_UFL
    176      1.1  mrg   if (options.fpe & GFC_FPE_UNDERFLOW)
    177      1.1  mrg     estr_write ("Fortran runtime warning: IEEE 'underflow' "
    178      1.1  mrg 	        "exception not supported.\n");
    179      1.1  mrg #endif
    180      1.1  mrg 
    181      1.1  mrg #ifndef FP_X_IMP
    182      1.1  mrg   if (options.fpe & GFC_FPE_INEXACT)
    183      1.1  mrg     estr_write ("Fortran runtime warning: IEEE 'inexact' "
    184      1.1  mrg 	        "exception not supported.\n");
    185      1.1  mrg #endif
    186      1.1  mrg 
    187      1.1  mrg   set_fpu_trap_exceptions (options.fpe, 0);
    188      1.1  mrg }
    189      1.1  mrg 
    190      1.1  mrg 
    191      1.1  mrg int
    192      1.1  mrg get_fpu_except_flags (void)
    193      1.1  mrg {
    194      1.1  mrg   int result;
    195      1.1  mrg   FP_EXCEPT_TYPE set_excepts;
    196      1.1  mrg 
    197      1.1  mrg   result = 0;
    198      1.1  mrg   set_excepts = fpgetsticky ();
    199      1.1  mrg 
    200      1.1  mrg #ifdef FP_X_INV
    201      1.1  mrg   if (set_excepts & FP_X_INV)
    202      1.1  mrg     result |= GFC_FPE_INVALID;
    203      1.1  mrg #endif
    204      1.1  mrg 
    205      1.1  mrg #ifdef FP_X_DZ
    206      1.1  mrg   if (set_excepts & FP_X_DZ)
    207      1.1  mrg     result |= GFC_FPE_ZERO;
    208      1.1  mrg #endif
    209      1.1  mrg 
    210      1.1  mrg #ifdef FP_X_OFL
    211      1.1  mrg   if (set_excepts & FP_X_OFL)
    212      1.1  mrg     result |= GFC_FPE_OVERFLOW;
    213      1.1  mrg #endif
    214      1.1  mrg 
    215      1.1  mrg #ifdef FP_X_UFL
    216      1.1  mrg   if (set_excepts & FP_X_UFL)
    217      1.1  mrg     result |= GFC_FPE_UNDERFLOW;
    218      1.1  mrg #endif
    219      1.1  mrg 
    220      1.1  mrg #ifdef FP_X_DNML
    221      1.1  mrg   if (set_excepts & FP_X_DNML)
    222      1.1  mrg     result |= GFC_FPE_DENORMAL;
    223      1.1  mrg #endif
    224      1.1  mrg 
    225      1.1  mrg #ifdef FP_X_IMP
    226      1.1  mrg   if (set_excepts & FP_X_IMP)
    227      1.1  mrg     result |= GFC_FPE_INEXACT;
    228      1.1  mrg #endif
    229      1.1  mrg 
    230      1.1  mrg   return result;
    231      1.1  mrg }
    232      1.1  mrg 
    233      1.1  mrg 
    234      1.1  mrg void
    235      1.1  mrg set_fpu_except_flags (int set, int clear)
    236      1.1  mrg {
    237      1.1  mrg   FP_EXCEPT_TYPE flags;
    238      1.1  mrg 
    239      1.1  mrg   flags = fpgetsticky ();
    240      1.1  mrg 
    241      1.1  mrg #ifdef FP_X_INV
    242      1.1  mrg   if (set & GFC_FPE_INVALID)
    243      1.1  mrg     flags |= FP_X_INV;
    244      1.1  mrg   if (clear & GFC_FPE_INVALID)
    245      1.1  mrg     flags &= ~FP_X_INV;
    246      1.1  mrg #endif
    247      1.1  mrg 
    248      1.1  mrg #ifdef FP_X_DZ
    249      1.1  mrg   if (set & GFC_FPE_ZERO)
    250      1.1  mrg     flags |= FP_X_DZ;
    251      1.1  mrg   if (clear & GFC_FPE_ZERO)
    252      1.1  mrg     flags &= ~FP_X_DZ;
    253      1.1  mrg #endif
    254      1.1  mrg 
    255      1.1  mrg #ifdef FP_X_OFL
    256      1.1  mrg   if (set & GFC_FPE_OVERFLOW)
    257      1.1  mrg     flags |= FP_X_OFL;
    258      1.1  mrg   if (clear & GFC_FPE_OVERFLOW)
    259      1.1  mrg     flags &= ~FP_X_OFL;
    260      1.1  mrg #endif
    261      1.1  mrg 
    262      1.1  mrg #ifdef FP_X_UFL
    263      1.1  mrg   if (set & GFC_FPE_UNDERFLOW)
    264      1.1  mrg     flags |= FP_X_UFL;
    265      1.1  mrg   if (clear & GFC_FPE_UNDERFLOW)
    266      1.1  mrg     flags &= ~FP_X_UFL;
    267      1.1  mrg #endif
    268      1.1  mrg 
    269      1.1  mrg #ifdef FP_X_DNML
    270      1.1  mrg   if (set & GFC_FPE_DENORMAL)
    271      1.1  mrg     flags |= FP_X_DNML;
    272      1.1  mrg   if (clear & GFC_FPE_DENORMAL)
    273      1.1  mrg     flags &= ~FP_X_DNML;
    274      1.1  mrg #endif
    275      1.1  mrg 
    276      1.1  mrg #ifdef FP_X_IMP
    277      1.1  mrg   if (set & GFC_FPE_INEXACT)
    278      1.1  mrg     flags |= FP_X_IMP;
    279      1.1  mrg   if (clear & GFC_FPE_INEXACT)
    280      1.1  mrg     flags &= ~FP_X_IMP;
    281      1.1  mrg #endif
    282      1.1  mrg 
    283      1.1  mrg   FPSETSTICKY (flags);
    284      1.1  mrg }
    285      1.1  mrg 
    286      1.1  mrg 
    287      1.1  mrg int
    288      1.1  mrg support_fpu_flag (int flag)
    289      1.1  mrg {
    290      1.1  mrg   if (flag & GFC_FPE_INVALID)
    291      1.1  mrg   {
    292      1.1  mrg #ifndef FP_X_INV
    293      1.1  mrg     return 0;
    294      1.1  mrg #endif
    295      1.1  mrg   }
    296      1.1  mrg   else if (flag & GFC_FPE_ZERO)
    297      1.1  mrg   {
    298      1.1  mrg #ifndef FP_X_DZ
    299      1.1  mrg     return 0;
    300      1.1  mrg #endif
    301      1.1  mrg   }
    302      1.1  mrg   else if (flag & GFC_FPE_OVERFLOW)
    303      1.1  mrg   {
    304      1.1  mrg #ifndef FP_X_OFL
    305      1.1  mrg     return 0;
    306      1.1  mrg #endif
    307      1.1  mrg   }
    308      1.1  mrg   else if (flag & GFC_FPE_UNDERFLOW)
    309      1.1  mrg   {
    310      1.1  mrg #ifndef FP_X_UFL
    311      1.1  mrg     return 0;
    312      1.1  mrg #endif
    313      1.1  mrg   }
    314      1.1  mrg   else if (flag & GFC_FPE_DENORMAL)
    315      1.1  mrg   {
    316      1.1  mrg #ifndef FP_X_DNML
    317      1.1  mrg     return 0;
    318      1.1  mrg #endif
    319      1.1  mrg   }
    320      1.1  mrg   else if (flag & GFC_FPE_INEXACT)
    321      1.1  mrg   {
    322      1.1  mrg #ifndef FP_X_IMP
    323      1.1  mrg     return 0;
    324      1.1  mrg #endif
    325      1.1  mrg   }
    326      1.1  mrg 
    327      1.1  mrg   return 1;
    328      1.1  mrg }
    329      1.1  mrg 
    330      1.1  mrg 
    331      1.1  mrg int
    332      1.1  mrg get_fpu_rounding_mode (void)
    333      1.1  mrg {
    334      1.1  mrg   switch (fpgetround ())
    335      1.1  mrg     {
    336      1.1  mrg       case FP_RN:
    337      1.1  mrg 	return GFC_FPE_TONEAREST;
    338      1.1  mrg       case FP_RP:
    339      1.1  mrg 	return GFC_FPE_UPWARD;
    340      1.1  mrg       case FP_RM:
    341      1.1  mrg 	return GFC_FPE_DOWNWARD;
    342      1.1  mrg       case FP_RZ:
    343      1.1  mrg 	return GFC_FPE_TOWARDZERO;
    344      1.1  mrg       default:
    345      1.1  mrg 	return 0; /* Should be unreachable.  */
    346      1.1  mrg     }
    347      1.1  mrg }
    348      1.1  mrg 
    349      1.1  mrg 
    350      1.1  mrg void
    351      1.1  mrg set_fpu_rounding_mode (int mode)
    352      1.1  mrg {
    353      1.1  mrg   FP_RND_TYPE rnd_mode;
    354      1.1  mrg 
    355      1.1  mrg   switch (mode)
    356      1.1  mrg     {
    357      1.1  mrg       case GFC_FPE_TONEAREST:
    358      1.1  mrg 	rnd_mode = FP_RN;
    359      1.1  mrg         break;
    360      1.1  mrg       case GFC_FPE_UPWARD:
    361      1.1  mrg 	rnd_mode = FP_RP;
    362      1.1  mrg         break;
    363      1.1  mrg       case GFC_FPE_DOWNWARD:
    364      1.1  mrg 	rnd_mode = FP_RM;
    365      1.1  mrg         break;
    366      1.1  mrg       case GFC_FPE_TOWARDZERO:
    367      1.1  mrg 	rnd_mode = FP_RZ;
    368      1.1  mrg         break;
    369      1.1  mrg       default:
    370      1.1  mrg 	return; /* Should be unreachable.  */
    371      1.1  mrg     }
    372      1.1  mrg   fpsetround (rnd_mode);
    373      1.1  mrg }
    374      1.1  mrg 
    375      1.1  mrg 
    376      1.1  mrg int
    377  1.1.1.4  mrg support_fpu_rounding_mode (int mode)
    378      1.1  mrg {
    379  1.1.1.4  mrg   if (mode == GFC_FPE_AWAY)
    380  1.1.1.4  mrg     return 0;
    381  1.1.1.4  mrg   else
    382  1.1.1.4  mrg     return 1;
    383      1.1  mrg }
    384      1.1  mrg 
    385      1.1  mrg 
    386      1.1  mrg typedef struct
    387      1.1  mrg {
    388      1.1  mrg   FP_EXCEPT_TYPE mask;
    389      1.1  mrg   FP_EXCEPT_TYPE sticky;
    390      1.1  mrg   FP_RND_TYPE round;
    391      1.1  mrg } fpu_state_t;
    392      1.1  mrg 
    393      1.1  mrg 
    394      1.1  mrg /* Check we can actually store the FPU state in the allocated size.  */
    395      1.1  mrg _Static_assert (sizeof(fpu_state_t) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE,
    396      1.1  mrg 		"GFC_FPE_STATE_BUFFER_SIZE is too small");
    397      1.1  mrg 
    398      1.1  mrg 
    399      1.1  mrg void
    400      1.1  mrg get_fpu_state (void *s)
    401      1.1  mrg {
    402      1.1  mrg   fpu_state_t *state = s;
    403      1.1  mrg 
    404      1.1  mrg   state->mask = fpgetmask ();
    405      1.1  mrg   state->sticky = fpgetsticky ();
    406      1.1  mrg   state->round = fpgetround ();
    407      1.1  mrg }
    408      1.1  mrg 
    409      1.1  mrg void
    410      1.1  mrg set_fpu_state (void *s)
    411      1.1  mrg {
    412      1.1  mrg   fpu_state_t *state = s;
    413      1.1  mrg 
    414      1.1  mrg   fpsetmask (state->mask);
    415      1.1  mrg   FPSETSTICKY (state->sticky);
    416      1.1  mrg   fpsetround (state->round);
    417      1.1  mrg }
    418      1.1  mrg 
    419      1.1  mrg 
    420      1.1  mrg int
    421      1.1  mrg support_fpu_underflow_control (int kind __attribute__((unused)))
    422      1.1  mrg {
    423      1.1  mrg   return 0;
    424      1.1  mrg }
    425      1.1  mrg 
    426      1.1  mrg 
    427      1.1  mrg int
    428      1.1  mrg get_fpu_underflow_mode (void)
    429      1.1  mrg {
    430      1.1  mrg   return 0;
    431      1.1  mrg }
    432      1.1  mrg 
    433      1.1  mrg 
    434      1.1  mrg void
    435      1.1  mrg set_fpu_underflow_mode (int gradual __attribute__((unused)))
    436      1.1  mrg {
    437      1.1  mrg }
    438      1.1  mrg 
    439