exp2l: Work around a NetBSD 10.0/i386 bug.
[gnulib.git] / lib / fenv-except-tracking-test.c
blob73cdd2c08a22251e5243bc95ebd5f887503cbd41
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}. */
20 #include <config.h>
22 /* Specification. */
23 #include <fenv.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. */
33 # include <float.h>
34 # include <fpxcp.h>
36 /* Documentation:
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> */
39 int
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)
50 int
51 fetestexcept (int exceptions)
53 # if defined _MSC_VER
55 /* Look at the flags in the SSE unit. */
56 unsigned int mxcsr;
57 _FPU_GETSSECW (mxcsr);
58 return x86hardware_to_exceptions (mxcsr) & FE_ALL_EXCEPT & exceptions;
60 # else
62 unsigned short fstat;
63 _FPU_GETSTAT (fstat);
65 unsigned int mxcsr = 0;
66 if (CPU_HAS_SSE ())
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;
73 # endif
76 # elif defined __aarch64__ /* arm64 */
78 int
79 fetestexcept (int exceptions)
81 unsigned long fpsr;
82 _FPU_GETFPSR (fpsr);
83 return fpsr & FE_ALL_EXCEPT & exceptions;
86 # elif defined __arm__
88 int
89 fetestexcept (int exceptions)
91 # ifdef __SOFTFP__
92 return 0;
93 # else
94 unsigned int fpscr;
95 _FPU_GETCW (fpscr);
96 return fpscr & FE_ALL_EXCEPT & exceptions;
97 # endif
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)
125 unsigned long fpsr;
126 _FPU_GETCW (fpsr);
127 return (fpsr >> 13) & FE_ALL_EXCEPT & exceptions;
130 # elif defined __m68k__
133 fetestexcept (int exceptions)
135 unsigned int fpsr;
136 _FPU_GETFPSR (fpsr);
137 return fpsr & FE_ALL_EXCEPT & exceptions;
140 # elif defined __mips__
143 fetestexcept (int exceptions)
145 unsigned int fcsr;
146 _FPU_GETCW (fcsr);
147 return fcsr & FE_ALL_EXCEPT & exceptions;
150 # elif defined __loongarch__
153 fetestexcept (int exceptions)
155 unsigned int fcsr;
156 _FPU_GETCW (fcsr);
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)
175 unsigned int flags;
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)
185 unsigned int fpc;
186 _FPU_GETCW (fpc);
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;
193 # endif
196 # elif defined __sh__
199 fetestexcept (int exceptions)
201 unsigned int fpscr;
202 _FPU_GETCW (fpscr);
203 return fpscr & FE_ALL_EXCEPT & exceptions;
206 # elif defined __sparc
209 fetestexcept (int exceptions)
211 unsigned long fsr;
212 _FPU_GETCW (fsr);
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;
217 # endif
220 # else
222 # if defined __GNUC__ || defined __clang__
223 # warning "Unknown CPU / architecture. Please report your platform and compiler to <bug-gnulib@gnu.org>."
224 # endif
225 # define NEED_FALLBACK 1
227 # endif
229 #else
231 /* The compiler does not support __asm__ statements or equivalent
232 intrinsics. */
234 # if HAVE_FPSETSTICKY
235 /* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2. */
237 /* Get fpgetsticky, fpsetsticky. */
238 # include <ieeefp.h>
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
243 # endif
246 fetestexcept (int exceptions)
248 fp_except_t flags = fpgetsticky ();
249 return flags & FE_ALL_EXCEPT & exceptions;
252 # else
254 # define NEED_FALLBACK 1
256 # endif
258 #endif
260 #if NEED_FALLBACK
262 /* A dummy fallback. */
265 fetestexcept (int exceptions)
267 return 0;
270 #endif