1 /* FPU-related code for systems with GNU libc.
2 Copyright (C) 2005-2018 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
)
43 if (trap
& GFC_FPE_INVALID
)
44 feenableexcept (FE_INVALID
);
45 if (notrap
& GFC_FPE_INVALID
)
46 fedisableexcept (FE_INVALID
);
49 /* Some glibc targets (like alpha) have FE_DENORMAL, but not many. */
51 if (trap
& GFC_FPE_DENORMAL
)
52 feenableexcept (FE_DENORMAL
);
53 if (notrap
& GFC_FPE_DENORMAL
)
54 fedisableexcept (FE_DENORMAL
);
58 if (trap
& GFC_FPE_ZERO
)
59 feenableexcept (FE_DIVBYZERO
);
60 if (notrap
& GFC_FPE_ZERO
)
61 fedisableexcept (FE_DIVBYZERO
);
65 if (trap
& GFC_FPE_OVERFLOW
)
66 feenableexcept (FE_OVERFLOW
);
67 if (notrap
& GFC_FPE_OVERFLOW
)
68 fedisableexcept (FE_OVERFLOW
);
72 if (trap
& GFC_FPE_UNDERFLOW
)
73 feenableexcept (FE_UNDERFLOW
);
74 if (notrap
& GFC_FPE_UNDERFLOW
)
75 fedisableexcept (FE_UNDERFLOW
);
79 if (trap
& GFC_FPE_INEXACT
)
80 feenableexcept (FE_INEXACT
);
81 if (notrap
& GFC_FPE_INEXACT
)
82 fedisableexcept (FE_INEXACT
);
88 get_fpu_trap_exceptions (void)
90 int exceptions
= fegetexcept ();
94 if (exceptions
& FE_INVALID
) res
|= GFC_FPE_INVALID
;
98 if (exceptions
& FE_DENORMAL
) res
|= GFC_FPE_DENORMAL
;
102 if (exceptions
& FE_DIVBYZERO
) res
|= GFC_FPE_ZERO
;
106 if (exceptions
& FE_OVERFLOW
) res
|= GFC_FPE_OVERFLOW
;
110 if (exceptions
& FE_UNDERFLOW
) res
|= GFC_FPE_UNDERFLOW
;
114 if (exceptions
& FE_INEXACT
) res
|= GFC_FPE_INEXACT
;
122 support_fpu_trap (int flag
)
127 if (!support_fpu_flag (flag
))
131 if (flag
& GFC_FPE_INVALID
) exceptions
|= FE_INVALID
;
135 if (flag
& GFC_FPE_ZERO
) exceptions
|= FE_DIVBYZERO
;
139 if (flag
& GFC_FPE_OVERFLOW
) exceptions
|= FE_OVERFLOW
;
143 if (flag
& GFC_FPE_UNDERFLOW
) exceptions
|= FE_UNDERFLOW
;
147 if (flag
& GFC_FPE_DENORMAL
) exceptions
|= FE_DENORMAL
;
151 if (flag
& GFC_FPE_INEXACT
) exceptions
|= FE_INEXACT
;
154 old
= feenableexcept (exceptions
);
157 fedisableexcept (exceptions
& ~old
);
165 if (options
.fpe
& GFC_FPE_INVALID
)
166 estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
167 "exception not supported.\n");
171 if (options
.fpe
& GFC_FPE_DENORMAL
)
172 estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
173 "exception not supported.\n");
177 if (options
.fpe
& GFC_FPE_ZERO
)
178 estr_write ("Fortran runtime warning: IEEE 'division by zero' "
179 "exception not supported.\n");
183 if (options
.fpe
& GFC_FPE_OVERFLOW
)
184 estr_write ("Fortran runtime warning: IEEE 'overflow' "
185 "exception not supported.\n");
189 if (options
.fpe
& GFC_FPE_UNDERFLOW
)
190 estr_write ("Fortran runtime warning: IEEE 'underflow' "
191 "exception not supported.\n");
195 if (options
.fpe
& GFC_FPE_INEXACT
)
196 estr_write ("Fortran runtime warning: IEEE 'inexact' "
197 "exception not supported.\n");
200 set_fpu_trap_exceptions (options
.fpe
, 0);
205 get_fpu_except_flags (void)
207 int result
, set_excepts
;
210 set_excepts
= fetestexcept (FE_ALL_EXCEPT
);
213 if (set_excepts
& FE_INVALID
)
214 result
|= GFC_FPE_INVALID
;
218 if (set_excepts
& FE_DIVBYZERO
)
219 result
|= GFC_FPE_ZERO
;
223 if (set_excepts
& FE_OVERFLOW
)
224 result
|= GFC_FPE_OVERFLOW
;
228 if (set_excepts
& FE_UNDERFLOW
)
229 result
|= GFC_FPE_UNDERFLOW
;
233 if (set_excepts
& FE_DENORMAL
)
234 result
|= GFC_FPE_DENORMAL
;
238 if (set_excepts
& FE_INEXACT
)
239 result
|= GFC_FPE_INEXACT
;
247 set_fpu_except_flags (int set
, int clear
)
249 int exc_set
= 0, exc_clr
= 0;
252 if (set
& GFC_FPE_INVALID
)
253 exc_set
|= FE_INVALID
;
254 else if (clear
& GFC_FPE_INVALID
)
255 exc_clr
|= FE_INVALID
;
259 if (set
& GFC_FPE_ZERO
)
260 exc_set
|= FE_DIVBYZERO
;
261 else if (clear
& GFC_FPE_ZERO
)
262 exc_clr
|= FE_DIVBYZERO
;
266 if (set
& GFC_FPE_OVERFLOW
)
267 exc_set
|= FE_OVERFLOW
;
268 else if (clear
& GFC_FPE_OVERFLOW
)
269 exc_clr
|= FE_OVERFLOW
;
273 if (set
& GFC_FPE_UNDERFLOW
)
274 exc_set
|= FE_UNDERFLOW
;
275 else if (clear
& GFC_FPE_UNDERFLOW
)
276 exc_clr
|= FE_UNDERFLOW
;
280 if (set
& GFC_FPE_DENORMAL
)
281 exc_set
|= FE_DENORMAL
;
282 else if (clear
& GFC_FPE_DENORMAL
)
283 exc_clr
|= FE_DENORMAL
;
287 if (set
& GFC_FPE_INEXACT
)
288 exc_set
|= FE_INEXACT
;
289 else if (clear
& GFC_FPE_INEXACT
)
290 exc_clr
|= FE_INEXACT
;
293 feclearexcept (exc_clr
);
294 feraiseexcept (exc_set
);
299 support_fpu_flag (int flag
)
301 if (flag
& GFC_FPE_INVALID
)
307 else if (flag
& GFC_FPE_ZERO
)
313 else if (flag
& GFC_FPE_OVERFLOW
)
319 else if (flag
& GFC_FPE_UNDERFLOW
)
325 else if (flag
& GFC_FPE_DENORMAL
)
331 else if (flag
& GFC_FPE_INEXACT
)
343 get_fpu_rounding_mode (void)
347 rnd_mode
= fegetround ();
353 return GFC_FPE_TONEAREST
;
358 return GFC_FPE_UPWARD
;
363 return GFC_FPE_DOWNWARD
;
368 return GFC_FPE_TOWARDZERO
;
372 return 0; /* Should be unreachable. */
378 set_fpu_rounding_mode (int mode
)
385 case GFC_FPE_TONEAREST
:
386 rnd_mode
= FE_TONEAREST
;
392 rnd_mode
= FE_UPWARD
;
397 case GFC_FPE_DOWNWARD
:
398 rnd_mode
= FE_DOWNWARD
;
403 case GFC_FPE_TOWARDZERO
:
404 rnd_mode
= FE_TOWARDZERO
;
409 return; /* Should be unreachable. */
412 fesetround (rnd_mode
);
417 support_fpu_rounding_mode (int mode
)
421 case GFC_FPE_TONEAREST
:
435 case GFC_FPE_DOWNWARD
:
442 case GFC_FPE_TOWARDZERO
:
450 return 0; /* Should be unreachable. */
456 get_fpu_state (void *state
)
463 set_fpu_state (void *state
)
469 /* Underflow in glibc is currently only supported on alpha, through
470 the FE_MAP_UMZ macro and __ieee_set_fp_control() function call. */
473 support_fpu_underflow_control (int kind
__attribute__((unused
)))
475 #if defined(__alpha__) && defined(FE_MAP_UMZ)
476 return (kind
== 4 || kind
== 8) ? 1 : 0;
484 get_fpu_underflow_mode (void)
486 #if defined(__alpha__) && defined(FE_MAP_UMZ)
488 fenv_t state
= __ieee_get_fp_control ();
490 /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow. */
491 return (state
& FE_MAP_UMZ
) ? 0 : 1;
502 set_fpu_underflow_mode (int gradual
__attribute__((unused
)))
504 #if defined(__alpha__) && defined(FE_MAP_UMZ)
506 fenv_t state
= __ieee_get_fp_control ();
509 state
&= ~FE_MAP_UMZ
;
513 __ieee_set_fp_control (state
);