1 /* FPU-related code for systems with GNU libc.
2 Copyright (C) 2005-2023 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
)
132 return support_fpu_flag (flag
);
139 if (options
.fpe
& GFC_FPE_INVALID
)
140 estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
141 "exception not supported.\n");
145 if (options
.fpe
& GFC_FPE_DENORMAL
)
146 estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
147 "exception not supported.\n");
151 if (options
.fpe
& GFC_FPE_ZERO
)
152 estr_write ("Fortran runtime warning: IEEE 'division by zero' "
153 "exception not supported.\n");
157 if (options
.fpe
& GFC_FPE_OVERFLOW
)
158 estr_write ("Fortran runtime warning: IEEE 'overflow' "
159 "exception not supported.\n");
163 if (options
.fpe
& GFC_FPE_UNDERFLOW
)
164 estr_write ("Fortran runtime warning: IEEE 'underflow' "
165 "exception not supported.\n");
169 if (options
.fpe
& GFC_FPE_INEXACT
)
170 estr_write ("Fortran runtime warning: IEEE 'inexact' "
171 "exception not supported.\n");
174 set_fpu_trap_exceptions (options
.fpe
, 0);
179 get_fpu_except_flags (void)
181 int result
, set_excepts
;
184 set_excepts
= fetestexcept (FE_ALL_EXCEPT
);
187 if (set_excepts
& FE_INVALID
)
188 result
|= GFC_FPE_INVALID
;
192 if (set_excepts
& FE_DIVBYZERO
)
193 result
|= GFC_FPE_ZERO
;
197 if (set_excepts
& FE_OVERFLOW
)
198 result
|= GFC_FPE_OVERFLOW
;
202 if (set_excepts
& FE_UNDERFLOW
)
203 result
|= GFC_FPE_UNDERFLOW
;
207 if (set_excepts
& FE_DENORMAL
)
208 result
|= GFC_FPE_DENORMAL
;
212 if (set_excepts
& FE_INEXACT
)
213 result
|= GFC_FPE_INEXACT
;
221 set_fpu_except_flags (int set
, int clear
)
223 int exc_set
= 0, exc_clr
= 0;
226 if (set
& GFC_FPE_INVALID
)
227 exc_set
|= FE_INVALID
;
228 else if (clear
& GFC_FPE_INVALID
)
229 exc_clr
|= FE_INVALID
;
233 if (set
& GFC_FPE_ZERO
)
234 exc_set
|= FE_DIVBYZERO
;
235 else if (clear
& GFC_FPE_ZERO
)
236 exc_clr
|= FE_DIVBYZERO
;
240 if (set
& GFC_FPE_OVERFLOW
)
241 exc_set
|= FE_OVERFLOW
;
242 else if (clear
& GFC_FPE_OVERFLOW
)
243 exc_clr
|= FE_OVERFLOW
;
247 if (set
& GFC_FPE_UNDERFLOW
)
248 exc_set
|= FE_UNDERFLOW
;
249 else if (clear
& GFC_FPE_UNDERFLOW
)
250 exc_clr
|= FE_UNDERFLOW
;
254 if (set
& GFC_FPE_DENORMAL
)
255 exc_set
|= FE_DENORMAL
;
256 else if (clear
& GFC_FPE_DENORMAL
)
257 exc_clr
|= FE_DENORMAL
;
261 if (set
& GFC_FPE_INEXACT
)
262 exc_set
|= FE_INEXACT
;
263 else if (clear
& GFC_FPE_INEXACT
)
264 exc_clr
|= FE_INEXACT
;
267 feclearexcept (exc_clr
);
268 feraiseexcept (exc_set
);
273 support_fpu_flag (int flag
)
275 if (flag
& GFC_FPE_INVALID
)
281 else if (flag
& GFC_FPE_ZERO
)
287 else if (flag
& GFC_FPE_OVERFLOW
)
293 else if (flag
& GFC_FPE_UNDERFLOW
)
299 else if (flag
& GFC_FPE_DENORMAL
)
305 else if (flag
& GFC_FPE_INEXACT
)
317 get_fpu_rounding_mode (void)
321 rnd_mode
= fegetround ();
327 return GFC_FPE_TONEAREST
;
332 return GFC_FPE_UPWARD
;
337 return GFC_FPE_DOWNWARD
;
342 return GFC_FPE_TOWARDZERO
;
345 #ifdef FE_TONEARESTFROMZERO
346 case FE_TONEARESTFROMZERO
:
351 return 0; /* Should be unreachable. */
357 set_fpu_rounding_mode (int mode
)
364 case GFC_FPE_TONEAREST
:
365 rnd_mode
= FE_TONEAREST
;
371 rnd_mode
= FE_UPWARD
;
376 case GFC_FPE_DOWNWARD
:
377 rnd_mode
= FE_DOWNWARD
;
382 case GFC_FPE_TOWARDZERO
:
383 rnd_mode
= FE_TOWARDZERO
;
387 #ifdef FE_TONEARESTFROMZERO
389 rnd_mode
= FE_TONEARESTFROMZERO
;
394 return; /* Should be unreachable. */
397 fesetround (rnd_mode
);
402 support_fpu_rounding_mode (int mode
)
406 case GFC_FPE_TONEAREST
:
420 case GFC_FPE_DOWNWARD
:
427 case GFC_FPE_TOWARDZERO
:
435 #ifdef FE_TONEARESTFROMZERO
442 return 0; /* Should be unreachable. */
448 get_fpu_state (void *state
)
455 set_fpu_state (void *state
)
461 /* Underflow in glibc is currently only supported on alpha, through
462 the FE_MAP_UMZ macro and __ieee_set_fp_control() function call. */
465 support_fpu_underflow_control (int kind
__attribute__((unused
)))
467 #if defined(__alpha__) && defined(FE_MAP_UMZ)
468 return (kind
== 4 || kind
== 8) ? 1 : 0;
476 get_fpu_underflow_mode (void)
478 #if defined(__alpha__) && defined(FE_MAP_UMZ)
480 fenv_t state
= __ieee_get_fp_control ();
482 /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow. */
483 return (state
& FE_MAP_UMZ
) ? 0 : 1;
494 set_fpu_underflow_mode (int gradual
__attribute__((unused
)))
496 #if defined(__alpha__) && defined(FE_MAP_UMZ)
498 fenv_t state
= __ieee_get_fp_control ();
501 state
&= ~FE_MAP_UMZ
;
505 __ieee_set_fp_control (state
);