mirror of
https://git.savannah.gnu.org/git/gnulib.git
synced 2025-08-08 17:22:05 +03:00
fenv-exceptions-trapping: Add tests.
* tests/test-fenv-except-trapping-1.c: New file. * tests/test-fenv-except-trapping-2.sh: New file. * tests/test-fenv-except-trapping-2.c: New file. * modules/fenv-exceptions-trapping-tests: New file.
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
2023-10-31 Bruno Haible <bruno@clisp.org>
|
||||
|
||||
fenv-exceptions-trapping: Add tests.
|
||||
* tests/test-fenv-except-trapping-1.c: New file.
|
||||
* tests/test-fenv-except-trapping-2.sh: New file.
|
||||
* tests/test-fenv-except-trapping-2.c: New file.
|
||||
* modules/fenv-exceptions-trapping-tests: New file.
|
||||
|
||||
fenv-exceptions-trapping: New module.
|
||||
* lib/fenv.in.h (feenableexcept, fedisableexcept, fegetexcept): New
|
||||
declarations.
|
||||
|
25
modules/fenv-exceptions-trapping-tests
Normal file
25
modules/fenv-exceptions-trapping-tests
Normal file
@@ -0,0 +1,25 @@
|
||||
Files:
|
||||
tests/test-fenv-except-trapping-1.c
|
||||
tests/test-fenv-except-trapping-2.sh
|
||||
tests/test-fenv-except-trapping-2.c
|
||||
tests/infinity.h
|
||||
tests/macros.h
|
||||
m4/musl.m4
|
||||
|
||||
Depends-on:
|
||||
fenv-exceptions-tracking-c99
|
||||
nan
|
||||
snan
|
||||
|
||||
configure.ac:
|
||||
gl_MUSL_LIBC
|
||||
|
||||
Makefile.am:
|
||||
TESTS += \
|
||||
test-fenv-except-trapping-1 \
|
||||
test-fenv-except-trapping-2.sh
|
||||
check_PROGRAMS += \
|
||||
test-fenv-except-trapping-1 \
|
||||
test-fenv-except-trapping-2
|
||||
test_fenv_except_trapping_1_LDADD = $(LDADD) @FENV_EXCEPTIONS_TRAPPING_LIBM@
|
||||
test_fenv_except_trapping_2_LDADD = $(LDADD) @FENV_EXCEPTIONS_TRAPPING_LIBM@ @FENV_EXCEPTIONS_TRACKING_LIBM@
|
69
tests/test-fenv-except-trapping-1.c
Normal file
69
tests/test-fenv-except-trapping-1.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/* Test of turning floating-point exceptions into traps (signals).
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <fenv.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
/* Check of the Boole-an algebra. */
|
||||
|
||||
/* Converts 5 bits to an exceptions bit mask. */
|
||||
static int
|
||||
uint_to_exceptions (unsigned int a)
|
||||
{
|
||||
return (a & 0x01 ? FE_INVALID : 0)
|
||||
| (a & 0x02 ? FE_DIVBYZERO : 0)
|
||||
| (a & 0x04 ? FE_OVERFLOW : 0)
|
||||
| (a & 0x08 ? FE_UNDERFLOW : 0)
|
||||
| (a & 0x10 ? FE_INEXACT : 0);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
unsigned int a, b;
|
||||
|
||||
/* Run through all possible valid arguments to feenableexcept and
|
||||
fedisableexcept. */
|
||||
for (a = 0; a < 0x20; a++)
|
||||
for (b = 0; b < 0x20; b++)
|
||||
{
|
||||
unsigned int c = a & ~b;
|
||||
|
||||
if (fedisableexcept (FE_ALL_EXCEPT) == -1
|
||||
|| feenableexcept (uint_to_exceptions (a)) == -1)
|
||||
{
|
||||
fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr);
|
||||
return 77;
|
||||
}
|
||||
ASSERT (fedisableexcept (uint_to_exceptions (b))
|
||||
== uint_to_exceptions (a));
|
||||
/* Check fegetexcept. */
|
||||
ASSERT (fegetexcept () == uint_to_exceptions (c));
|
||||
/* Check the return value of feenableexcept. It should be consistent
|
||||
with fegetexcept. */
|
||||
ASSERT (feenableexcept (0) == uint_to_exceptions (c));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
488
tests/test-fenv-except-trapping-2.c
Normal file
488
tests/test-fenv-except-trapping-2.c
Normal file
@@ -0,0 +1,488 @@
|
||||
/* Test of turning floating-point exceptions into traps (signals).
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Bruno Haible <bruno@clisp.org>, 2023. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#include <fenv.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "infinity.h"
|
||||
#include "snan.h"
|
||||
#include "macros.h"
|
||||
|
||||
/* Operations that should raise various floating-point exceptions. */
|
||||
|
||||
/* For a list, see the glibc documentation
|
||||
<https://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html> */
|
||||
|
||||
#define infinityf my_infinityf /* Avoid collision with Cygwin's <math.h> */
|
||||
static float volatile infinityf, qnanf;
|
||||
static double volatile infinityd, qnand;
|
||||
static long double volatile infinityl, qnanl;
|
||||
|
||||
static void
|
||||
raise_invalid_addition (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = infinityf; b = - infinityf;
|
||||
c = a + b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = infinityd; b = - infinityd;
|
||||
c = a + b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = infinityl; b = - infinityl;
|
||||
c = a + b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_invalid_multiplication (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = infinityf; b = 0.0f;
|
||||
c = a * b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = infinityd; b = 0.0;
|
||||
c = a * b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = infinityl; b = 0.0L;
|
||||
c = a * b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_invalid_division (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = infinityf; b = - infinityf;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = infinityd; b = - infinityd;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = infinityl; b = - infinityl;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_invalid_comparison (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED int volatile c;
|
||||
a = qnanf; b = qnanf;
|
||||
c = a > b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED int volatile c;
|
||||
a = qnand; b = qnand;
|
||||
c = a > b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED int volatile c;
|
||||
a = qnanl; b = qnanl;
|
||||
c = a > b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_invalid_snan (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = SNaNf (); b = 1.0f;
|
||||
c = a + b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = SNaNd (); b = 1.0;
|
||||
c = a + b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = SNaNl (); b = 1.0L;
|
||||
c = a + b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_divbyzero (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = 2.5f; b = - 0.0f;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = 2.5; b = - 0.0;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = 2.5L; b = - 0.0L;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_overflow (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = 1e20f; b = 1e30f;
|
||||
c = a * b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = 1e160; b = 1e260;
|
||||
c = a * b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = 1e200L; b = 1e300L;
|
||||
c = a * b;
|
||||
c = c * c;
|
||||
c = c * c;
|
||||
c = c * c;
|
||||
c = c * c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_underflow (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = 1e-20f; b = 1e-30f;
|
||||
c = a * b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = 1e-160; b = 1e-260;
|
||||
c = a * b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = 1e-200L; b = 1e-300L;
|
||||
c = a * b;
|
||||
c = c * c;
|
||||
c = c * c;
|
||||
c = c * c;
|
||||
c = c * c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
raise_inexact (char type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 'f':
|
||||
{
|
||||
float volatile a, b;
|
||||
_GL_UNUSED float volatile c;
|
||||
a = 2.5f; b = 3.0f;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
{
|
||||
double volatile a, b;
|
||||
_GL_UNUSED double volatile c;
|
||||
a = 2.5; b = 3.0;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
{
|
||||
long double volatile a, b;
|
||||
_GL_UNUSED long double volatile c;
|
||||
a = 2.5L; b = 3.0L;
|
||||
c = a / b;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
if (argc > 3)
|
||||
{
|
||||
const char *operation_arg = argv[1];
|
||||
const char *procedure_arg = argv[2];
|
||||
const char *type_arg = argv[3];
|
||||
|
||||
void (*operation) (char) = NULL;
|
||||
int expected_exceptions = 0;
|
||||
int possible_exceptions = 0;
|
||||
|
||||
/* Preparations (to be executed before we call feenableexcept). */
|
||||
infinityf = Infinityf ();
|
||||
qnanf = NaNf ();
|
||||
infinityd = Infinityd ();
|
||||
qnand = NaNd ();
|
||||
infinityl = Infinityl ();
|
||||
qnanl = NaNl ();
|
||||
feclearexcept (FE_ALL_EXCEPT);
|
||||
|
||||
/* Analyze the operation argument. */
|
||||
switch (operation_arg[0])
|
||||
{
|
||||
case '1':
|
||||
operation = raise_invalid_addition;
|
||||
expected_exceptions = FE_INVALID;
|
||||
break;
|
||||
case '2':
|
||||
operation = raise_invalid_multiplication;
|
||||
expected_exceptions = FE_INVALID;
|
||||
break;
|
||||
case '3':
|
||||
operation = raise_invalid_division;
|
||||
expected_exceptions = FE_INVALID;
|
||||
break;
|
||||
case '4':
|
||||
operation = raise_invalid_comparison;
|
||||
expected_exceptions = FE_INVALID;
|
||||
break;
|
||||
case '5':
|
||||
operation = raise_invalid_snan;
|
||||
expected_exceptions = FE_INVALID;
|
||||
break;
|
||||
case '6':
|
||||
operation = raise_divbyzero;
|
||||
expected_exceptions = FE_DIVBYZERO;
|
||||
break;
|
||||
case '7':
|
||||
operation = raise_overflow;
|
||||
expected_exceptions = FE_OVERFLOW;
|
||||
possible_exceptions = FE_INEXACT;
|
||||
break;
|
||||
case '8':
|
||||
operation = raise_underflow;
|
||||
expected_exceptions = FE_UNDERFLOW;
|
||||
possible_exceptions = FE_INEXACT;
|
||||
break;
|
||||
case '9':
|
||||
operation = raise_inexact;
|
||||
expected_exceptions = FE_INEXACT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Analyze the procedure argument. */
|
||||
switch (procedure_arg[0])
|
||||
{
|
||||
/* These three procedures should lead to a trap. */
|
||||
case 'p':
|
||||
if (feenableexcept (expected_exceptions) == -1)
|
||||
goto skip;
|
||||
break;
|
||||
case 'q':
|
||||
if (feenableexcept (FE_ALL_EXCEPT) == -1)
|
||||
goto skip;
|
||||
break;
|
||||
case 'r':
|
||||
if (feenableexcept (FE_ALL_EXCEPT) == -1)
|
||||
goto skip;
|
||||
ASSERT (fedisableexcept (FE_ALL_EXCEPT & ~expected_exceptions)
|
||||
== FE_ALL_EXCEPT);
|
||||
break;
|
||||
/* This procedure should *not* lead to a trap. */
|
||||
case 's':
|
||||
if (feenableexcept (FE_ALL_EXCEPT & ~(expected_exceptions | possible_exceptions)) == -1)
|
||||
goto skip;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Avoid known test failures. */
|
||||
int known_failure = 0;
|
||||
/* The '4' tests do not work on Linux/powerpc* and Linux/s390*, as well as
|
||||
on GNU/kFreeBSD/i386, GNU/kFreeBSD/x86_64, musl libc/i386,
|
||||
musl libc/powerpc64le, macOS/i386, macOS/x86_64, macOS/arm64,
|
||||
FreeBSD/i386, FreeBSD/x86_64, NetBSD/i386, NetBSD/x86_64, OpenBSD/i386,
|
||||
OpenBSD/x86_64, AIX/powerpc, Solaris/i386, Solaris/x86_64,
|
||||
Cygwin/x86_64, native Windows/i386,
|
||||
native Windows/x86_64. */
|
||||
#if (__GLIBC__ >= 2 && (defined __powerpc__ || (defined __s390__ || defined __s390x__))) \
|
||||
|| (__GLIBC__ >= 2 && __FreeBSD_kernel__ && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86))) \
|
||||
|| (defined MUSL_LIBC && ((defined __i386 || defined _M_IX86) || defined __powerpc__)) \
|
||||
|| ((defined __APPLE__ && defined __MACH__) && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86) || defined __aarch64__)) \
|
||||
|| ((defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__) && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86))) \
|
||||
|| (defined _AIX && defined __powerpc__) \
|
||||
|| (defined __sun && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86))) \
|
||||
|| (defined __CYGWIN__ && (defined __x86_64__ || defined _M_X64)) \
|
||||
|| (defined _WIN32 && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)))
|
||||
known_failure |= (operation_arg[0] == '4');
|
||||
#endif
|
||||
/* The '7' and '8' tests, with types 'f' and 'd', do not work reliably
|
||||
on Linux/i386. */
|
||||
#if defined __i386 || defined _M_IX86
|
||||
known_failure |= (operation_arg[0] == '7' || operation_arg[0] == '8');
|
||||
#endif
|
||||
/* The '9' tests do not work on Linux/alpha, musl libc/powerpc64le,
|
||||
AIX/powerpc. */
|
||||
#if (__GLIBC__ >= 2 && defined __alpha) \
|
||||
|| ((defined MUSL_LIBC || defined _AIX) && defined __powerpc__)
|
||||
known_failure |= (operation_arg[0] == '9');
|
||||
#endif
|
||||
/* The 'l' tests do not work on Linux/loongarch64 with glibc 2.37.
|
||||
Likewise on Linux/alpha with glibc 2.7 on Linux 2.6.26.
|
||||
Likewise on FreeBSD 12.2/sparc.
|
||||
Cause unknown. */
|
||||
#if (__GLIBC__ >= 2 && defined __loongarch__) \
|
||||
|| ((__GLIBC__ == 2 && __GLIBC_MINOR__ < 36) && defined __alpha) \
|
||||
|| (defined __FreeBSD__ && defined __sparc)
|
||||
known_failure |= (type_arg[0] == 'l');
|
||||
#endif
|
||||
if (known_failure)
|
||||
{
|
||||
fputs ("Skipping test: known failure on this platform\n", stderr);
|
||||
return 77;
|
||||
}
|
||||
|
||||
/* Analyze the type argument. */
|
||||
switch (type_arg[0])
|
||||
{
|
||||
case 'f':
|
||||
case 'd':
|
||||
case 'l':
|
||||
operation (type_arg[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
skip:
|
||||
fputs ("Skipping test: trapping floating-point exceptions are not supported on this machine.\n", stderr);
|
||||
return 77;
|
||||
}
|
33
tests/test-fenv-except-trapping-2.sh
Executable file
33
tests/test-fenv-except-trapping-2.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Test of turning floating-point exceptions into traps (signals).
|
||||
|
||||
final_rc=0
|
||||
|
||||
for operation in 1 2 3 4 5 6 7 8 9; do
|
||||
for procedure in p q r s; do
|
||||
for type in f d l; do
|
||||
${CHECKER} ./test-fenv-except-trapping-2${EXEEXT} $operation $procedure $type
|
||||
rc=$?
|
||||
if test $rc = 77; then
|
||||
if test $final_rc = 0; then
|
||||
final_rc=77
|
||||
fi
|
||||
else
|
||||
if test $procedure = s; then
|
||||
if test $rc != 0; then
|
||||
echo "Failed (got a trap): ./test-fenv-except-trapping-2 $operation $procedure $type" 1>&2
|
||||
final_rc=1
|
||||
fi
|
||||
else
|
||||
if test $rc = 0; then
|
||||
echo "Failed (got no trap): ./test-fenv-except-trapping-2 $operation $procedure $type" 1>&2
|
||||
final_rc=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
exit $final_rc
|
Reference in New Issue
Block a user