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}. */
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. */
37 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
39 /* Just like fetestexcept. */
43 _FPU_GETSSECW (mxcsr
);
44 *saved_flags
= x86hardware_to_exceptions (mxcsr
) & FE_ALL_EXCEPT
& exceptions
;
51 unsigned int mxcsr
= 0;
54 /* Look at the flags in the SSE unit as well. */
55 _FPU_GETSSECW (mxcsr
);
58 *saved_flags
= x86hardware_to_exceptions (fstat
| mxcsr
)
59 & FE_ALL_EXCEPT
& exceptions
;
65 # elif defined __aarch64__ /* arm64 */
67 /* On Linux, NetBSD, and Android, fexcept_t is binary-equivalent to
69 On macOS, fexcept_t is binary-equivalent to an 'unsigned short'.
70 On FreeBSD and OpenBSD, fexcept_t is binary-equivalent to an 'unsigned long'.
71 A simple C cast does the necessary conversion. */
74 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
76 /* Just like fetestexcept. */
79 *saved_flags
= fpsr
& FE_ALL_EXCEPT
& exceptions
;
83 # elif defined __arm__
85 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
88 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
90 /* Just like fetestexcept. */
96 *saved_flags
= fpscr
& FE_ALL_EXCEPT
& exceptions
;
101 # elif defined __alpha
103 /* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
105 On NetBSD, it is equivalent to an 'unsigned short'.
106 On OpenBSD, it is equivalent to an 'unsigned int'.
107 A simple C cast does the necessary conversion. */
110 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
112 /* Just like fetestexcept. */
113 unsigned long swcr
= __ieee_get_fp_control ();
114 *saved_flags
= swcr
& FE_ALL_EXCEPT
& exceptions
;
118 # elif defined __hppa
120 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
123 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
125 /* Just like fetestexcept. */
126 union { unsigned long long fpreg
; unsigned int halfreg
[2]; } s
;
127 /* Get the current status word. */
128 __asm__
__volatile__ ("fstd %%fr0,0(%1)" : "=m" (s
.fpreg
) : "r" (&s
.fpreg
) : "%r0");
129 *saved_flags
= (s
.halfreg
[0] >> 27) & FE_ALL_EXCEPT
& exceptions
;
133 # elif defined __ia64__
135 /* On all OSes except NetBSD, fexcept_t is binary-equivalent to
137 On NetBSD, it is equivalent to an 'unsigned short'.
138 A simple C cast does the necessary conversion. */
141 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
143 /* Just like fetestexcept. */
146 *saved_flags
= (fpsr
>> 13) & FE_ALL_EXCEPT
& exceptions
;
150 # elif defined __m68k__
152 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
155 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
157 /* Just like fetestexcept. */
160 *saved_flags
= fpsr
& FE_ALL_EXCEPT
& exceptions
;
164 # elif defined __mips__
166 /* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
168 On NetBSD and OpenBSD, it is equivalent to an 'unsigned int'.
169 A simple C cast does the necessary conversion. */
172 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
174 /* Just like fetestexcept. */
177 *saved_flags
= fcsr
& FE_ALL_EXCEPT
& exceptions
;
181 # elif defined __loongarch__
183 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
186 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
188 /* Just like fetestexcept. */
191 *saved_flags
= fcsr
& FE_ALL_EXCEPT
& exceptions
;
195 # elif defined __powerpc__
197 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
200 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
202 /* Just like fetestexcept. */
203 union { unsigned long long u
; double f
; } memenv
;
204 _FPU_GETCW_AS_DOUBLE (memenv
.f
);
205 *saved_flags
= memenv
.u
& FE_ALL_EXCEPT
& exceptions
;
209 # elif defined __riscv
211 /* On all OSes except FreeBSD, fexcept_t is binary-equivalent to
213 On FreeBSD, it is equivalent to an 'unsigned long'.
214 A simple C cast does the necessary conversion. */
217 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
219 /* Just like fetestexcept. */
221 __asm__
__volatile__ ("frflags %0" : "=r" (flags
)); /* same as "csrr %0, fflags" */
222 *saved_flags
= flags
& FE_ALL_EXCEPT
& exceptions
;
226 # elif defined __s390__ || defined __s390x__
228 /* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
231 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
233 /* Just like fetestexcept. */
236 # if FE_INEXACT == 8 /* glibc compatible FE_* values */
237 *saved_flags
= ((fpc
>> 16) | ((fpc
& 0x00000300) == 0 ? fpc
>> 8 : 0))
238 & FE_ALL_EXCEPT
& exceptions
;
239 # else /* musl libc compatible FE_* values */
240 *saved_flags
= (fpc
| ((fpc
& 0x00000300) == 0 ? fpc
<< 8 : 0))
241 & FE_ALL_EXCEPT
& exceptions
;
246 # elif defined __sh__
248 /* On glibc, fexcept_t is binary-equivalent to an 'unsigned short'.
249 On all other OSes, fexcept_t is binary-equivalent to an 'unsigned int'.
250 A simple C cast does the necessary conversion. */
253 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
255 /* Just like fetestexcept. */
258 *saved_flags
= fpscr
& FE_ALL_EXCEPT
& exceptions
;
262 # elif defined __sparc
264 /* On all OSes except Solaris, fexcept_t is binary-equivalent to an 'unsigned long'.
265 On Solaris, fexcept_t is an 'int'.
266 A simple C cast does the necessary conversion. */
269 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
271 /* Just like fetestexcept. */
274 # if FE_INEXACT == 32 /* glibc compatible FE_* values */
275 *saved_flags
= fsr
& FE_ALL_EXCEPT
& exceptions
;
276 # else /* Solaris compatible FE_* values */
277 *saved_flags
= (fsr
>> 5) & FE_ALL_EXCEPT
& exceptions
;
284 # if defined __GNUC__ || defined __clang__
285 # warning "Unknown CPU / architecture. Please report your platform and compiler to <bug-gnulib@gnu.org>."
287 # define NEED_FALLBACK 1
293 /* The compiler does not support __asm__ statements or equivalent
296 # if HAVE_FPSETSTICKY
297 /* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2. */
299 /* Get fpgetsticky, fpsetsticky. */
301 /* The type is called 'fp_except_t' on FreeBSD, but 'fp_except' on
302 all other systems. */
303 # if !defined __FreeBSD__
304 # define fp_except_t fp_except
308 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
310 /* Just like fetestexcept. */
311 fp_except_t flags
= fpgetsticky ();
312 *saved_flags
= flags
& FE_ALL_EXCEPT
& exceptions
;
316 # elif defined _AIX && defined __powerpc__ /* AIX */
322 <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-clr-flag-fp-set-flag-fp-read-flag-fp-swap-flag-subroutine> */
325 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
327 /* Just like fetestexcept. */
328 fpflag_t flags
= fp_read_flag ();
329 *saved_flags
= fpflag_to_exceptions (flags
) & FE_ALL_EXCEPT
& exceptions
;
335 # define NEED_FALLBACK 1
343 /* A dummy fallback. */
346 fegetexceptflag (fexcept_t
*saved_flags
, int exceptions
)
348 /* Just like fetestexcept. */