1 /* FPU-related code for systems with GNU libc.
2 Copyright (C) 2005-2014 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
)
124 return support_fpu_flag (flag
);
131 if (options
.fpe
& GFC_FPE_INVALID
)
132 estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
133 "exception not supported.\n");
137 if (options
.fpe
& GFC_FPE_DENORMAL
)
138 estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
139 "exception not supported.\n");
143 if (options
.fpe
& GFC_FPE_ZERO
)
144 estr_write ("Fortran runtime warning: IEEE 'division by zero' "
145 "exception not supported.\n");
149 if (options
.fpe
& GFC_FPE_OVERFLOW
)
150 estr_write ("Fortran runtime warning: IEEE 'overflow' "
151 "exception not supported.\n");
155 if (options
.fpe
& GFC_FPE_UNDERFLOW
)
156 estr_write ("Fortran runtime warning: IEEE 'underflow' "
157 "exception not supported.\n");
161 if (options
.fpe
& GFC_FPE_INEXACT
)
162 estr_write ("Fortran runtime warning: IEEE 'inexact' "
163 "exception not supported.\n");
166 set_fpu_trap_exceptions (options
.fpe
, 0);
171 get_fpu_except_flags (void)
173 int result
, set_excepts
;
176 set_excepts
= fetestexcept (FE_ALL_EXCEPT
);
179 if (set_excepts
& FE_INVALID
)
180 result
|= GFC_FPE_INVALID
;
184 if (set_excepts
& FE_DIVBYZERO
)
185 result
|= GFC_FPE_ZERO
;
189 if (set_excepts
& FE_OVERFLOW
)
190 result
|= GFC_FPE_OVERFLOW
;
194 if (set_excepts
& FE_UNDERFLOW
)
195 result
|= GFC_FPE_UNDERFLOW
;
199 if (set_excepts
& FE_DENORMAL
)
200 result
|= GFC_FPE_DENORMAL
;
204 if (set_excepts
& FE_INEXACT
)
205 result
|= GFC_FPE_INEXACT
;
213 set_fpu_except_flags (int set
, int clear
)
215 int exc_set
= 0, exc_clr
= 0;
218 if (set
& GFC_FPE_INVALID
)
219 exc_set
|= FE_INVALID
;
220 else if (clear
& GFC_FPE_INVALID
)
221 exc_clr
|= FE_INVALID
;
225 if (set
& GFC_FPE_ZERO
)
226 exc_set
|= FE_DIVBYZERO
;
227 else if (clear
& GFC_FPE_ZERO
)
228 exc_clr
|= FE_DIVBYZERO
;
232 if (set
& GFC_FPE_OVERFLOW
)
233 exc_set
|= FE_OVERFLOW
;
234 else if (clear
& GFC_FPE_OVERFLOW
)
235 exc_clr
|= FE_OVERFLOW
;
239 if (set
& GFC_FPE_UNDERFLOW
)
240 exc_set
|= FE_UNDERFLOW
;
241 else if (clear
& GFC_FPE_UNDERFLOW
)
242 exc_clr
|= FE_UNDERFLOW
;
246 if (set
& GFC_FPE_DENORMAL
)
247 exc_set
|= FE_DENORMAL
;
248 else if (clear
& GFC_FPE_DENORMAL
)
249 exc_clr
|= FE_DENORMAL
;
253 if (set
& GFC_FPE_INEXACT
)
254 exc_set
|= FE_INEXACT
;
255 else if (clear
& GFC_FPE_INEXACT
)
256 exc_clr
|= FE_INEXACT
;
259 feclearexcept (exc_clr
);
260 feraiseexcept (exc_set
);
265 support_fpu_flag (int flag
)
267 if (flag
& GFC_FPE_INVALID
)
273 else if (flag
& GFC_FPE_ZERO
)
279 else if (flag
& GFC_FPE_OVERFLOW
)
285 else if (flag
& GFC_FPE_UNDERFLOW
)
291 else if (flag
& GFC_FPE_DENORMAL
)
297 else if (flag
& GFC_FPE_INEXACT
)
309 get_fpu_rounding_mode (void)
313 rnd_mode
= fegetround ();
319 return GFC_FPE_TONEAREST
;
324 return GFC_FPE_UPWARD
;
329 return GFC_FPE_DOWNWARD
;
334 return GFC_FPE_TOWARDZERO
;
338 return 0; /* Should be unreachable. */
344 set_fpu_rounding_mode (int mode
)
351 case GFC_FPE_TONEAREST
:
352 rnd_mode
= FE_TONEAREST
;
358 rnd_mode
= FE_UPWARD
;
363 case GFC_FPE_DOWNWARD
:
364 rnd_mode
= FE_DOWNWARD
;
369 case GFC_FPE_TOWARDZERO
:
370 rnd_mode
= FE_TOWARDZERO
;
375 return; /* Should be unreachable. */
378 fesetround (rnd_mode
);
383 support_fpu_rounding_mode (int mode
)
387 case GFC_FPE_TONEAREST
:
401 case GFC_FPE_DOWNWARD
:
408 case GFC_FPE_TOWARDZERO
:
416 return 0; /* Should be unreachable. */
422 get_fpu_state (void *state
)
429 set_fpu_state (void *state
)
435 /* Underflow in glibc is currently only supported on alpha, through
436 the FE_MAP_UMZ macro and __ieee_set_fp_control() function call. */
439 support_fpu_underflow_control (int kind
__attribute__((unused
)))
441 #if defined(__alpha__) && defined(FE_MAP_UMZ)
442 return (kind
== 4 || kind
== 8) ? 1 : 0;
450 get_fpu_underflow_mode (void)
452 #if defined(__alpha__) && defined(FE_MAP_UMZ)
454 fenv_t state
= __ieee_get_fp_control ();
456 /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow. */
457 return (state
& FE_MAP_UMZ
) ? 0 : 1;
468 set_fpu_underflow_mode (int gradual
__attribute__((unused
)))
470 #if defined(__alpha__) && defined(FE_MAP_UMZ)
472 fenv_t state
= __ieee_get_fp_control ();
475 state
&= ~FE_MAP_UMZ
;
479 __ieee_set_fp_control (state
);