1 /* FPU-related code for systems with GNU libc.
2 Copyright (C) 2005-2019 Free Software Foundation, Inc.
3 Contributed by Francois-Xavier Coudert <coudert@clipper.ens.fr>
5 This file is part of the GNU Fortran runtime library (libgfortran).
7 Libgfortran is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 3 of the License, or (at your option) any later version.
12 Libgfortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
26 /* FPU-related code for systems with the GNU libc, providing the
27 feenableexcept function in fenv.h to set individual exceptions
28 (there's nothing to do that in C99). */
35 /* Check we can actually store the FPU state in the allocated size. */
36 _Static_assert (sizeof(fenv_t
) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE
,
37 "GFC_FPE_STATE_BUFFER_SIZE is too small");
40 void set_fpu_trap_exceptions (int trap
, int notrap
)
42 int mode_set
= 0, mode_clr
= 0;
45 if (trap
& GFC_FPE_INVALID
)
46 mode_set
|= FE_INVALID
;
47 if (notrap
& GFC_FPE_INVALID
)
48 mode_clr
|= FE_INVALID
;
51 /* Some glibc targets (like alpha) have FE_DENORMAL, but not many. */
53 if (trap
& GFC_FPE_DENORMAL
)
54 mode_set
|= FE_DENORMAL
;
55 if (notrap
& GFC_FPE_DENORMAL
)
56 mode_clr
|= FE_DENORMAL
;
60 if (trap
& GFC_FPE_ZERO
)
61 mode_set
|= FE_DIVBYZERO
;
62 if (notrap
& GFC_FPE_ZERO
)
63 mode_clr
|= FE_DIVBYZERO
;
67 if (trap
& GFC_FPE_OVERFLOW
)
68 mode_set
|= FE_OVERFLOW
;
69 if (notrap
& GFC_FPE_OVERFLOW
)
70 mode_clr
|= FE_OVERFLOW
;
74 if (trap
& GFC_FPE_UNDERFLOW
)
75 mode_set
|= FE_UNDERFLOW
;
76 if (notrap
& GFC_FPE_UNDERFLOW
)
77 mode_clr
|= FE_UNDERFLOW
;
81 if (trap
& GFC_FPE_INEXACT
)
82 mode_set
|= FE_INEXACT
;
83 if (notrap
& GFC_FPE_INEXACT
)
84 mode_clr
|= FE_INEXACT
;
87 /* Clear stalled exception flags. */
88 feclearexcept (FE_ALL_EXCEPT
);
90 feenableexcept (mode_set
);
91 fedisableexcept (mode_clr
);
96 get_fpu_trap_exceptions (void)
98 int exceptions
= fegetexcept ();
102 if (exceptions
& FE_INVALID
) res
|= GFC_FPE_INVALID
;
106 if (exceptions
& FE_DENORMAL
) res
|= GFC_FPE_DENORMAL
;
110 if (exceptions
& FE_DIVBYZERO
) res
|= GFC_FPE_ZERO
;
114 if (exceptions
& FE_OVERFLOW
) res
|= GFC_FPE_OVERFLOW
;
118 if (exceptions
& FE_UNDERFLOW
) res
|= GFC_FPE_UNDERFLOW
;
122 if (exceptions
& FE_INEXACT
) res
|= GFC_FPE_INEXACT
;
130 support_fpu_trap (int flag
)
135 if (!support_fpu_flag (flag
))
139 if (flag
& GFC_FPE_INVALID
) exceptions
|= FE_INVALID
;
143 if (flag
& GFC_FPE_ZERO
) exceptions
|= FE_DIVBYZERO
;
147 if (flag
& GFC_FPE_OVERFLOW
) exceptions
|= FE_OVERFLOW
;
151 if (flag
& GFC_FPE_UNDERFLOW
) exceptions
|= FE_UNDERFLOW
;
155 if (flag
& GFC_FPE_DENORMAL
) exceptions
|= FE_DENORMAL
;
159 if (flag
& GFC_FPE_INEXACT
) exceptions
|= FE_INEXACT
;
162 old
= feenableexcept (exceptions
);
165 fedisableexcept (exceptions
& ~old
);
173 if (options
.fpe
& GFC_FPE_INVALID
)
174 estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
175 "exception not supported.\n");
179 if (options
.fpe
& GFC_FPE_DENORMAL
)
180 estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
181 "exception not supported.\n");
185 if (options
.fpe
& GFC_FPE_ZERO
)
186 estr_write ("Fortran runtime warning: IEEE 'division by zero' "
187 "exception not supported.\n");
191 if (options
.fpe
& GFC_FPE_OVERFLOW
)
192 estr_write ("Fortran runtime warning: IEEE 'overflow' "
193 "exception not supported.\n");
197 if (options
.fpe
& GFC_FPE_UNDERFLOW
)
198 estr_write ("Fortran runtime warning: IEEE 'underflow' "
199 "exception not supported.\n");
203 if (options
.fpe
& GFC_FPE_INEXACT
)
204 estr_write ("Fortran runtime warning: IEEE 'inexact' "
205 "exception not supported.\n");
208 set_fpu_trap_exceptions (options
.fpe
, 0);
213 get_fpu_except_flags (void)
215 int result
, set_excepts
;
218 set_excepts
= fetestexcept (FE_ALL_EXCEPT
);
221 if (set_excepts
& FE_INVALID
)
222 result
|= GFC_FPE_INVALID
;
226 if (set_excepts
& FE_DIVBYZERO
)
227 result
|= GFC_FPE_ZERO
;
231 if (set_excepts
& FE_OVERFLOW
)
232 result
|= GFC_FPE_OVERFLOW
;
236 if (set_excepts
& FE_UNDERFLOW
)
237 result
|= GFC_FPE_UNDERFLOW
;
241 if (set_excepts
& FE_DENORMAL
)
242 result
|= GFC_FPE_DENORMAL
;
246 if (set_excepts
& FE_INEXACT
)
247 result
|= GFC_FPE_INEXACT
;
255 set_fpu_except_flags (int set
, int clear
)
257 int exc_set
= 0, exc_clr
= 0;
260 if (set
& GFC_FPE_INVALID
)
261 exc_set
|= FE_INVALID
;
262 else if (clear
& GFC_FPE_INVALID
)
263 exc_clr
|= FE_INVALID
;
267 if (set
& GFC_FPE_ZERO
)
268 exc_set
|= FE_DIVBYZERO
;
269 else if (clear
& GFC_FPE_ZERO
)
270 exc_clr
|= FE_DIVBYZERO
;
274 if (set
& GFC_FPE_OVERFLOW
)
275 exc_set
|= FE_OVERFLOW
;
276 else if (clear
& GFC_FPE_OVERFLOW
)
277 exc_clr
|= FE_OVERFLOW
;
281 if (set
& GFC_FPE_UNDERFLOW
)
282 exc_set
|= FE_UNDERFLOW
;
283 else if (clear
& GFC_FPE_UNDERFLOW
)
284 exc_clr
|= FE_UNDERFLOW
;
288 if (set
& GFC_FPE_DENORMAL
)
289 exc_set
|= FE_DENORMAL
;
290 else if (clear
& GFC_FPE_DENORMAL
)
291 exc_clr
|= FE_DENORMAL
;
295 if (set
& GFC_FPE_INEXACT
)
296 exc_set
|= FE_INEXACT
;
297 else if (clear
& GFC_FPE_INEXACT
)
298 exc_clr
|= FE_INEXACT
;
301 feclearexcept (exc_clr
);
302 feraiseexcept (exc_set
);
307 support_fpu_flag (int flag
)
309 if (flag
& GFC_FPE_INVALID
)
315 else if (flag
& GFC_FPE_ZERO
)
321 else if (flag
& GFC_FPE_OVERFLOW
)
327 else if (flag
& GFC_FPE_UNDERFLOW
)
333 else if (flag
& GFC_FPE_DENORMAL
)
339 else if (flag
& GFC_FPE_INEXACT
)
351 get_fpu_rounding_mode (void)
355 rnd_mode
= fegetround ();
361 return GFC_FPE_TONEAREST
;
366 return GFC_FPE_UPWARD
;
371 return GFC_FPE_DOWNWARD
;
376 return GFC_FPE_TOWARDZERO
;
380 return 0; /* Should be unreachable. */
386 set_fpu_rounding_mode (int mode
)
393 case GFC_FPE_TONEAREST
:
394 rnd_mode
= FE_TONEAREST
;
400 rnd_mode
= FE_UPWARD
;
405 case GFC_FPE_DOWNWARD
:
406 rnd_mode
= FE_DOWNWARD
;
411 case GFC_FPE_TOWARDZERO
:
412 rnd_mode
= FE_TOWARDZERO
;
417 return; /* Should be unreachable. */
420 fesetround (rnd_mode
);
425 support_fpu_rounding_mode (int mode
)
429 case GFC_FPE_TONEAREST
:
443 case GFC_FPE_DOWNWARD
:
450 case GFC_FPE_TOWARDZERO
:
458 return 0; /* Should be unreachable. */
464 get_fpu_state (void *state
)
471 set_fpu_state (void *state
)
477 /* Underflow in glibc is currently only supported on alpha, through
478 the FE_MAP_UMZ macro and __ieee_set_fp_control() function call. */
481 support_fpu_underflow_control (int kind
__attribute__((unused
)))
483 #if defined(__alpha__) && defined(FE_MAP_UMZ)
484 return (kind
== 4 || kind
== 8) ? 1 : 0;
492 get_fpu_underflow_mode (void)
494 #if defined(__alpha__) && defined(FE_MAP_UMZ)
496 fenv_t state
= __ieee_get_fp_control ();
498 /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow. */
499 return (state
& FE_MAP_UMZ
) ? 0 : 1;
510 set_fpu_underflow_mode (int gradual
__attribute__((unused
)))
512 #if defined(__alpha__) && defined(FE_MAP_UMZ)
514 fenv_t state
= __ieee_get_fp_control ();
517 state
&= ~FE_MAP_UMZ
;
521 __ieee_set_fp_control (state
);