1 /* Test of turning floating-point exceptions into traps (signals).
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program 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 General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2023. */
30 /* Operations that should raise various floating-point exceptions. */
32 /* For a list, see the glibc documentation
33 <https://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html> */
35 #define infinityf my_infinityf /* Avoid collision with Cygwin's <math.h> */
36 static float volatile infinityf
, qnanf
;
37 static double volatile infinityd
, qnand
;
38 static long double volatile infinityl
, qnanl
;
41 raise_invalid_addition (char type
)
48 _GL_UNUSED
float volatile c
;
49 a
= infinityf
; b
= - infinityf
;
56 _GL_UNUSED
double volatile c
;
57 a
= infinityd
; b
= - infinityd
;
63 long double volatile a
, b
;
64 _GL_UNUSED
long double volatile c
;
65 a
= infinityl
; b
= - infinityl
;
73 raise_invalid_multiplication (char type
)
80 _GL_UNUSED
float volatile c
;
81 a
= infinityf
; b
= 0.0f
;
88 _GL_UNUSED
double volatile c
;
89 a
= infinityd
; b
= 0.0;
95 long double volatile a
, b
;
96 _GL_UNUSED
long double volatile c
;
97 a
= infinityl
; b
= 0.0L;
105 raise_invalid_division (char type
)
112 _GL_UNUSED
float volatile c
;
113 a
= infinityf
; b
= - infinityf
;
119 double volatile a
, b
;
120 _GL_UNUSED
double volatile c
;
121 a
= infinityd
; b
= - infinityd
;
127 long double volatile a
, b
;
128 _GL_UNUSED
long double volatile c
;
129 a
= infinityl
; b
= - infinityl
;
137 raise_invalid_comparison (char type
)
144 _GL_UNUSED
int volatile c
;
145 a
= qnanf
; b
= qnanf
;
151 double volatile a
, b
;
152 _GL_UNUSED
int volatile c
;
153 a
= qnand
; b
= qnand
;
159 long double volatile a
, b
;
160 _GL_UNUSED
int volatile c
;
161 a
= qnanl
; b
= qnanl
;
169 raise_invalid_snan (char type
)
176 _GL_UNUSED
float volatile c
;
177 a
= SNaNf (); b
= 1.0f
;
183 double volatile a
, b
;
184 _GL_UNUSED
double volatile c
;
185 a
= SNaNd (); b
= 1.0;
191 long double volatile a
, b
;
192 _GL_UNUSED
long double volatile c
;
193 a
= SNaNl (); b
= 1.0L;
201 raise_divbyzero (char type
)
208 _GL_UNUSED
float volatile c
;
209 a
= 2.5f
; b
= - 0.0f
;
215 double volatile a
, b
;
216 _GL_UNUSED
double volatile c
;
223 long double volatile a
, b
;
224 _GL_UNUSED
long double volatile c
;
225 a
= 2.5L; b
= - 0.0L;
233 raise_overflow (char type
)
240 _GL_UNUSED
float volatile c
;
241 a
= 1e20f
; b
= 1e30f
;
247 double volatile a
, b
;
248 _GL_UNUSED
double volatile c
;
249 a
= 1e160
; b
= 1e260
;
255 long double volatile a
, b
;
256 _GL_UNUSED
long double volatile c
;
257 a
= 1e200L
; b
= 1e300L
;
269 raise_underflow (char type
)
276 _GL_UNUSED
float volatile c
;
277 a
= 1e-20f
; b
= 1e-30f
;
283 double volatile a
, b
;
284 _GL_UNUSED
double volatile c
;
285 a
= 1e-160; b
= 1e-260;
291 long double volatile a
, b
;
292 _GL_UNUSED
long double volatile c
;
293 a
= 1e-200L; b
= 1e-300L;
305 raise_inexact (char type
)
312 _GL_UNUSED
float volatile c
;
319 double volatile a
, b
;
320 _GL_UNUSED
double volatile c
;
327 long double volatile a
, b
;
328 _GL_UNUSED
long double volatile c
;
337 main (int argc
, char *argv
[])
341 const char *operation_arg
= argv
[1];
342 const char *procedure_arg
= argv
[2];
343 const char *type_arg
= argv
[3];
345 void (*operation
) (char) = NULL
;
346 int expected_exceptions
= 0;
347 int possible_exceptions
= 0;
349 /* Preparations (to be executed before we call feenableexcept). */
350 infinityf
= Infinityf ();
352 infinityd
= Infinityd ();
354 infinityl
= Infinityl ();
356 feclearexcept (FE_ALL_EXCEPT
);
358 /* Analyze the operation argument. */
359 switch (operation_arg
[0])
362 operation
= raise_invalid_addition
;
363 expected_exceptions
= FE_INVALID
;
366 operation
= raise_invalid_multiplication
;
367 expected_exceptions
= FE_INVALID
;
370 operation
= raise_invalid_division
;
371 expected_exceptions
= FE_INVALID
;
374 operation
= raise_invalid_comparison
;
375 expected_exceptions
= FE_INVALID
;
378 operation
= raise_invalid_snan
;
379 expected_exceptions
= FE_INVALID
;
382 operation
= raise_divbyzero
;
383 expected_exceptions
= FE_DIVBYZERO
;
386 operation
= raise_overflow
;
387 expected_exceptions
= FE_OVERFLOW
;
388 possible_exceptions
= FE_INEXACT
;
391 operation
= raise_underflow
;
392 expected_exceptions
= FE_UNDERFLOW
;
393 possible_exceptions
= FE_INEXACT
;
396 operation
= raise_inexact
;
397 expected_exceptions
= FE_INEXACT
;
401 /* Analyze the procedure argument. */
402 switch (procedure_arg
[0])
404 /* These three procedures should lead to a trap. */
406 if (feenableexcept (expected_exceptions
) == -1)
410 if (feenableexcept (FE_ALL_EXCEPT
) == -1)
414 if (feenableexcept (FE_ALL_EXCEPT
) == -1)
416 ASSERT (fedisableexcept (FE_ALL_EXCEPT
& ~expected_exceptions
)
419 /* This procedure should *not* lead to a trap. */
421 if (feenableexcept (FE_ALL_EXCEPT
& ~(expected_exceptions
| possible_exceptions
)) == -1)
426 /* Avoid known test failures. */
427 int known_failure
= 0;
428 /* The '4' tests do not work
429 - on glibc/{i386,x86_64}, with gcc < 8 (except when option -mno-ieee-fp
430 is used) or with clang,
431 - on glibc/powerpc* and glibc/s390*,
433 GNU/kFreeBSD/i386, GNU/kFreeBSD/x86_64,
434 musl libc/i386, musl libc/powerpc64le,
435 macOS/i386, macOS/x86_64, macOS/arm64,
436 FreeBSD/i386, FreeBSD/x86_64, FreeBSD/powerpc64,
437 NetBSD/i386, NetBSD/x86_64, NetBSD/powerpc,
438 OpenBSD/i386, OpenBSD/x86_64, OpenBSD/mips64,
441 Solaris/i386, Solaris/x86_64,
443 native Windows/i386, native Windows/x86_64,
445 Explanation of some of the {i386,x86_64} cases:
446 - Quoting the Intel 64 and IA-32 Architectures Software Developer's
448 "The UCOMISD instruction differs from the COMISD instruction in that
449 it signals a SIMD floating-point invalid operation exception (#I)
450 only when a source operand is an SNaN. The COMISD instruction
451 signals an invalid numeric exception only if a source operand is
452 either an SNaN or a QNaN."
453 - gcc < 8 (except when option -mno-ieee-fp is used) generates 'ucom*'
454 or 'fucom*' instructions and thus fails the test.
455 - gcc >= 8 generates 'com*' or 'fcom*' instructions and thus passes
457 #if (__GLIBC__ >= 2 && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)) && __GNUC__ < 8) \
458 || (__GLIBC__ >= 2 && (defined __powerpc__ || (defined __s390__ || defined __s390x__))) \
459 || (__GLIBC__ >= 2 && __FreeBSD_kernel__ && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86))) \
460 || (defined MUSL_LIBC && ((defined __i386 || defined _M_IX86) || defined __powerpc__)) \
461 || ((defined __APPLE__ && defined __MACH__) && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86) || defined __aarch64__)) \
462 || ((defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__) && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86))) \
463 || ((defined __FreeBSD__ || defined __NetBSD__) && defined __powerpc__) \
464 || (defined __OpenBSD__ && defined __mips64) \
465 || (defined __minix && (defined __i386 || defined _M_IX86)) \
466 || (defined _AIX && defined __powerpc__) \
467 || (defined __sun && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86))) \
468 || (defined __CYGWIN__ && (defined __x86_64__ || defined _M_X64)) \
469 || (defined _WIN32 && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86))) \
470 || (defined __HAIKU__ && (defined __i386 || defined _M_IX86))
471 known_failure
|= (operation_arg
[0] == '4');
473 /* The '7' and '8' tests, with types 'f' and 'd', do not work reliably
475 #if defined __i386 || defined _M_IX86
476 known_failure
|= (operation_arg
[0] == '7' || operation_arg
[0] == '8');
478 /* The '9' tests do not work on Linux/alpha. */
479 #if (__GLIBC__ >= 2 && defined __alpha)
480 known_failure
|= (operation_arg
[0] == '9');
482 /* The 'l' tests do not work on Linux/loongarch64 with glibc 2.37.
483 Likewise on Linux/alpha with glibc 2.7 on Linux 2.6.26.
484 Likewise on FreeBSD 12.2/sparc, NetBSD 8.0/sparc, OpenBSD 7.2/sparc64.
485 Likewise on OpenBSD 7.4/mips64.
487 #if (__GLIBC__ >= 2 && defined __loongarch__) \
488 || ((__GLIBC__ == 2 && __GLIBC_MINOR__ < 36) && defined __alpha) \
489 || ((defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__) && defined __sparc) \
490 || (defined __OpenBSD__ && defined __mips64)
491 known_failure
|= (type_arg
[0] == 'l');
495 if (test_exit_status
!= EXIT_SUCCESS
)
496 return test_exit_status
;
497 fputs ("Skipping test: known failure on this platform\n", stderr
);
501 /* Analyze the type argument. */
507 operation (type_arg
[0]);
512 return test_exit_status
;
515 if (test_exit_status
!= EXIT_SUCCESS
)
516 return test_exit_status
;
517 fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr
);