1 /* Functions for tracking which floating-point exceptions have occurred.
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>/{fclrexcpt.c,fraiseexcpt.c,ftestexcept.c}
18 together with glibc/sysdeps/<cpu>/{fpu_control.h,fenv_private.h,fenv_libc.h}. */
25 #include "fenv-private.h"
27 #if defined _AIX && defined __powerpc__ /* AIX */
29 /* On AIX, the register fpscr is augmented with a 32-bit word named fpscrx
30 in thread-local storage. Instead of accessing fpscr, we must access the
31 combination. The function fp_read_flag() does this. */
37 <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-clr-flag-fp-set-flag-fp-read-flag-fp-swap-flag-subroutine> */
40 fetestexcept (int exceptions
)
42 fpflag_t flags
= fp_read_flag ();
43 return fpflag_to_exceptions (flags
) & FE_ALL_EXCEPT
& exceptions
;
46 #elif defined __GNUC__ || defined __clang__ || defined _MSC_VER
48 # if (defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)
51 fetestexcept (int exceptions
)
55 /* Look at the flags in the SSE unit. */
57 _FPU_GETSSECW (mxcsr
);
58 return x86hardware_to_exceptions (mxcsr
) & FE_ALL_EXCEPT
& exceptions
;
65 unsigned int mxcsr
= 0;
68 /* Look at the flags in the SSE unit as well. */
69 _FPU_GETSSECW (mxcsr
);
72 return x86hardware_to_exceptions (fstat
| mxcsr
) & FE_ALL_EXCEPT
& exceptions
;
76 # elif defined __aarch64__ /* arm64 */
79 fetestexcept (int exceptions
)
83 return fpsr
& FE_ALL_EXCEPT
& exceptions
;
86 # elif defined __arm__
89 fetestexcept (int exceptions
)
96 return fpscr
& FE_ALL_EXCEPT
& exceptions
;
100 # elif defined __alpha
103 fetestexcept (int exceptions
)
105 unsigned long swcr
= __ieee_get_fp_control ();
106 return swcr
& FE_ALL_EXCEPT
& exceptions
;
109 # elif defined __hppa
112 fetestexcept (int exceptions
)
114 union { unsigned long long fpreg
; unsigned int halfreg
[2]; } s
;
115 /* Get the current status word. */
116 __asm__
__volatile__ ("fstd %%fr0,0(%1)" : "=m" (s
.fpreg
) : "r" (&s
.fpreg
) : "%r0");
117 return (s
.halfreg
[0] >> 27) & FE_ALL_EXCEPT
& exceptions
;
120 # elif defined __ia64__
123 fetestexcept (int exceptions
)
127 return (fpsr
>> 13) & FE_ALL_EXCEPT
& exceptions
;
130 # elif defined __m68k__
133 fetestexcept (int exceptions
)
137 return fpsr
& FE_ALL_EXCEPT
& exceptions
;
140 # elif defined __mips__
143 fetestexcept (int exceptions
)
147 return fcsr
& FE_ALL_EXCEPT
& exceptions
;
150 # elif defined __loongarch__
153 fetestexcept (int exceptions
)
157 return fcsr
& FE_ALL_EXCEPT
& exceptions
;
160 # elif defined __powerpc__
163 fetestexcept (int exceptions
)
165 union { unsigned long long u
; double f
; } memenv
;
166 _FPU_GETCW_AS_DOUBLE (memenv
.f
);
167 return memenv
.u
& FE_ALL_EXCEPT
& exceptions
;
170 # elif defined __riscv
173 fetestexcept (int exceptions
)
176 __asm__
__volatile__ ("frflags %0" : "=r" (flags
)); /* same as "csrr %0, fflags" */
177 return flags
& FE_ALL_EXCEPT
& exceptions
;
180 # elif defined __s390__ || defined __s390x__
183 fetestexcept (int exceptions
)
187 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
188 return ((fpc
>> 16) | ((fpc
& 0x00000300) == 0 ? fpc
>> 8 : 0))
189 & FE_ALL_EXCEPT
& exceptions
;
190 # else /* musl libc compatible FE_* values */
191 return (fpc
| ((fpc
& 0x00000300) == 0 ? fpc
<< 8 : 0))
192 & FE_ALL_EXCEPT
& exceptions
;
196 # elif defined __sh__
199 fetestexcept (int exceptions
)
203 return fpscr
& FE_ALL_EXCEPT
& exceptions
;
206 # elif defined __sparc
209 fetestexcept (int exceptions
)
213 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
214 return fsr
& FE_ALL_EXCEPT
& exceptions
;
215 # else /* Solaris compatible FE_* values */
216 return (fsr
>> 5) & FE_ALL_EXCEPT
& exceptions
;
222 # if defined __GNUC__ || defined __clang__
223 # warning "Unknown CPU / architecture. Please report your platform and compiler to <bug-gnulib@gnu.org>."
225 # define NEED_FALLBACK 1
231 /* The compiler does not support __asm__ statements or equivalent
234 # if HAVE_FPSETSTICKY
235 /* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2. */
237 /* Get fpgetsticky, fpsetsticky. */
239 /* The type is called 'fp_except_t' on FreeBSD, but 'fp_except' on
240 all other systems. */
241 # if !defined __FreeBSD__
242 # define fp_except_t fp_except
246 fetestexcept (int exceptions
)
248 fp_except_t flags
= fpgetsticky ();
249 return flags
& FE_ALL_EXCEPT
& exceptions
;
254 # define NEED_FALLBACK 1
262 /* A dummy fallback. */
265 fetestexcept (int exceptions
)