usleep tests: Avoid failure due to known Cygwin 3.5.3 bug.
[gnulib.git] / tests / test-fenv-except-trapping-2.c
blob166454080e5af48990e57eae91eb4e07c82a4005
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. */
19 #include <config.h>
21 /* Specification. */
22 #include <fenv.h>
24 #include <stdio.h>
26 #include "infinity.h"
27 #include "snan.h"
28 #include "macros.h"
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;
40 static void
41 raise_invalid_addition (char type)
43 switch (type)
45 case 'f':
47 float volatile a, b;
48 _GL_UNUSED float volatile c;
49 a = infinityf; b = - infinityf;
50 c = a + b;
52 break;
53 case 'd':
55 double volatile a, b;
56 _GL_UNUSED double volatile c;
57 a = infinityd; b = - infinityd;
58 c = a + b;
60 break;
61 case 'l':
63 long double volatile a, b;
64 _GL_UNUSED long double volatile c;
65 a = infinityl; b = - infinityl;
66 c = a + b;
68 break;
72 static void
73 raise_invalid_multiplication (char type)
75 switch (type)
77 case 'f':
79 float volatile a, b;
80 _GL_UNUSED float volatile c;
81 a = infinityf; b = 0.0f;
82 c = a * b;
84 break;
85 case 'd':
87 double volatile a, b;
88 _GL_UNUSED double volatile c;
89 a = infinityd; b = 0.0;
90 c = a * b;
92 break;
93 case 'l':
95 long double volatile a, b;
96 _GL_UNUSED long double volatile c;
97 a = infinityl; b = 0.0L;
98 c = a * b;
100 break;
104 static void
105 raise_invalid_division (char type)
107 switch (type)
109 case 'f':
111 float volatile a, b;
112 _GL_UNUSED float volatile c;
113 a = infinityf; b = - infinityf;
114 c = a / b;
116 break;
117 case 'd':
119 double volatile a, b;
120 _GL_UNUSED double volatile c;
121 a = infinityd; b = - infinityd;
122 c = a / b;
124 break;
125 case 'l':
127 long double volatile a, b;
128 _GL_UNUSED long double volatile c;
129 a = infinityl; b = - infinityl;
130 c = a / b;
132 break;
136 static void
137 raise_invalid_comparison (char type)
139 switch (type)
141 case 'f':
143 float volatile a, b;
144 _GL_UNUSED int volatile c;
145 a = qnanf; b = qnanf;
146 c = a > b;
148 break;
149 case 'd':
151 double volatile a, b;
152 _GL_UNUSED int volatile c;
153 a = qnand; b = qnand;
154 c = a > b;
156 break;
157 case 'l':
159 long double volatile a, b;
160 _GL_UNUSED int volatile c;
161 a = qnanl; b = qnanl;
162 c = a > b;
164 break;
168 static void
169 raise_invalid_snan (char type)
171 switch (type)
173 case 'f':
175 float volatile a, b;
176 _GL_UNUSED float volatile c;
177 a = SNaNf (); b = 1.0f;
178 c = a + b;
180 break;
181 case 'd':
183 double volatile a, b;
184 _GL_UNUSED double volatile c;
185 a = SNaNd (); b = 1.0;
186 c = a + b;
188 break;
189 case 'l':
191 long double volatile a, b;
192 _GL_UNUSED long double volatile c;
193 a = SNaNl (); b = 1.0L;
194 c = a + b;
196 break;
200 static void
201 raise_divbyzero (char type)
203 switch (type)
205 case 'f':
207 float volatile a, b;
208 _GL_UNUSED float volatile c;
209 a = 2.5f; b = - 0.0f;
210 c = a / b;
212 break;
213 case 'd':
215 double volatile a, b;
216 _GL_UNUSED double volatile c;
217 a = 2.5; b = - 0.0;
218 c = a / b;
220 break;
221 case 'l':
223 long double volatile a, b;
224 _GL_UNUSED long double volatile c;
225 a = 2.5L; b = - 0.0L;
226 c = a / b;
228 break;
232 static void
233 raise_overflow (char type)
235 switch (type)
237 case 'f':
239 float volatile a, b;
240 _GL_UNUSED float volatile c;
241 a = 1e20f; b = 1e30f;
242 c = a * b;
244 break;
245 case 'd':
247 double volatile a, b;
248 _GL_UNUSED double volatile c;
249 a = 1e160; b = 1e260;
250 c = a * b;
252 break;
253 case 'l':
255 long double volatile a, b;
256 _GL_UNUSED long double volatile c;
257 a = 1e200L; b = 1e300L;
258 c = a * b;
259 c = c * c;
260 c = c * c;
261 c = c * c;
262 c = c * c;
264 break;
268 static void
269 raise_underflow (char type)
271 switch (type)
273 case 'f':
275 float volatile a, b;
276 _GL_UNUSED float volatile c;
277 a = 1e-20f; b = 1e-30f;
278 c = a * b;
280 break;
281 case 'd':
283 double volatile a, b;
284 _GL_UNUSED double volatile c;
285 a = 1e-160; b = 1e-260;
286 c = a * b;
288 break;
289 case 'l':
291 long double volatile a, b;
292 _GL_UNUSED long double volatile c;
293 a = 1e-200L; b = 1e-300L;
294 c = a * b;
295 c = c * c;
296 c = c * c;
297 c = c * c;
298 c = c * c;
300 break;
304 static void
305 raise_inexact (char type)
307 switch (type)
309 case 'f':
311 float volatile a, b;
312 _GL_UNUSED float volatile c;
313 a = 2.5f; b = 3.0f;
314 c = a / b;
316 break;
317 case 'd':
319 double volatile a, b;
320 _GL_UNUSED double volatile c;
321 a = 2.5; b = 3.0;
322 c = a / b;
324 break;
325 case 'l':
327 long double volatile a, b;
328 _GL_UNUSED long double volatile c;
329 a = 2.5L; b = 3.0L;
330 c = a / b;
332 break;
337 main (int argc, char *argv[])
339 if (argc > 3)
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 ();
351 qnanf = NaNf ();
352 infinityd = Infinityd ();
353 qnand = NaNd ();
354 infinityl = Infinityl ();
355 qnanl = NaNl ();
356 feclearexcept (FE_ALL_EXCEPT);
358 /* Analyze the operation argument. */
359 switch (operation_arg[0])
361 case '1':
362 operation = raise_invalid_addition;
363 expected_exceptions = FE_INVALID;
364 break;
365 case '2':
366 operation = raise_invalid_multiplication;
367 expected_exceptions = FE_INVALID;
368 break;
369 case '3':
370 operation = raise_invalid_division;
371 expected_exceptions = FE_INVALID;
372 break;
373 case '4':
374 operation = raise_invalid_comparison;
375 expected_exceptions = FE_INVALID;
376 break;
377 case '5':
378 operation = raise_invalid_snan;
379 expected_exceptions = FE_INVALID;
380 break;
381 case '6':
382 operation = raise_divbyzero;
383 expected_exceptions = FE_DIVBYZERO;
384 break;
385 case '7':
386 operation = raise_overflow;
387 expected_exceptions = FE_OVERFLOW;
388 possible_exceptions = FE_INEXACT;
389 break;
390 case '8':
391 operation = raise_underflow;
392 expected_exceptions = FE_UNDERFLOW;
393 possible_exceptions = FE_INEXACT;
394 break;
395 case '9':
396 operation = raise_inexact;
397 expected_exceptions = FE_INEXACT;
398 break;
401 /* Analyze the procedure argument. */
402 switch (procedure_arg[0])
404 /* These three procedures should lead to a trap. */
405 case 'p':
406 if (feenableexcept (expected_exceptions) == -1)
407 goto skip;
408 break;
409 case 'q':
410 if (feenableexcept (FE_ALL_EXCEPT) == -1)
411 goto skip;
412 break;
413 case 'r':
414 if (feenableexcept (FE_ALL_EXCEPT) == -1)
415 goto skip;
416 ASSERT (fedisableexcept (FE_ALL_EXCEPT & ~expected_exceptions)
417 == FE_ALL_EXCEPT);
418 break;
419 /* This procedure should *not* lead to a trap. */
420 case 's':
421 if (feenableexcept (FE_ALL_EXCEPT & ~(expected_exceptions | possible_exceptions)) == -1)
422 goto skip;
423 break;
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*,
432 - as well as on
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,
439 Minix/i386,
440 AIX/powerpc,
441 Solaris/i386, Solaris/x86_64,
442 Cygwin/x86_64,
443 native Windows/i386, native Windows/x86_64,
444 Haiku/i386.
445 Explanation of some of the {i386,x86_64} cases:
446 - Quoting the Intel 64 and IA-32 Architectures Software Developer's
447 Manual:
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
456 the test. */
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');
472 #endif
473 /* The '7' and '8' tests, with types 'f' and 'd', do not work reliably
474 on Linux/i386. */
475 #if defined __i386 || defined _M_IX86
476 known_failure |= (operation_arg[0] == '7' || operation_arg[0] == '8');
477 #endif
478 /* The '9' tests do not work on Linux/alpha. */
479 #if (__GLIBC__ >= 2 && defined __alpha)
480 known_failure |= (operation_arg[0] == '9');
481 #endif
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.
486 Cause unknown. */
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');
492 #endif
493 if (known_failure)
495 if (test_exit_status != EXIT_SUCCESS)
496 return test_exit_status;
497 fputs ("Skipping test: known failure on this platform\n", stderr);
498 return 77;
501 /* Analyze the type argument. */
502 switch (type_arg[0])
504 case 'f':
505 case 'd':
506 case 'l':
507 operation (type_arg[0]);
508 break;
512 return test_exit_status;
514 skip:
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);
518 return 77;