Home | History | Annotate | Line # | Download | only in config
      1  1.1  mrg /* FPU-related code for aarch64.
      2  1.1  mrg    Copyright (C) 2020-2022 Free Software Foundation, Inc.
      3  1.1  mrg    Contributed by Francois-Xavier Coudert <fxcoudert (at) gcc.gnu.org>
      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 
     27  1.1  mrg /* Rounding mask and modes */
     28  1.1  mrg 
     29  1.1  mrg #define FPCR_RM_MASK  0x0c00000
     30  1.1  mrg #define FE_TONEAREST  0x0000000
     31  1.1  mrg #define FE_UPWARD     0x0400000
     32  1.1  mrg #define FE_DOWNWARD   0x0800000
     33  1.1  mrg #define FE_TOWARDZERO 0x0c00000
     34  1.1  mrg #define FE_MAP_FZ     0x1000000
     35  1.1  mrg 
     36  1.1  mrg /* Exceptions */
     37  1.1  mrg 
     38  1.1  mrg #define FE_INVALID	1
     39  1.1  mrg #define FE_DIVBYZERO	2
     40  1.1  mrg #define FE_OVERFLOW	4
     41  1.1  mrg #define FE_UNDERFLOW	8
     42  1.1  mrg #define FE_INEXACT	16
     43  1.1  mrg 
     44  1.1  mrg #define FE_ALL_EXCEPT (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)
     45  1.1  mrg #define FE_EXCEPT_SHIFT	8
     46  1.1  mrg 
     47  1.1  mrg 
     48  1.1  mrg 
     49  1.1  mrg /* This structure corresponds to the layout of the block
     50  1.1  mrg    written by FSTENV.  */
     51  1.1  mrg struct fenv
     52  1.1  mrg {
     53  1.1  mrg   unsigned int __fpcr;
     54  1.1  mrg   unsigned int __fpsr;
     55  1.1  mrg };
     56  1.1  mrg 
     57  1.1  mrg /* Check we can actually store the FPU state in the allocated size.  */
     58  1.1  mrg _Static_assert (sizeof(struct fenv) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE,
     59  1.1  mrg 		"GFC_FPE_STATE_BUFFER_SIZE is too small");
     60  1.1  mrg 
     61  1.1  mrg 
     62  1.1  mrg 
     63  1.1  mrg void
     64  1.1  mrg set_fpu (void)
     65  1.1  mrg {
     66  1.1  mrg   if (options.fpe & GFC_FPE_DENORMAL)
     67  1.1  mrg     estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
     68  1.1  mrg 	        "exception not supported.\n");
     69  1.1  mrg 
     70  1.1  mrg   set_fpu_trap_exceptions (options.fpe, 0);
     71  1.1  mrg }
     72  1.1  mrg 
     73  1.1  mrg 
     74  1.1  mrg int
     75  1.1  mrg get_fpu_trap_exceptions (void)
     76  1.1  mrg {
     77  1.1  mrg   unsigned int fpcr, exceptions;
     78  1.1  mrg   int res = 0;
     79  1.1  mrg 
     80  1.1  mrg   fpcr = __builtin_aarch64_get_fpcr();
     81  1.1  mrg   exceptions = (fpcr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
     82  1.1  mrg 
     83  1.1  mrg   if (exceptions & FE_INVALID) res |= GFC_FPE_INVALID;
     84  1.1  mrg   if (exceptions & FE_DIVBYZERO) res |= GFC_FPE_ZERO;
     85  1.1  mrg   if (exceptions & FE_OVERFLOW) res |= GFC_FPE_OVERFLOW;
     86  1.1  mrg   if (exceptions & FE_UNDERFLOW) res |= GFC_FPE_UNDERFLOW;
     87  1.1  mrg   if (exceptions & FE_INEXACT) res |= GFC_FPE_INEXACT;
     88  1.1  mrg 
     89  1.1  mrg   return res;
     90  1.1  mrg }
     91  1.1  mrg 
     92  1.1  mrg 
     93  1.1  mrg void set_fpu_trap_exceptions (int trap, int notrap)
     94  1.1  mrg {
     95  1.1  mrg   unsigned int mode_set = 0, mode_clr = 0;
     96  1.1  mrg   unsigned int fpsr, fpsr_new;
     97  1.1  mrg   unsigned int fpcr, fpcr_new;
     98  1.1  mrg 
     99  1.1  mrg   if (trap & GFC_FPE_INVALID)
    100  1.1  mrg     mode_set |= FE_INVALID;
    101  1.1  mrg   if (notrap & GFC_FPE_INVALID)
    102  1.1  mrg     mode_clr |= FE_INVALID;
    103  1.1  mrg 
    104  1.1  mrg   if (trap & GFC_FPE_ZERO)
    105  1.1  mrg     mode_set |= FE_DIVBYZERO;
    106  1.1  mrg   if (notrap & GFC_FPE_ZERO)
    107  1.1  mrg     mode_clr |= FE_DIVBYZERO;
    108  1.1  mrg 
    109  1.1  mrg   if (trap & GFC_FPE_OVERFLOW)
    110  1.1  mrg     mode_set |= FE_OVERFLOW;
    111  1.1  mrg   if (notrap & GFC_FPE_OVERFLOW)
    112  1.1  mrg     mode_clr |= FE_OVERFLOW;
    113  1.1  mrg 
    114  1.1  mrg   if (trap & GFC_FPE_UNDERFLOW)
    115  1.1  mrg     mode_set |= FE_UNDERFLOW;
    116  1.1  mrg   if (notrap & GFC_FPE_UNDERFLOW)
    117  1.1  mrg     mode_clr |= FE_UNDERFLOW;
    118  1.1  mrg 
    119  1.1  mrg   if (trap & GFC_FPE_INEXACT)
    120  1.1  mrg     mode_set |= FE_INEXACT;
    121  1.1  mrg   if (notrap & GFC_FPE_INEXACT)
    122  1.1  mrg     mode_clr |= FE_INEXACT;
    123  1.1  mrg 
    124  1.1  mrg   /* Clear stalled exception flags.  */
    125  1.1  mrg   fpsr = __builtin_aarch64_get_fpsr();
    126  1.1  mrg   fpsr_new = fpsr & ~FE_ALL_EXCEPT;
    127  1.1  mrg   if (fpsr_new != fpsr)
    128  1.1  mrg     __builtin_aarch64_set_fpsr(fpsr_new);
    129  1.1  mrg 
    130  1.1  mrg   fpcr_new = fpcr = __builtin_aarch64_get_fpcr();
    131  1.1  mrg   fpcr_new |= (mode_set << FE_EXCEPT_SHIFT);
    132  1.1  mrg   fpcr_new &= ~(mode_clr << FE_EXCEPT_SHIFT);
    133  1.1  mrg 
    134  1.1  mrg   if (fpcr_new != fpcr)
    135  1.1  mrg     __builtin_aarch64_set_fpcr(fpcr_new);
    136  1.1  mrg }
    137  1.1  mrg 
    138  1.1  mrg 
    139  1.1  mrg int
    140  1.1  mrg support_fpu_flag (int flag)
    141  1.1  mrg {
    142  1.1  mrg   if (flag & GFC_FPE_DENORMAL)
    143  1.1  mrg     return 0;
    144  1.1  mrg 
    145  1.1  mrg   return 1;
    146  1.1  mrg }
    147  1.1  mrg 
    148  1.1  mrg 
    149  1.1  mrg int
    150  1.1  mrg support_fpu_trap (int flag)
    151  1.1  mrg {
    152  1.1  mrg   if (flag & GFC_FPE_DENORMAL)
    153  1.1  mrg     return 0;
    154  1.1  mrg 
    155  1.1  mrg   return 1;
    156  1.1  mrg }
    157  1.1  mrg 
    158  1.1  mrg 
    159  1.1  mrg int
    160  1.1  mrg get_fpu_except_flags (void)
    161  1.1  mrg {
    162  1.1  mrg   int result;
    163  1.1  mrg   unsigned int fpsr;
    164  1.1  mrg 
    165  1.1  mrg   result = 0;
    166  1.1  mrg   fpsr = __builtin_aarch64_get_fpsr() & FE_ALL_EXCEPT;
    167  1.1  mrg 
    168  1.1  mrg   if (fpsr & FE_INVALID)
    169  1.1  mrg     result |= GFC_FPE_INVALID;
    170  1.1  mrg   if (fpsr & FE_DIVBYZERO)
    171  1.1  mrg     result |= GFC_FPE_ZERO;
    172  1.1  mrg   if (fpsr & FE_OVERFLOW)
    173  1.1  mrg     result |= GFC_FPE_OVERFLOW;
    174  1.1  mrg   if (fpsr & FE_UNDERFLOW)
    175  1.1  mrg     result |= GFC_FPE_UNDERFLOW;
    176  1.1  mrg   if (fpsr & FE_INEXACT)
    177  1.1  mrg     result |= GFC_FPE_INEXACT;
    178  1.1  mrg 
    179  1.1  mrg   return result;
    180  1.1  mrg }
    181  1.1  mrg 
    182  1.1  mrg 
    183  1.1  mrg void
    184  1.1  mrg set_fpu_except_flags (int set, int clear)
    185  1.1  mrg {
    186  1.1  mrg   unsigned int exc_set = 0, exc_clr = 0;
    187  1.1  mrg   unsigned int fpsr, fpsr_new;
    188  1.1  mrg 
    189  1.1  mrg   if (set & GFC_FPE_INVALID)
    190  1.1  mrg     exc_set |= FE_INVALID;
    191  1.1  mrg   else if (clear & GFC_FPE_INVALID)
    192  1.1  mrg     exc_clr |= FE_INVALID;
    193  1.1  mrg 
    194  1.1  mrg   if (set & GFC_FPE_ZERO)
    195  1.1  mrg     exc_set |= FE_DIVBYZERO;
    196  1.1  mrg   else if (clear & GFC_FPE_ZERO)
    197  1.1  mrg     exc_clr |= FE_DIVBYZERO;
    198  1.1  mrg 
    199  1.1  mrg   if (set & GFC_FPE_OVERFLOW)
    200  1.1  mrg     exc_set |= FE_OVERFLOW;
    201  1.1  mrg   else if (clear & GFC_FPE_OVERFLOW)
    202  1.1  mrg     exc_clr |= FE_OVERFLOW;
    203  1.1  mrg 
    204  1.1  mrg   if (set & GFC_FPE_UNDERFLOW)
    205  1.1  mrg     exc_set |= FE_UNDERFLOW;
    206  1.1  mrg   else if (clear & GFC_FPE_UNDERFLOW)
    207  1.1  mrg     exc_clr |= FE_UNDERFLOW;
    208  1.1  mrg 
    209  1.1  mrg   if (set & GFC_FPE_INEXACT)
    210  1.1  mrg     exc_set |= FE_INEXACT;
    211  1.1  mrg   else if (clear & GFC_FPE_INEXACT)
    212  1.1  mrg     exc_clr |= FE_INEXACT;
    213  1.1  mrg 
    214  1.1  mrg   fpsr_new = fpsr = __builtin_aarch64_get_fpsr();
    215  1.1  mrg   fpsr_new &= ~exc_clr;
    216  1.1  mrg   fpsr_new |= exc_set;
    217  1.1  mrg 
    218  1.1  mrg   if (fpsr_new != fpsr)
    219  1.1  mrg     __builtin_aarch64_set_fpsr(fpsr_new);
    220  1.1  mrg }
    221  1.1  mrg 
    222  1.1  mrg 
    223  1.1  mrg void
    224  1.1  mrg get_fpu_state (void *state)
    225  1.1  mrg {
    226  1.1  mrg   struct fenv *envp = state;
    227  1.1  mrg   envp->__fpcr = __builtin_aarch64_get_fpcr();
    228  1.1  mrg   envp->__fpsr = __builtin_aarch64_get_fpsr();
    229  1.1  mrg }
    230  1.1  mrg 
    231  1.1  mrg 
    232  1.1  mrg void
    233  1.1  mrg set_fpu_state (void *state)
    234  1.1  mrg {
    235  1.1  mrg   struct fenv *envp = state;
    236  1.1  mrg   __builtin_aarch64_set_fpcr(envp->__fpcr);
    237  1.1  mrg   __builtin_aarch64_set_fpsr(envp->__fpsr);
    238  1.1  mrg }
    239  1.1  mrg 
    240  1.1  mrg 
    241  1.1  mrg int
    242  1.1  mrg get_fpu_rounding_mode (void)
    243  1.1  mrg {
    244  1.1  mrg   unsigned int fpcr = __builtin_aarch64_get_fpcr();
    245  1.1  mrg   fpcr &= FPCR_RM_MASK;
    246  1.1  mrg 
    247  1.1  mrg   switch (fpcr)
    248  1.1  mrg     {
    249  1.1  mrg       case FE_TONEAREST:
    250  1.1  mrg         return GFC_FPE_TONEAREST;
    251  1.1  mrg       case FE_UPWARD:
    252  1.1  mrg         return GFC_FPE_UPWARD;
    253  1.1  mrg       case FE_DOWNWARD:
    254  1.1  mrg         return GFC_FPE_DOWNWARD;
    255  1.1  mrg       case FE_TOWARDZERO:
    256  1.1  mrg         return GFC_FPE_TOWARDZERO;
    257  1.1  mrg       default:
    258  1.1  mrg         return 0; /* Should be unreachable.  */
    259  1.1  mrg     }
    260  1.1  mrg }
    261  1.1  mrg 
    262  1.1  mrg 
    263  1.1  mrg void
    264  1.1  mrg set_fpu_rounding_mode (int round)
    265  1.1  mrg {
    266  1.1  mrg   unsigned int fpcr, round_mode;
    267  1.1  mrg 
    268  1.1  mrg   switch (round)
    269  1.1  mrg     {
    270  1.1  mrg     case GFC_FPE_TONEAREST:
    271  1.1  mrg       round_mode = FE_TONEAREST;
    272  1.1  mrg       break;
    273  1.1  mrg     case GFC_FPE_UPWARD:
    274  1.1  mrg       round_mode = FE_UPWARD;
    275  1.1  mrg       break;
    276  1.1  mrg     case GFC_FPE_DOWNWARD:
    277  1.1  mrg       round_mode = FE_DOWNWARD;
    278  1.1  mrg       break;
    279  1.1  mrg     case GFC_FPE_TOWARDZERO:
    280  1.1  mrg       round_mode = FE_TOWARDZERO;
    281  1.1  mrg       break;
    282  1.1  mrg     default:
    283  1.1  mrg       return; /* Should be unreachable.  */
    284  1.1  mrg     }
    285  1.1  mrg 
    286  1.1  mrg   fpcr = __builtin_aarch64_get_fpcr();
    287  1.1  mrg 
    288  1.1  mrg   /* Only set FPCR if requested mode is different from current.  */
    289  1.1  mrg   round_mode = (fpcr ^ round_mode) & FPCR_RM_MASK;
    290  1.1  mrg   if (round_mode != 0)
    291  1.1  mrg     __builtin_aarch64_set_fpcr(fpcr ^ round_mode);
    292  1.1  mrg }
    293  1.1  mrg 
    294  1.1  mrg 
    295  1.1  mrg int
    296  1.1  mrg support_fpu_rounding_mode (int mode __attribute__((unused)))
    297  1.1  mrg {
    298  1.1  mrg   return 1;
    299  1.1  mrg }
    300  1.1  mrg 
    301  1.1  mrg 
    302  1.1  mrg int
    303  1.1  mrg support_fpu_underflow_control (int kind __attribute__((unused)))
    304  1.1  mrg {
    305  1.1  mrg   /* Not supported for binary128.  */
    306  1.1  mrg   return (kind == 4 || kind == 8) ? 1 : 0;
    307  1.1  mrg }
    308  1.1  mrg 
    309  1.1  mrg 
    310  1.1  mrg int
    311  1.1  mrg get_fpu_underflow_mode (void)
    312  1.1  mrg {
    313  1.1  mrg   unsigned int fpcr = __builtin_aarch64_get_fpcr();
    314  1.1  mrg 
    315  1.1  mrg   /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow.  */
    316  1.1  mrg   return (fpcr & FE_MAP_FZ) ? 0 : 1;
    317  1.1  mrg }
    318  1.1  mrg 
    319  1.1  mrg 
    320  1.1  mrg void
    321  1.1  mrg set_fpu_underflow_mode (int gradual __attribute__((unused)))
    322  1.1  mrg {
    323  1.1  mrg   unsigned int fpcr = __builtin_aarch64_get_fpcr();
    324  1.1  mrg 
    325  1.1  mrg   if (gradual)
    326  1.1  mrg     fpcr &= ~FE_MAP_FZ;
    327  1.1  mrg   else
    328  1.1  mrg     fpcr |= FE_MAP_FZ;
    329  1.1  mrg 
    330  1.1  mrg   __builtin_aarch64_set_fpcr(fpcr);
    331  1.1  mrg }
    332