exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / fenv-except-trapping.c
blob982713fea8cae8d13912db9b229613637783658c
1 /* Functions for turning floating-point exceptions into traps (signals).
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>/{feenablxcpt.c,fedisblxcpt.c,fegetexcept.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 int
32 feenableexcept (int exceptions)
34 exceptions &= FE_ALL_EXCEPT;
36 # if defined _MSC_VER
38 exceptions = exceptions_to_x86hardware (exceptions);
40 /* Enable the traps only in the SSE unit. */
41 unsigned int mxcsr, orig_mxcsr;
42 _FPU_GETSSECW (orig_mxcsr);
43 mxcsr = orig_mxcsr & ~(exceptions << 7);
44 if (mxcsr != orig_mxcsr)
45 _FPU_SETSSECW (mxcsr);
47 unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7);
48 return x86hardware_to_exceptions (trapbits);
50 # else
52 /* Enable the traps in the 387 unit. */
53 unsigned short fctrl, orig_fctrl;
54 _FPU_GETCW (orig_fctrl);
55 fctrl = orig_fctrl & ~exceptions;
56 if (fctrl != orig_fctrl)
57 _FPU_SETCW (fctrl);
59 if (CPU_HAS_SSE ())
61 /* Enable the traps in the SSE unit as well. */
62 unsigned int mxcsr, orig_mxcsr;
63 _FPU_GETSSECW (orig_mxcsr);
64 mxcsr = orig_mxcsr & ~(exceptions << 7);
65 if (mxcsr != orig_mxcsr)
66 _FPU_SETSSECW (mxcsr);
69 return FE_ALL_EXCEPT & ~orig_fctrl;
71 # endif
74 int
75 fedisableexcept (int exceptions)
77 exceptions &= FE_ALL_EXCEPT;
79 # if defined _MSC_VER
81 exceptions = exceptions_to_x86hardware (exceptions);
83 /* Disable the traps only in the SSE unit. */
84 unsigned int mxcsr, orig_mxcsr;
85 _FPU_GETSSECW (orig_mxcsr);
86 mxcsr = orig_mxcsr | (exceptions << 7);
87 if (mxcsr != orig_mxcsr)
88 _FPU_SETSSECW (mxcsr);
90 unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7);
91 return x86hardware_to_exceptions (trapbits);
93 # else
95 /* Disable the traps in the 387 unit. */
96 unsigned short fctrl, orig_fctrl;
97 _FPU_GETCW (orig_fctrl);
98 fctrl = orig_fctrl | exceptions;
99 if (fctrl != orig_fctrl)
100 _FPU_SETCW (fctrl);
102 if (CPU_HAS_SSE ())
104 /* Disable the traps in the SSE unit as well. */
105 unsigned int mxcsr, orig_mxcsr;
106 _FPU_GETSSECW (orig_mxcsr);
107 mxcsr = orig_mxcsr | (exceptions << 7);
108 if (mxcsr != orig_mxcsr)
109 _FPU_SETSSECW (mxcsr);
112 return FE_ALL_EXCEPT & ~orig_fctrl;
114 # endif
118 fegetexcept (void)
120 # if defined _MSC_VER
121 /* Look at the trap bits in the SSE unit. */
122 unsigned int mxcsr;
123 _FPU_GETSSECW (mxcsr);
124 unsigned int trapbits = 0x3f & ~(mxcsr >> 7);
125 return x86hardware_to_exceptions (trapbits);
126 # else
127 /* Look at the trap bits in the 387 unit. */
128 unsigned short fctrl;
129 _FPU_GETCW (fctrl);
130 return FE_ALL_EXCEPT & ~fctrl;
131 # endif
134 # elif defined __aarch64__ /* arm64 */
137 feenableexcept (int exceptions)
139 exceptions &= FE_ALL_EXCEPT;
141 unsigned long fpcr, orig_fpcr;
142 _FPU_GETCW (orig_fpcr);
143 fpcr = orig_fpcr | (exceptions << 8);
144 if (fpcr != orig_fpcr)
146 _FPU_SETCW (fpcr);
147 /* Test whether fpcr was actually changed as desired. */
148 unsigned long new_fpcr;
149 _FPU_GETCW (new_fpcr);
150 if (new_fpcr != fpcr)
151 return -1;
154 return FE_ALL_EXCEPT & (orig_fpcr >> 8);
158 fedisableexcept (int exceptions)
160 exceptions &= FE_ALL_EXCEPT;
162 unsigned long fpcr, orig_fpcr;
163 _FPU_GETCW (orig_fpcr);
164 fpcr = orig_fpcr & ~(exceptions << 8);
165 if (fpcr != orig_fpcr)
167 _FPU_SETCW (fpcr);
168 /* Testing whether fpcr was actually changed as desired is not needed
169 here, since we only cleared some bits. */
172 return FE_ALL_EXCEPT & (orig_fpcr >> 8);
176 fegetexcept (void)
178 unsigned long fpcr;
179 _FPU_GETCW (fpcr);
180 return FE_ALL_EXCEPT & (fpcr >> 8);
183 # elif defined __arm__
186 feenableexcept (int exceptions)
188 exceptions &= FE_ALL_EXCEPT;
190 # ifdef __SOFTFP__
191 if (exceptions != 0)
192 return -1;
193 return 0;
194 # else
195 unsigned int fpscr, orig_fpscr;
196 _FPU_GETCW (orig_fpscr);
197 fpscr = orig_fpscr | (exceptions << 8);
198 if (fpscr != orig_fpscr)
200 _FPU_SETCW (fpscr);
201 /* Test whether fpscr was actually changed as desired. */
202 unsigned int new_fpscr;
203 _FPU_GETCW (new_fpscr);
204 if (new_fpscr != fpscr)
205 return -1;
208 return FE_ALL_EXCEPT & (orig_fpscr >> 8);
209 # endif
213 fedisableexcept (int exceptions)
215 exceptions &= FE_ALL_EXCEPT;
217 # ifdef __SOFTFP__
218 return 0;
219 # else
220 unsigned int fpscr, orig_fpscr;
221 _FPU_GETCW (orig_fpscr);
222 fpscr = orig_fpscr & ~(exceptions << 8);
223 if (fpscr != orig_fpscr)
225 _FPU_SETCW (fpscr);
226 /* Testing whether fpscr was actually changed as desired is not needed
227 here, since we only cleared some bits. */
230 return FE_ALL_EXCEPT & (orig_fpscr >> 8);
231 # endif
235 fegetexcept (void)
237 # ifdef __SOFTFP__
238 return 0;
239 # else
240 unsigned int fpscr;
241 _FPU_GETCW (fpscr);
242 return FE_ALL_EXCEPT & (fpscr >> 8);
243 # endif
246 # elif defined __alpha
249 feenableexcept (int exceptions)
251 exceptions &= FE_ALL_EXCEPT;
253 unsigned long swcr, orig_swcr;
254 orig_swcr = __ieee_get_fp_control ();
255 swcr = orig_swcr | ((unsigned long) exceptions >> 16);
256 if (swcr != orig_swcr)
257 __ieee_set_fp_control (swcr);
259 return FE_ALL_EXCEPT & (orig_swcr << 16);
263 fedisableexcept (int exceptions)
265 exceptions &= FE_ALL_EXCEPT;
267 unsigned long swcr, orig_swcr;
268 orig_swcr = __ieee_get_fp_control ();
269 swcr = orig_swcr & ~((unsigned long) exceptions >> 16);
270 if (swcr != orig_swcr)
271 __ieee_set_fp_control (swcr);
273 return FE_ALL_EXCEPT & (orig_swcr << 16);
277 fegetexcept (void)
279 unsigned long swcr = __ieee_get_fp_control ();
280 return FE_ALL_EXCEPT & (swcr << 16);
283 # elif defined __hppa
286 feenableexcept (int exceptions)
288 exceptions &= FE_ALL_EXCEPT;
290 union { unsigned long long fpreg; unsigned int halfreg[2]; } s;
291 /* Get the current status word. */
292 __asm__ __volatile__ ("fstd %%fr0,0(%1)" : "=m" (s.fpreg) : "r" (&s.fpreg) : "%r0");
293 unsigned int old_halfreg0 = s.halfreg[0];
294 /* Set all the relevant bits. */
295 s.halfreg[0] |= (unsigned int) exceptions;
296 if (s.halfreg[0] != old_halfreg0)
298 /* Store the new status word. */
299 __asm__ __volatile__ ("fldd 0(%0),%%fr0" : : "r" (&s.fpreg), "m" (s.fpreg) : "%r0");
302 return FE_ALL_EXCEPT & old_halfreg0;
306 fedisableexcept (int exceptions)
308 exceptions &= FE_ALL_EXCEPT;
310 union { unsigned long long fpreg; unsigned int halfreg[2]; } s;
311 /* Get the current status word. */
312 __asm__ __volatile__ ("fstd %%fr0,0(%1)" : "=m" (s.fpreg) : "r" (&s.fpreg) : "%r0");
313 unsigned int old_halfreg0 = s.halfreg[0];
314 /* Clear all the relevant bits. */
315 s.halfreg[0] &= ~ (unsigned int) exceptions;
316 if (s.halfreg[0] != old_halfreg0)
318 /* Store the new status word. */
319 __asm__ __volatile__ ("fldd 0(%0),%%fr0" : : "r" (&s.fpreg), "m" (s.fpreg) : "%r0");
322 return FE_ALL_EXCEPT & old_halfreg0;
326 fegetexcept (void)
328 union { unsigned long long fpreg; unsigned int halfreg[2]; } s;
329 /* Get the current status word. */
330 __asm__ __volatile__ ("fstd %%fr0,0(%1)" : "=m" (s.fpreg) : "r" (&s.fpreg) : "%r0");
332 return FE_ALL_EXCEPT & s.halfreg[0];
335 # elif defined __ia64__
338 feenableexcept (int exceptions)
340 exceptions &= FE_ALL_EXCEPT;
342 unsigned long fpsr, orig_fpsr;
343 _FPU_GETCW (orig_fpsr);
344 fpsr = orig_fpsr & ~ (unsigned long) exceptions;
345 if (fpsr != orig_fpsr)
346 _FPU_SETCW (fpsr);
348 return FE_ALL_EXCEPT & ~orig_fpsr;
352 fedisableexcept (int exceptions)
354 exceptions &= FE_ALL_EXCEPT;
356 unsigned long fpsr, orig_fpsr;
357 _FPU_GETCW (orig_fpsr);
358 fpsr = orig_fpsr | (unsigned long) exceptions;
359 if (fpsr != orig_fpsr)
360 _FPU_SETCW (fpsr);
362 return FE_ALL_EXCEPT & ~orig_fpsr;
366 fegetexcept (void)
368 unsigned long fpsr;
369 _FPU_GETCW (fpsr);
370 return FE_ALL_EXCEPT & ~fpsr;
373 # elif defined __m68k__
376 feenableexcept (int exceptions)
378 exceptions &= FE_ALL_EXCEPT;
380 unsigned int fpcr, orig_fpcr;
381 _FPU_GETCW (orig_fpcr);
382 fpcr = orig_fpcr | ((exceptions << 6) | (exceptions & FE_INVALID ? 0xc000 : 0));
383 if (fpcr != orig_fpcr)
384 _FPU_SETCW (fpcr);
386 return FE_ALL_EXCEPT & (orig_fpcr >> 6);
390 fedisableexcept (int exceptions)
392 exceptions &= FE_ALL_EXCEPT;
394 unsigned int fpcr, orig_fpcr;
395 _FPU_GETCW (orig_fpcr);
396 fpcr = orig_fpcr & ~ ((exceptions << 6) | (exceptions & FE_INVALID ? 0xc000 : 0));
397 if (fpcr != orig_fpcr)
398 _FPU_SETCW (fpcr);
400 return FE_ALL_EXCEPT & (orig_fpcr >> 6);
404 fegetexcept (void)
406 unsigned int fpcr;
407 _FPU_GETCW (fpcr);
408 return FE_ALL_EXCEPT & (fpcr >> 6);
411 # elif defined __mips__
414 feenableexcept (int exceptions)
416 exceptions &= FE_ALL_EXCEPT;
418 unsigned int fcsr, orig_fcsr;
419 _FPU_GETCW (orig_fcsr);
420 fcsr = orig_fcsr | (exceptions << 5);
421 if (fcsr != orig_fcsr)
422 _FPU_SETCW (fcsr);
424 return FE_ALL_EXCEPT & (orig_fcsr >> 5);
428 fedisableexcept (int exceptions)
430 exceptions &= FE_ALL_EXCEPT;
432 unsigned int fcsr, orig_fcsr;
433 _FPU_GETCW (orig_fcsr);
434 fcsr = orig_fcsr & ~ (exceptions << 5);
435 if (fcsr != orig_fcsr)
436 _FPU_SETCW (fcsr);
438 return FE_ALL_EXCEPT & (orig_fcsr >> 5);
442 fegetexcept (void)
444 unsigned int fcsr;
445 _FPU_GETCW (fcsr);
446 return FE_ALL_EXCEPT & (fcsr >> 5);
449 # elif defined __loongarch__
452 feenableexcept (int exceptions)
454 exceptions &= FE_ALL_EXCEPT;
456 unsigned int fcsr, orig_fcsr;
457 _FPU_GETCW (orig_fcsr);
458 fcsr = orig_fcsr | (exceptions >> 16);
459 if (fcsr != orig_fcsr)
460 _FPU_SETCW (fcsr);
462 return FE_ALL_EXCEPT & (orig_fcsr << 16);
466 fedisableexcept (int exceptions)
468 exceptions &= FE_ALL_EXCEPT;
470 unsigned int fcsr, orig_fcsr;
471 _FPU_GETCW (orig_fcsr);
472 fcsr = orig_fcsr & ~ (exceptions >> 16);
473 if (fcsr != orig_fcsr)
474 _FPU_SETCW (fcsr);
476 return FE_ALL_EXCEPT & (orig_fcsr << 16);
480 fegetexcept (void)
482 unsigned int fcsr;
483 _FPU_GETCW (fcsr);
484 return FE_ALL_EXCEPT & (fcsr << 16);
487 # elif defined __powerpc__
489 # if defined __linux__
490 # include <sys/prctl.h>
491 # elif defined _AIX
492 # include <fptrap.h>
493 # endif
496 feenableexcept (int exceptions)
498 exceptions &= FE_ALL_EXCEPT;
500 union { unsigned long long u; double f; } memenv, orig_memenv;
501 _FPU_GETCW_AS_DOUBLE (memenv.f);
502 orig_memenv = memenv;
504 memenv.u |= ((unsigned int) exceptions >> 22);
506 if (!(memenv.u == orig_memenv.u))
508 if ((orig_memenv.u & 0x000000f8) == 0 && (memenv.u & 0x000000f8) != 0)
510 /* Put the thread into precise trapping mode. */
511 # if defined __linux__ || defined __NetBSD__
512 prctl (PR_SET_FPEXC, PR_FP_EXC_PRECISE);
513 # elif defined _AIX
514 /* Documentation: <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-trap-subroutine> */
515 fp_trap (FP_TRAP_SYNC);
516 # endif
519 _FPU_SETCW_AS_DOUBLE (memenv.f);
522 return FE_ALL_EXCEPT & ((unsigned int) orig_memenv.u << 22);
526 fedisableexcept (int exceptions)
528 exceptions &= FE_ALL_EXCEPT;
530 union { unsigned long long u; double f; } memenv, orig_memenv;
531 _FPU_GETCW_AS_DOUBLE (memenv.f);
532 orig_memenv = memenv;
534 memenv.u &= ~ ((unsigned int) exceptions >> 22);
536 if (!(memenv.u == orig_memenv.u))
538 _FPU_SETCW_AS_DOUBLE (memenv.f);
540 if ((orig_memenv.u & 0x000000f8) != 0 && (memenv.u & 0x000000f8) == 0)
542 /* Put the thread into no-trapping mode. */
543 # if defined __linux__ || defined __NetBSD__
544 prctl (PR_SET_FPEXC, PR_FP_EXC_DISABLED);
545 # elif defined _AIX
546 /* Documentation: <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-trap-subroutine> */
547 fp_trap (FP_TRAP_OFF);
548 # endif
552 return FE_ALL_EXCEPT & ((unsigned int) orig_memenv.u << 22);
556 fegetexcept (void)
558 union { unsigned long long u; double f; } memenv;
559 _FPU_GETCW_AS_DOUBLE (memenv.f);
561 return FE_ALL_EXCEPT & ((unsigned int) memenv.u << 22);
564 # elif defined __riscv
567 feenableexcept (int exceptions)
569 exceptions &= FE_ALL_EXCEPT;
571 if (exceptions != 0)
572 return -1;
573 return 0;
577 fedisableexcept (int exceptions)
579 return 0;
583 fegetexcept (void)
585 return 0;
588 # elif defined __s390__ || defined __s390x__
591 feenableexcept (int exceptions)
593 exceptions &= FE_ALL_EXCEPT;
595 unsigned int fpc, orig_fpc;
596 _FPU_GETCW (orig_fpc);
597 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
598 fpc = orig_fpc | ((unsigned int) exceptions << 24);
599 # else /* musl libc compatible FE_* values */
600 fpc = orig_fpc | ((unsigned int) exceptions << 8);
601 # endif
602 if (fpc != orig_fpc)
603 _FPU_SETCW (fpc);
605 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
606 return FE_ALL_EXCEPT & (orig_fpc >> 24);
607 # else /* musl libc compatible FE_* values */
608 return FE_ALL_EXCEPT & (orig_fpc >> 8);
609 # endif
613 fedisableexcept (int exceptions)
615 exceptions &= FE_ALL_EXCEPT;
617 unsigned int fpc, orig_fpc;
618 _FPU_GETCW (orig_fpc);
619 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
620 fpc = orig_fpc & ~((unsigned int) exceptions << 24);
621 # else /* musl libc compatible FE_* values */
622 fpc = orig_fpc & ~((unsigned int) exceptions << 8);
623 # endif
624 if (fpc != orig_fpc)
625 _FPU_SETCW (fpc);
627 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
628 return FE_ALL_EXCEPT & (orig_fpc >> 24);
629 # else /* musl libc compatible FE_* values */
630 return FE_ALL_EXCEPT & (orig_fpc >> 8);
631 # endif
635 fegetexcept (void)
637 unsigned int fpc;
638 _FPU_GETCW (fpc);
639 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
640 return FE_ALL_EXCEPT & (fpc >> 24);
641 # else /* musl libc compatible FE_* values */
642 return FE_ALL_EXCEPT & (fpc >> 8);
643 # endif
646 # elif defined __sh__
649 feenableexcept (int exceptions)
651 exceptions &= FE_ALL_EXCEPT;
653 unsigned int fpscr, orig_fpscr;
654 _FPU_GETCW (orig_fpscr);
655 fpscr = orig_fpscr | ((unsigned int) exceptions << 5);
656 if (fpscr != orig_fpscr)
657 _FPU_SETCW (fpscr);
659 return FE_ALL_EXCEPT & (orig_fpscr >> 5);
663 fedisableexcept (int exceptions)
665 exceptions &= FE_ALL_EXCEPT;
667 unsigned int fpscr, orig_fpscr;
668 _FPU_GETCW (orig_fpscr);
669 fpscr = orig_fpscr & ~ ((unsigned int) exceptions << 5);
670 if (fpscr != orig_fpscr)
671 _FPU_SETCW (fpscr);
673 return FE_ALL_EXCEPT & (orig_fpscr >> 5);
677 fegetexcept (void)
679 unsigned int fpscr;
680 _FPU_GETCW (fpscr);
681 return FE_ALL_EXCEPT & (fpscr >> 5);
684 # elif defined __sparc
687 feenableexcept (int exceptions)
689 exceptions &= FE_ALL_EXCEPT;
691 unsigned long fsr, orig_fsr;
692 _FPU_GETCW (orig_fsr);
693 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
694 fsr = orig_fsr | (exceptions << 18);
695 # else /* Solaris compatible FE_* values */
696 fsr = orig_fsr | (exceptions << 23);
697 # endif
698 if (fsr != orig_fsr)
699 _FPU_SETCW (fsr);
701 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
702 return FE_ALL_EXCEPT & (orig_fsr >> 18);
703 # else /* Solaris compatible FE_* values */
704 return FE_ALL_EXCEPT & (orig_fsr >> 23);
705 # endif
709 fedisableexcept (int exceptions)
711 exceptions &= FE_ALL_EXCEPT;
713 unsigned long fsr, orig_fsr;
714 _FPU_GETCW (orig_fsr);
715 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
716 fsr = orig_fsr & ~(exceptions << 18);
717 # else /* Solaris compatible FE_* values */
718 fsr = orig_fsr & ~(exceptions << 23);
719 # endif
720 if (fsr != orig_fsr)
721 _FPU_SETCW (fsr);
723 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
724 return FE_ALL_EXCEPT & (orig_fsr >> 18);
725 # else /* Solaris compatible FE_* values */
726 return FE_ALL_EXCEPT & (orig_fsr >> 23);
727 # endif
731 fegetexcept (void)
733 unsigned long fsr;
734 _FPU_GETCW (fsr);
735 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
736 return FE_ALL_EXCEPT & (fsr >> 18);
737 # else /* Solaris compatible FE_* values */
738 return FE_ALL_EXCEPT & (fsr >> 23);
739 # endif
742 # else
744 # if defined __GNUC__ || defined __clang__
745 # warning "Unknown CPU / architecture. Please report your platform and compiler to <bug-gnulib@gnu.org>."
746 # endif
747 # define NEED_FALLBACK 1
749 # endif
751 #else
753 /* The compiler does not support __asm__ statements or equivalent
754 intrinsics. */
756 # if HAVE_FPSETMASK
757 /* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2. */
759 /* Get fpgetmask, fpsetmask. */
760 # include <ieeefp.h>
762 /* The type is called 'fp_except_t' on FreeBSD, but 'fp_except' on
763 all other systems. */
764 # if !defined __FreeBSD__
765 # define fp_except_t fp_except
766 # endif
768 static fp_except_t
769 exceptions_to_mask (int exceptions)
771 fp_except_t m = 0;
772 if (exceptions & FE_INVALID)
773 m |= FP_X_INV;
774 if (exceptions & FE_DIVBYZERO)
775 m |= FP_X_DZ;
776 if (exceptions & FE_OVERFLOW)
777 m |= FP_X_OFL;
778 if (exceptions & FE_UNDERFLOW)
779 m |= FP_X_UFL;
780 if (exceptions & FE_INEXACT)
781 m |= FP_X_IMP;
782 return m;
785 static int
786 mask_to_exceptions (fp_except_t m)
788 int exceptions = 0;
789 if (m & FP_X_INV)
790 exceptions |= FE_INVALID;
791 if (m & FP_X_DZ)
792 exceptions |= FE_DIVBYZERO;
793 if (m & FP_X_OFL)
794 exceptions |= FE_OVERFLOW;
795 if (m & FP_X_UFL)
796 exceptions |= FE_UNDERFLOW;
797 if (m & FP_X_IMP)
798 exceptions |= FE_INEXACT;
799 return exceptions;
803 feenableexcept (int exceptions)
805 exceptions &= FE_ALL_EXCEPT;
807 fp_except_t trapbits = fpgetmask ();
808 fpsetmask (trapbits | exceptions_to_mask (exceptions));
809 return mask_to_exceptions (trapbits);
813 fedisableexcept (int exceptions)
815 exceptions &= FE_ALL_EXCEPT;
817 fp_except_t trapbits = fpgetmask ();
818 fpsetmask (trapbits & ~ exceptions_to_mask (exceptions));
819 return mask_to_exceptions (trapbits);
823 fegetexcept (void)
825 fp_except_t trapbits = fpgetmask ();
826 return mask_to_exceptions (trapbits);
829 # elif defined _AIX && defined __powerpc__ /* AIX */
831 # include <fptrap.h>
832 /* Documentation:
833 <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-any-enable-fp-is-enabled-fp-enable-all-fp-enable-fp-disable-all-fp-disable-subroutine>
834 <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-trap-subroutine> */
836 /* Convert from an 'int exceptions' to an fptrap_t. */
837 # if 0 /* Unoptimized */
838 # define exceptions_to_fptrap(exceptions) \
839 ( ((exceptions) & FE_INVALID ? TRP_INVALID : 0) \
840 | ((exceptions) & FE_DIVBYZERO ? TRP_DIV_BY_ZERO : 0) \
841 | ((exceptions) & FE_OVERFLOW ? TRP_OVERFLOW : 0) \
842 | ((exceptions) & FE_UNDERFLOW ? TRP_UNDERFLOW : 0) \
843 | ((exceptions) & FE_INEXACT ? TRP_INEXACT : 0))
844 # else /* Optimized */
845 # define exceptions_to_fptrap(exceptions) \
846 (((unsigned int) (exceptions) & FE_ALL_EXCEPT) >> 22)
847 # endif
850 feenableexcept (int exceptions)
852 exceptions &= FE_ALL_EXCEPT;
854 int prev_enabled = fegetexcept ();
855 if (exceptions != 0)
857 fp_enable (exceptions_to_fptrap (exceptions));
858 if (prev_enabled == 0 /* && fegetexcept () != 0 */)
859 /* Enable precise trapping mode. */
860 fp_trap (FP_TRAP_SYNC);
862 return prev_enabled;
866 fedisableexcept (int exceptions)
868 exceptions &= FE_ALL_EXCEPT;
870 int prev_enabled = fegetexcept ();
871 if (exceptions != 0)
873 fp_disable (exceptions_to_fptrap (exceptions));
874 if (prev_enabled != 0 && fegetexcept () == 0)
875 /* Disable precise trapping mode. */
876 fp_trap (FP_TRAP_OFF);
878 return prev_enabled;
882 fegetexcept (void)
884 return fegetexcept_impl ();
887 # elif HAVE_FESETTRAPENABLE
888 /* HP-UX, QNX */
891 feenableexcept (int exceptions)
893 exceptions &= FE_ALL_EXCEPT;
895 int prev_enabled = fegettrapenable ();
896 if (exceptions != 0)
897 fesettrapenable (prev_enabled | exceptions);
898 return prev_enabled;
902 fedisableexcept (int exceptions)
904 exceptions &= FE_ALL_EXCEPT;
906 int prev_enabled = fegettrapenable ();
907 if (exceptions != 0)
908 fesettrapenable (prev_enabled & ~exceptions);
909 return prev_enabled;
913 fegetexcept (void)
915 return fegettrapenable ();
918 # else
920 # define NEED_FALLBACK 1
922 # endif
924 #endif
926 #if NEED_FALLBACK
928 /* A dummy fallback. */
931 feenableexcept (int exceptions)
933 exceptions &= FE_ALL_EXCEPT;
934 if (exceptions != 0)
935 return -1;
936 return 0;
940 fedisableexcept (int exceptions)
942 return 0;
946 fegetexcept (void)
948 return 0;
951 #endif