exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / fenv-except-state-set.c
blobcafad201e34e41c5e3aa755152b45b4d5e0aee18
1 /* Functions for saving the floating-point exception status flags.
2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Based on glibc/sysdeps/<cpu>/{fgetexcptflg.c,fsetexcptflg.c}
18 together with glibc/sysdeps/<cpu>/{fpu_control.h,fenv_private.h,fenv_libc.h}. */
20 #include <config.h>
22 /* Specification. */
23 #include <fenv.h>
25 #include "fenv-private.h"
27 #if defined __GNUC__ || defined __clang__ || defined _MSC_VER
29 # if (defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)
31 /* On most OSes, fexcept_t is binary-equivalent to an 'unsigned short'.
32 On NetBSD, OpenBSD, Solaris, Cygwin, MSVC, Android/x86_64, Minix, fexcept_t
33 is equivalent to an 'unsigned int'.
34 A simple C cast does the necessary conversion. */
36 int
37 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
39 exceptions &= FE_ALL_EXCEPT;
41 unsigned int desired_flags = (unsigned int) *saved_flags;
43 # if defined _MSC_VER
44 exceptions = exceptions_to_x86hardware (exceptions);
45 desired_flags = exceptions_to_x86hardware (desired_flags);
47 /* Modify the flags in the SSE unit. */
48 unsigned int mxcsr, orig_mxcsr;
49 _FPU_GETSSECW (orig_mxcsr);
50 mxcsr = orig_mxcsr ^ ((orig_mxcsr ^ desired_flags) & exceptions);
51 if (mxcsr != orig_mxcsr)
52 _FPU_SETSSECW (mxcsr);
54 # else
56 /* The flags can be set in the 387 unit or in the SSE unit.
57 When we need to clear a flag, we need to do so in both units,
58 due to the way fetestexcept() is implemented.
59 When we need to set a flag, it is sufficient to do it in the SSE unit,
60 because that is guaranteed to not trap. However, on i386 CPUs that have
61 only a 387 unit, set the flags in the 387, as long as this cannot trap. */
63 if (CPU_HAS_SSE ())
65 /* Modify the flags in the SSE unit. */
66 unsigned int mxcsr, orig_mxcsr;
67 _FPU_GETSSECW (orig_mxcsr);
68 mxcsr = orig_mxcsr ^ ((orig_mxcsr ^ desired_flags) & exceptions);
69 if (mxcsr != orig_mxcsr)
70 _FPU_SETSSECW (mxcsr);
72 /* Modify the flags in the 387 unit, but only by clearing bits, not by
73 setting bits. */
74 x86_387_fenv_t env;
75 __asm__ __volatile__ ("fnstenv %0" : "=m" (*&env));
76 /* Note: fnstenv masks all floating-point exceptions until the fldenv
77 below. */
78 env.__status_word &= ~ (exceptions & ~desired_flags);
79 __asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
81 # if !(defined __x86_64__ || defined _M_X64)
82 else
84 /* Modify the flags in the 387 unit. */
85 x86_387_fenv_t env;
86 __asm__ __volatile__ ("fnstenv %0" : "=m" (*&env));
87 /* Note: fnstenv masks all floating-point exceptions until the fldenv
88 or fldcw below. */
89 env.__status_word ^= ((env.__status_word ^ desired_flags) & exceptions);
90 if ((~env.__control_word) & env.__status_word & exceptions)
92 /* Setting the exception flags may trigger a trap (at the next
93 floating-point instruction, but that does not matter).
94 ISO C 23 § 7.6.4.5 does not allow it. */
95 __asm__ __volatile__ ("fldcw %0" : : "m" (*&env.__control_word));
96 return -1;
98 __asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
100 # endif
101 # endif
102 return 0;
105 # elif defined __aarch64__ /* arm64 */
107 /* On Linux, NetBSD, and Android, fexcept_t is binary-equivalent to
108 an 'unsigned int'.
109 On macOS, fexcept_t is binary-equivalent to an 'unsigned short'.
110 On FreeBSD and OpenBSD, fexcept_t is binary-equivalent to an 'unsigned long'.
111 A simple C cast does the necessary conversion. */
114 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
116 unsigned long desired_flags = (unsigned long) *saved_flags;
117 unsigned long fpsr, orig_fpsr;
118 _FPU_GETFPSR (orig_fpsr);
119 fpsr = orig_fpsr ^ ((orig_fpsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
120 if (fpsr != orig_fpsr)
121 _FPU_SETFPSR (fpsr);
122 /* Possibly some new exception flags have been set. But just storing them
123 does not cause a trap to be executed (when traps are enabled). */
124 return 0;
127 # elif defined __arm__
129 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
132 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
134 # ifdef __SOFTFP__
135 if (exceptions != 0)
136 return -1;
137 # else
138 unsigned int desired_flags = (unsigned int) *saved_flags;
139 unsigned int fpscr, orig_fpscr;
140 _FPU_GETCW (orig_fpscr);
141 fpscr = orig_fpscr ^ ((orig_fpscr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
142 if (fpscr != orig_fpscr)
143 _FPU_SETCW (fpscr);
144 # endif
145 return 0;
148 # elif defined __alpha
150 /* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
151 an 'unsigned long'.
152 On NetBSD, it is equivalent to an 'unsigned short'.
153 On OpenBSD, it is equivalent to an 'unsigned int'.
154 A simple C cast does the necessary conversion. */
157 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
159 unsigned long desired_flags = (unsigned long) *saved_flags;
160 unsigned long swcr, orig_swcr;
161 orig_swcr = __ieee_get_fp_control ();
162 swcr = orig_swcr ^ ((orig_swcr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
163 if (swcr != orig_swcr)
164 __ieee_set_fp_control (swcr);
165 /* Possibly some new exception flags have been set. But just storing them
166 does not cause a trap to be executed (when traps are enabled). */
167 return 0;
170 # elif defined __hppa
172 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
175 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
177 unsigned int desired_flags = (unsigned int) *saved_flags;
178 union { unsigned long long fpreg; unsigned int halfreg[2]; } s;
179 /* Get the current status word. */
180 __asm__ __volatile__ ("fstd %%fr0,0(%1)" : "=m" (s.fpreg) : "r" (&s.fpreg) : "%r0");
181 unsigned int old_halfreg0 = s.halfreg[0];
182 /* Modify all the relevant bits. */
183 s.halfreg[0] ^= (s.halfreg[0] ^ (desired_flags << 27)) & ((FE_ALL_EXCEPT & exceptions) << 27);
184 if (s.halfreg[0] != old_halfreg0)
186 /* Store the new status word. */
187 __asm__ __volatile__ ("fldd 0(%0),%%fr0" : : "r" (&s.fpreg), "m" (s.fpreg) : "%r0");
189 /* Possibly some new exception flags have been set. But just storing them
190 does not cause a trap to be executed (when traps are enabled). */
191 return 0;
194 # elif defined __ia64__
196 /* On all OSes except NetBSD, fexcept_t is binary-equivalent to
197 an 'unsigned long'.
198 On NetBSD, it is equivalent to an 'unsigned short'.
199 A simple C cast does the necessary conversion. */
202 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
204 unsigned long desired_flags = (unsigned long) *saved_flags;
205 unsigned long fpsr, orig_fpsr;
206 _FPU_GETCW (orig_fpsr);
207 fpsr = orig_fpsr ^ ((orig_fpsr ^ (desired_flags << 13)) & ((FE_ALL_EXCEPT & exceptions) << 13));
208 if (fpsr != orig_fpsr)
209 _FPU_SETCW (fpsr);
210 /* Possibly some new exception flags have been set. But just storing them
211 does not cause a trap to be executed (when traps are enabled). */
212 return 0;
215 # elif defined __m68k__
217 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
220 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
222 unsigned int desired_flags = (unsigned int) *saved_flags;
223 unsigned int fpsr, orig_fpsr;
224 _FPU_GETFPSR (orig_fpsr);
225 fpsr = orig_fpsr ^ ((orig_fpsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
226 if (fpsr != orig_fpsr)
227 _FPU_SETFPSR (fpsr);
228 /* Possibly some new exception flags have been set. But just storing them
229 does not cause a trap to be executed (when traps are enabled). */
230 return 0;
233 # elif defined __mips__
235 /* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
236 an 'unsigned short'.
237 On NetBSD and OpenBSD, it is equivalent to an 'unsigned int'.
238 A simple C cast does the necessary conversion. */
241 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
243 unsigned int desired_flags = (unsigned int) *saved_flags;
244 unsigned int fcsr, orig_fcsr;
245 _FPU_GETCW (orig_fcsr);
246 fcsr = orig_fcsr ^ ((orig_fcsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
247 if (fcsr != orig_fcsr)
248 _FPU_SETCW (fcsr);
249 return 0;
252 # elif defined __loongarch__
254 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
257 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
259 unsigned int desired_flags = (unsigned int) *saved_flags;
260 unsigned int fcsr, orig_fcsr;
261 _FPU_GETCW (orig_fcsr);
262 fcsr = orig_fcsr ^ ((orig_fcsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
263 if (fcsr != orig_fcsr)
264 _FPU_SETCW (fcsr);
265 /* Possibly some new exception flags have been set. But just storing them
266 does not cause a trap to be executed (when traps are enabled). */
267 return 0;
270 # elif defined __powerpc__
272 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
275 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
277 /* The hardware does not support setting an exception flag without triggering
278 a trap, except through the "Ignore Exceptions Mode", bits FE0 and FE1 of
279 the MSR register set to zero, that can be obtained through a system call:
280 - On Linux and NetBSD: prctl (PR_SET_FPEXC, PR_FP_EXC_DISABLED);
281 - On AIX: fp_trap (FP_TRAP_OFF);
282 But that is not what we need here, as it would have a persistent effect on
283 the thread. */
284 exceptions &= FE_ALL_EXCEPT;
286 unsigned int desired_flags = (unsigned int) *saved_flags;
287 desired_flags &= exceptions;
289 union { unsigned long long u; double f; } memenv, orig_memenv;
290 _FPU_GETCW_AS_DOUBLE (memenv.f);
291 orig_memenv = memenv;
293 /* Instead of clearing FE_INVALID (= bit 29), we need to clear the
294 individual bits. */
295 memenv.u &= ~ (exceptions & FE_INVALID
296 ? (exceptions & ~FE_INVALID) | 0x01F80700U
297 : exceptions);
298 /* Instead of setting FE_INVALID (= bit 29), we need to set one of the
299 individual bits: bit 10 or, if that does not work, bit 24. */
300 memenv.u |= (desired_flags & FE_INVALID
301 ? (desired_flags & ~FE_INVALID) | (1U << 10)
302 : desired_flags);
304 if (!(memenv.u == orig_memenv.u))
306 if (memenv.u & (exceptions >> 22))
308 /* Setting the exception flags may trigger a trap.
309 ISO C 23 § 7.6.4.5 does not allow it. */
310 return -1;
312 _FPU_SETCW_AS_DOUBLE (memenv.f);
313 if (desired_flags & FE_INVALID)
315 /* Did it work? */
316 _FPU_GETCW_AS_DOUBLE (memenv.f);
317 if ((memenv.u & FE_INVALID) == 0)
319 memenv.u |= (1U << 24);
320 _FPU_SETCW_AS_DOUBLE (memenv.f);
325 return 0;
328 # elif defined __riscv
330 /* On all OSes except FreeBSD, fexcept_t is binary-equivalent to
331 an 'unsigned int'.
332 On FreeBSD, it is equivalent to an 'unsigned long'.
333 A simple C cast does the necessary conversion. */
336 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
338 # if 1 /* both should be equivalent */
339 exceptions &= FE_ALL_EXCEPT;
341 unsigned int desired_flags = (unsigned int) *saved_flags;
342 desired_flags &= exceptions;
344 __asm__ __volatile__ ("csrc fflags, %0" : : "r" (exceptions));
345 __asm__ __volatile__ ("csrs fflags, %0" : : "r" (desired_flags));
346 # else
347 unsigned int desired_flags = (unsigned int) *saved_flags;
348 unsigned int fcsr, orig_fcsr;
349 __asm__ __volatile__ ("frflags %0" : "=r" (orig_fcsr)); /* same as "csrr %0, fflags" */
350 fcsr = orig_fcsr ^ ((orig_fcsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
351 if (fcsr != orig_fcsr)
352 __asm__ __volatile__ ("fsflags %0" : : "r" (fcsr)); /* same as "csrw fflags, %0" */
353 # endif
355 return 0;
358 # elif defined __s390__ || defined __s390x__
360 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
363 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
365 unsigned int desired_flags = (unsigned int) *saved_flags;
366 unsigned int fpc, orig_fpc;
367 _FPU_GETCW (orig_fpc);
368 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
369 fpc = orig_fpc ^ ((orig_fpc ^ (desired_flags << 16)) & ((FE_ALL_EXCEPT & exceptions) << 16));
370 if ((fpc & 0x00000300) == 0)
371 /* Clear the corresponding bits of the "data exception code". */
372 fpc &= ~((FE_ALL_EXCEPT & exceptions) << 8);
373 # else /* musl libc compatible FE_* values */
374 fpc = orig_fpc ^ ((orig_fpc ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
375 if ((fpc & 0x00000300) == 0)
376 /* Clear the corresponding bits of the "data exception code". */
377 fpc &= ~((FE_ALL_EXCEPT & exceptions) >> 8);
378 # endif
379 if (fpc != orig_fpc)
380 _FPU_SETCW (fpc);
381 /* Possibly some new exception flags have been set. But just storing them
382 does not cause a trap to be executed (when traps are enabled). */
383 return 0;
386 # elif defined __sh__
388 /* On glibc, fexcept_t is binary-equivalent to an 'unsigned short'.
389 On all other OSes, fexcept_t is binary-equivalent to an 'unsigned int'.
390 A simple C cast does the necessary conversion. */
393 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
395 unsigned int desired_flags = (unsigned int) *saved_flags;
396 unsigned int fpscr, orig_fpscr;
397 _FPU_GETCW (orig_fpscr);
398 fpscr = orig_fpscr ^ ((orig_fpscr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
399 if (fpscr != orig_fpscr)
400 _FPU_SETCW (fpscr);
401 /* Possibly some new exception flags have been set. But just storing them
402 does not cause a trap to be executed (when traps are enabled). */
403 return 0;
406 # elif defined __sparc
408 /* On all OSes except Solaris, fexcept_t is binary-equivalent to an 'unsigned long'.
409 On Solaris, fexcept_t is an 'int'.
410 A simple C cast does the necessary conversion. */
413 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
415 unsigned long desired_flags = (unsigned long) *saved_flags;
416 unsigned long fsr, orig_fsr;
417 _FPU_GETCW (orig_fsr);
418 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
419 fsr = orig_fsr ^ ((orig_fsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
420 # else /* Solaris compatible FE_* values */
421 fsr = orig_fsr ^ ((orig_fsr ^ (desired_flags << 5)) & ((FE_ALL_EXCEPT & exceptions) << 5));
422 # endif
423 if (fsr != orig_fsr)
424 _FPU_SETCW (fsr);
425 /* Possibly some new exception flags have been set. But just storing them
426 does not cause a trap to be executed (when traps are enabled). */
427 return 0;
430 # else
432 # if defined __GNUC__ || defined __clang__
433 # warning "Unknown CPU / architecture. Please report your platform and compiler to <bug-gnulib@gnu.org>."
434 # endif
435 # define NEED_FALLBACK 1
437 # endif
439 #else
441 /* The compiler does not support __asm__ statements or equivalent
442 intrinsics. */
444 # if (defined __sun || __GLIBC__ >= 2) && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)) && defined __SUNPRO_C
445 /* Solaris/i386, Solaris/x86_64, glibc/i386, glibc/x86_64, with SunPRO C. */
447 /* On these Solaris platforms, fpsetsticky cannot be used here, because it may
448 generate traps (since fpsetsticky calls _putsw, which modifies the control
449 word of the 387 unit). Instead, we need to modify only the flags in the SSE
450 unit. */
452 /* Accessors for the mxcsr register. Fortunately, the SunPRO C compiler
453 supports a poor form of 'asm'. */
455 static void
456 getssecw (unsigned int *mxcsr_p)
458 # if defined __x86_64__ || defined _M_X64
459 asm ("stmxcsr (%rdi)");
460 # else
461 /* The compiler generates a stack frame. Therefore the first argument is in
462 8(%ebp), not in 4(%esp). */
463 asm ("movl 8(%ebp),%eax");
464 asm ("stmxcsr (%eax)");
465 # endif
468 static void
469 setssecw (unsigned int const *mxcsr_p)
471 # if defined __x86_64__ || defined _M_X64
472 asm ("ldmxcsr (%rdi)");
473 # else
474 /* The compiler generates a stack frame. Therefore the first argument is in
475 8(%ebp), not in 4(%esp). */
476 asm ("movl 8(%ebp),%eax");
477 asm ("ldmxcsr (%eax)");
478 # endif
481 # if __GLIBC__ >= 2
482 /* Clears flags in the 387 unit. */
483 static void
484 mask387cw (unsigned short mask)
486 # if defined __x86_64__ || defined _M_X64
487 asm ("fnstenv -32(%rsp)");
488 asm ("andw %di,-28(%rsp)");
489 asm ("fldenv -32(%rsp)");
490 # else
491 /* The compiler generates a stack frame. Therefore the first argument is in
492 8(%ebp), not in 4(%esp). */
493 asm ("movl 8(%ebp),%eax");
494 asm ("fnstenv -32(%esp)");
495 asm ("andw %ax,-28(%esp)");
496 asm ("fldenv -32(%esp)");
497 # endif
499 # endif
502 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
504 exceptions &= FE_ALL_EXCEPT;
505 unsigned int desired_flags = (unsigned int) *saved_flags;
507 /* Modify the flags in the SSE unit. */
508 unsigned int mxcsr, orig_mxcsr;
509 getssecw (&orig_mxcsr);
510 mxcsr = orig_mxcsr ^ ((orig_mxcsr ^ desired_flags) & exceptions);
511 if (mxcsr != orig_mxcsr)
512 setssecw (&mxcsr);
514 # if __GLIBC__ >= 2
515 /* Modify the flags in the 387 unit, but only by clearing bits, not by
516 setting bits. */
517 mask387cw (~ (exceptions & ~desired_flags));
518 # endif
520 return 0;
523 # elif HAVE_FPSETSTICKY
524 /* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2. */
526 /* Get fpgetsticky, fpsetsticky. */
527 # include <ieeefp.h>
528 /* The type is called 'fp_except_t' on FreeBSD, but 'fp_except' on
529 all other systems. */
530 # if !defined __FreeBSD__
531 # define fp_except_t fp_except
532 # endif
535 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
537 unsigned long desired_flags = (unsigned long) *saved_flags;
538 fp_except_t flags, orig_flags;
539 orig_flags = fpgetsticky ();
540 flags = orig_flags ^ ((orig_fsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
541 if (flags != orig_flags)
542 fpsetsticky (flags);
543 /* Possibly some new exception flags have been set. But just storing them
544 does not cause a trap to be executed (when traps are enabled). */
545 return 0;
548 # elif defined _AIX && defined __powerpc__ /* AIX */
550 # include <float.h>
551 # include <fpxcp.h>
553 # include <fptrap.h>
555 /* Documentation:
556 <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-clr-flag-fp-set-flag-fp-read-flag-fp-swap-flag-subroutine> */
559 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
561 exceptions &= FE_ALL_EXCEPT;
563 unsigned int desired_flags = (unsigned int) *saved_flags;
564 int exceptions_to_clear = exceptions & ~desired_flags;
565 int exceptions_to_set = exceptions & desired_flags;
567 fpflag_t orig_flags = fp_read_flag ();
568 /* In addition to clearing FE_INVALID (= bit 29), we also need to clear the
569 individual bits. */
570 fpflag_t f_to_clear =
571 exceptions_to_fpflag (exceptions_to_clear)
572 | (exceptions_to_clear & FE_INVALID ? 0x01F80700U : 0);
573 /* Instead of setting FE_INVALID (= bit 29), we need to set one of the
574 individual bits: bit 10 or, if that does not work, bit 24. */
575 fpflag_t f_to_set =
576 (exceptions_to_set & FE_INVALID
577 ? exceptions_to_fpflag (exceptions_to_set & ~FE_INVALID) | (1U << 10)
578 : exceptions_to_fpflag (exceptions_to_set));
579 if (f_to_clear != 0)
580 fp_clr_flag (f_to_clear);
581 if (f_to_set != 0)
583 if ((fegetexcept_impl () & exceptions) != 0)
585 /* Setting the exception flags may trigger a trap.
586 ISO C 23 § 7.6.4.5 does not allow it. */
587 return -1;
589 fp_set_flag (f_to_set);
590 if (exceptions & FE_INVALID)
592 /* Did it work? */
593 if ((fp_read_flag () & FP_INVALID) == 0)
594 fp_set_flag (1U << 24);
598 return 0;
601 # else
603 # define NEED_FALLBACK 1
605 # endif
607 #endif
609 #if NEED_FALLBACK
611 /* A dummy fallback. */
614 fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
616 if (exceptions != 0)
617 return -1;
618 return 0;
621 #endif