attribs: Namespace-aware lookup_attribute_spec
[official-gcc.git] / libgfortran / config / fpu-glibc.h
blob61e3d86a2d10e37dd9bdf4c502d1577d095a35a0
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). */
30 #ifdef HAVE_FENV_H
31 #include <fenv.h>
32 #endif
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;
44 #ifdef FE_INVALID
45 if (trap & GFC_FPE_INVALID)
46 mode_set |= FE_INVALID;
47 if (notrap & GFC_FPE_INVALID)
48 mode_clr |= FE_INVALID;
49 #endif
51 /* Some glibc targets (like alpha) have FE_DENORMAL, but not many. */
52 #ifdef FE_DENORMAL
53 if (trap & GFC_FPE_DENORMAL)
54 mode_set |= FE_DENORMAL;
55 if (notrap & GFC_FPE_DENORMAL)
56 mode_clr |= FE_DENORMAL;
57 #endif
59 #ifdef FE_DIVBYZERO
60 if (trap & GFC_FPE_ZERO)
61 mode_set |= FE_DIVBYZERO;
62 if (notrap & GFC_FPE_ZERO)
63 mode_clr |= FE_DIVBYZERO;
64 #endif
66 #ifdef FE_OVERFLOW
67 if (trap & GFC_FPE_OVERFLOW)
68 mode_set |= FE_OVERFLOW;
69 if (notrap & GFC_FPE_OVERFLOW)
70 mode_clr |= FE_OVERFLOW;
71 #endif
73 #ifdef FE_UNDERFLOW
74 if (trap & GFC_FPE_UNDERFLOW)
75 mode_set |= FE_UNDERFLOW;
76 if (notrap & GFC_FPE_UNDERFLOW)
77 mode_clr |= FE_UNDERFLOW;
78 #endif
80 #ifdef FE_INEXACT
81 if (trap & GFC_FPE_INEXACT)
82 mode_set |= FE_INEXACT;
83 if (notrap & GFC_FPE_INEXACT)
84 mode_clr |= FE_INEXACT;
85 #endif
87 /* Clear stalled exception flags. */
88 feclearexcept (FE_ALL_EXCEPT);
90 feenableexcept (mode_set);
91 fedisableexcept (mode_clr);
95 int
96 get_fpu_trap_exceptions (void)
98 int exceptions = fegetexcept ();
99 int res = 0;
101 #ifdef FE_INVALID
102 if (exceptions & FE_INVALID) res |= GFC_FPE_INVALID;
103 #endif
105 #ifdef FE_DENORMAL
106 if (exceptions & FE_DENORMAL) res |= GFC_FPE_DENORMAL;
107 #endif
109 #ifdef FE_DIVBYZERO
110 if (exceptions & FE_DIVBYZERO) res |= GFC_FPE_ZERO;
111 #endif
113 #ifdef FE_OVERFLOW
114 if (exceptions & FE_OVERFLOW) res |= GFC_FPE_OVERFLOW;
115 #endif
117 #ifdef FE_UNDERFLOW
118 if (exceptions & FE_UNDERFLOW) res |= GFC_FPE_UNDERFLOW;
119 #endif
121 #ifdef FE_INEXACT
122 if (exceptions & FE_INEXACT) res |= GFC_FPE_INEXACT;
123 #endif
125 return res;
130 support_fpu_trap (int flag)
132 return support_fpu_flag (flag);
136 void set_fpu (void)
138 #ifndef FE_INVALID
139 if (options.fpe & GFC_FPE_INVALID)
140 estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
141 "exception not supported.\n");
142 #endif
144 #ifndef FE_DENORMAL
145 if (options.fpe & GFC_FPE_DENORMAL)
146 estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
147 "exception not supported.\n");
148 #endif
150 #ifndef FE_DIVBYZERO
151 if (options.fpe & GFC_FPE_ZERO)
152 estr_write ("Fortran runtime warning: IEEE 'division by zero' "
153 "exception not supported.\n");
154 #endif
156 #ifndef FE_OVERFLOW
157 if (options.fpe & GFC_FPE_OVERFLOW)
158 estr_write ("Fortran runtime warning: IEEE 'overflow' "
159 "exception not supported.\n");
160 #endif
162 #ifndef FE_UNDERFLOW
163 if (options.fpe & GFC_FPE_UNDERFLOW)
164 estr_write ("Fortran runtime warning: IEEE 'underflow' "
165 "exception not supported.\n");
166 #endif
168 #ifndef FE_INEXACT
169 if (options.fpe & GFC_FPE_INEXACT)
170 estr_write ("Fortran runtime warning: IEEE 'inexact' "
171 "exception not supported.\n");
172 #endif
174 set_fpu_trap_exceptions (options.fpe, 0);
179 get_fpu_except_flags (void)
181 int result, set_excepts;
183 result = 0;
184 set_excepts = fetestexcept (FE_ALL_EXCEPT);
186 #ifdef FE_INVALID
187 if (set_excepts & FE_INVALID)
188 result |= GFC_FPE_INVALID;
189 #endif
191 #ifdef FE_DIVBYZERO
192 if (set_excepts & FE_DIVBYZERO)
193 result |= GFC_FPE_ZERO;
194 #endif
196 #ifdef FE_OVERFLOW
197 if (set_excepts & FE_OVERFLOW)
198 result |= GFC_FPE_OVERFLOW;
199 #endif
201 #ifdef FE_UNDERFLOW
202 if (set_excepts & FE_UNDERFLOW)
203 result |= GFC_FPE_UNDERFLOW;
204 #endif
206 #ifdef FE_DENORMAL
207 if (set_excepts & FE_DENORMAL)
208 result |= GFC_FPE_DENORMAL;
209 #endif
211 #ifdef FE_INEXACT
212 if (set_excepts & FE_INEXACT)
213 result |= GFC_FPE_INEXACT;
214 #endif
216 return result;
220 void
221 set_fpu_except_flags (int set, int clear)
223 int exc_set = 0, exc_clr = 0;
225 #ifdef FE_INVALID
226 if (set & GFC_FPE_INVALID)
227 exc_set |= FE_INVALID;
228 else if (clear & GFC_FPE_INVALID)
229 exc_clr |= FE_INVALID;
230 #endif
232 #ifdef FE_DIVBYZERO
233 if (set & GFC_FPE_ZERO)
234 exc_set |= FE_DIVBYZERO;
235 else if (clear & GFC_FPE_ZERO)
236 exc_clr |= FE_DIVBYZERO;
237 #endif
239 #ifdef FE_OVERFLOW
240 if (set & GFC_FPE_OVERFLOW)
241 exc_set |= FE_OVERFLOW;
242 else if (clear & GFC_FPE_OVERFLOW)
243 exc_clr |= FE_OVERFLOW;
244 #endif
246 #ifdef FE_UNDERFLOW
247 if (set & GFC_FPE_UNDERFLOW)
248 exc_set |= FE_UNDERFLOW;
249 else if (clear & GFC_FPE_UNDERFLOW)
250 exc_clr |= FE_UNDERFLOW;
251 #endif
253 #ifdef FE_DENORMAL
254 if (set & GFC_FPE_DENORMAL)
255 exc_set |= FE_DENORMAL;
256 else if (clear & GFC_FPE_DENORMAL)
257 exc_clr |= FE_DENORMAL;
258 #endif
260 #ifdef FE_INEXACT
261 if (set & GFC_FPE_INEXACT)
262 exc_set |= FE_INEXACT;
263 else if (clear & GFC_FPE_INEXACT)
264 exc_clr |= FE_INEXACT;
265 #endif
267 feclearexcept (exc_clr);
268 feraiseexcept (exc_set);
273 support_fpu_flag (int flag)
275 if (flag & GFC_FPE_INVALID)
277 #ifndef FE_INVALID
278 return 0;
279 #endif
281 else if (flag & GFC_FPE_ZERO)
283 #ifndef FE_DIVBYZERO
284 return 0;
285 #endif
287 else if (flag & GFC_FPE_OVERFLOW)
289 #ifndef FE_OVERFLOW
290 return 0;
291 #endif
293 else if (flag & GFC_FPE_UNDERFLOW)
295 #ifndef FE_UNDERFLOW
296 return 0;
297 #endif
299 else if (flag & GFC_FPE_DENORMAL)
301 #ifndef FE_DENORMAL
302 return 0;
303 #endif
305 else if (flag & GFC_FPE_INEXACT)
307 #ifndef FE_INEXACT
308 return 0;
309 #endif
312 return 1;
317 get_fpu_rounding_mode (void)
319 int rnd_mode;
321 rnd_mode = fegetround ();
323 switch (rnd_mode)
325 #ifdef FE_TONEAREST
326 case FE_TONEAREST:
327 return GFC_FPE_TONEAREST;
328 #endif
330 #ifdef FE_UPWARD
331 case FE_UPWARD:
332 return GFC_FPE_UPWARD;
333 #endif
335 #ifdef FE_DOWNWARD
336 case FE_DOWNWARD:
337 return GFC_FPE_DOWNWARD;
338 #endif
340 #ifdef FE_TOWARDZERO
341 case FE_TOWARDZERO:
342 return GFC_FPE_TOWARDZERO;
343 #endif
345 #ifdef FE_TONEARESTFROMZERO
346 case FE_TONEARESTFROMZERO:
347 return GFC_FPE_AWAY;
348 #endif
350 default:
351 return 0; /* Should be unreachable. */
356 void
357 set_fpu_rounding_mode (int mode)
359 int rnd_mode;
361 switch (mode)
363 #ifdef FE_TONEAREST
364 case GFC_FPE_TONEAREST:
365 rnd_mode = FE_TONEAREST;
366 break;
367 #endif
369 #ifdef FE_UPWARD
370 case GFC_FPE_UPWARD:
371 rnd_mode = FE_UPWARD;
372 break;
373 #endif
375 #ifdef FE_DOWNWARD
376 case GFC_FPE_DOWNWARD:
377 rnd_mode = FE_DOWNWARD;
378 break;
379 #endif
381 #ifdef FE_TOWARDZERO
382 case GFC_FPE_TOWARDZERO:
383 rnd_mode = FE_TOWARDZERO;
384 break;
385 #endif
387 #ifdef FE_TONEARESTFROMZERO
388 case GFC_FPE_AWAY:
389 rnd_mode = FE_TONEARESTFROMZERO;
390 break;
391 #endif
393 default:
394 return; /* Should be unreachable. */
397 fesetround (rnd_mode);
402 support_fpu_rounding_mode (int mode)
404 switch (mode)
406 case GFC_FPE_TONEAREST:
407 #ifdef FE_TONEAREST
408 return 1;
409 #else
410 return 0;
411 #endif
413 case GFC_FPE_UPWARD:
414 #ifdef FE_UPWARD
415 return 1;
416 #else
417 return 0;
418 #endif
420 case GFC_FPE_DOWNWARD:
421 #ifdef FE_DOWNWARD
422 return 1;
423 #else
424 return 0;
425 #endif
427 case GFC_FPE_TOWARDZERO:
428 #ifdef FE_TOWARDZERO
429 return 1;
430 #else
431 return 0;
432 #endif
434 case GFC_FPE_AWAY:
435 #ifdef FE_TONEARESTFROMZERO
436 return 1;
437 #else
438 return 0;
439 #endif
441 default:
442 return 0; /* Should be unreachable. */
447 void
448 get_fpu_state (void *state)
450 fegetenv (state);
454 void
455 set_fpu_state (void *state)
457 fesetenv (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;
469 #else
470 return 0;
471 #endif
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;
485 #else
487 return 0;
489 #endif
493 void
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 ();
500 if (gradual)
501 state &= ~FE_MAP_UMZ;
502 else
503 state |= FE_MAP_UMZ;
505 __ieee_set_fp_control (state);
507 #endif