1
0
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:
Bruno Haible
2023-10-31 21:54:49 +01:00
parent e5a52e29df
commit e60ee371bb
5 changed files with 621 additions and 0 deletions

View File

@@ -1,5 +1,11 @@
2023-10-31 Bruno Haible <bruno@clisp.org> 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. fenv-exceptions-trapping: New module.
* lib/fenv.in.h (feenableexcept, fedisableexcept, fegetexcept): New * lib/fenv.in.h (feenableexcept, fedisableexcept, fegetexcept): New
declarations. declarations.

View 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@

View 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;
}

View 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;
}

View 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