+2024-01-18 Bruno Haible <bruno@clisp.org>
+
+ fmaf, fma, fmal: Work around bugs on OpenBSD 7.4/arm64.
+ * m4/fmaf.m4 (gl_FUNC_FMAF_WORKS): Use a volatile function pointer
+ variable to disable clang's inlining.
+ * m4/fma.m4 (gl_FUNC_FMA_WORKS): Likewise.
+ * m4/fmal.m4 (gl_FUNC_FMAL_WORKS): Likewise.
+ * doc/posix-functions/fmaf.texi: Mention the OpenBSD bug.
+ * doc/posix-functions/fma.texi: Likewise.
+ * doc/posix-functions/fmal.texi: Likewise.
+
2024-01-17 Bruno Haible <bruno@clisp.org>
getopt-gnu: Fix out-of-bounds access (regression 2023-12-11).
FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 9, MSVC 9.
@item
This function produces wrong results on some platforms:
-glibc 2.11, Mac OS X 10.5, FreeBSD 6.4/x86, NetBSD 8.0, Cygwin 1.5, mingw.
+glibc 2.11, Mac OS X 10.5, FreeBSD 6.4/x86, NetBSD 8.0, OpenBSD 7.4/arm64, Cygwin 1.5, mingw.
@end itemize
Portability problems not fixed by Gnulib:
FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 9, MSVC 9.
@item
This function produces wrong results on some platforms:
-glibc 2.11, Mac OS X 10.5, FreeBSD 6.4/x86, FreeBSD 12.2/arm, Cygwin 1.5, mingw.
+glibc 2.11, Mac OS X 10.5, FreeBSD 6.4/x86, FreeBSD 12.2/arm, OpenBSD 7.4/arm64, Cygwin 1.5, mingw.
@end itemize
Portability problems not fixed by Gnulib:
FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 9, Cygwin 1.7.x, MSVC 9, Android 4.4.
@item
This function produces wrong results on some platforms:
-glibc 2.17, macOS 10.13, FreeBSD 6.4/x86, mingw.
+glibc 2.17, macOS 10.13, FreeBSD 6.4/x86, OpenBSD 7.4/arm64, mingw.
@end itemize
Portability problems not fixed by Gnulib:
-# fma.m4 serial 6
+# fma.m4 serial 6.1
dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
[AC_LANG_SOURCE([[
#include <float.h>
#include <math.h>
+double (* volatile my_fma) (double, double, double) = fma;
double p0 = 0.0;
int main()
{
and is closer to (2^52 + 1) * 2^2, therefore the rounding
must round up and produce (2^52 + 1) * 2^2. */
volatile double expected = z + 4.0;
- volatile double result = fma (x, y, z);
+ volatile double result = my_fma (x, y, z);
if (result != expected)
failed_tests |= 1;
}
and is closer to (2^53 - 1) * 2^1, therefore the rounding
must round down and produce (2^53 - 1) * 2^1. */
volatile double expected = (ldexp (1.0, DBL_MANT_DIG) - 1.0) * 2.0;
- volatile double result = fma (x, y, z);
+ volatile double result = my_fma (x, y, z);
if (result != expected)
failed_tests |= 2;
}
and is closer to (2^52 + 2^50 + 1) * 2^-50, therefore the rounding
must round up and produce (2^52 + 2^50 + 1) * 2^-50. */
volatile double expected = 4.0 + 1.0 + ldexp (1.0, 3 - DBL_MANT_DIG);
- volatile double result = fma (x, y, z);
+ volatile double result = my_fma (x, y, z);
if (result != expected)
failed_tests |= 4;
}
(2^52 + 2^51 + 2^50 - 1) * 2^-50, therefore the rounding
must round down and produce (2^52 + 2^51 + 2^50 - 1) * 2^-50. */
volatile double expected = 7.0 - ldexp (1.0, 3 - DBL_MANT_DIG);
- volatile double result = fma (x, y, z);
+ volatile double result = my_fma (x, y, z);
if (result != expected)
failed_tests |= 8;
}
Lies between (2^53 - 2^0) and 2^53 and is closer to (2^53 - 2^0),
therefore the rounding must round down and produce (2^53 - 2^0). */
volatile double expected = ldexp (1.0, DBL_MANT_DIG) - 1.0;
- volatile double result = fma (x, y, z);
+ volatile double result = my_fma (x, y, z);
if (result != expected)
failed_tests |= 16;
}
+ /* This test fails on OpenBSD 7.4/arm64. */
if ((DBL_MANT_DIG % 2) == 1)
{
volatile double x = 1.0 + ldexp (1.0, - (DBL_MANT_DIG + 1) / 2); /* 2^0 + 2^-27 */
(2^53 - 1) * 2^-53, therefore the rounding must round down and
produce (2^53 - 1) * 2^-53. */
volatile double expected = 1.0 - ldexp (1.0, - DBL_MANT_DIG);
- volatile double result = fma (x, y, z);
+ volatile double result = my_fma (x, y, z);
if (result != expected)
failed_tests |= 32;
}
volatile double x = ldexp (1.0, DBL_MAX_EXP - 1);
volatile double y = ldexp (1.0, DBL_MAX_EXP - 1);
volatile double z = minus_inf;
- volatile double result = fma (x, y, z);
+ volatile double result = my_fma (x, y, z);
if (!(result == minus_inf))
failed_tests |= 64;
}
-# fmaf.m4 serial 8
+# fmaf.m4 serial 8.1
dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
[AC_LANG_SOURCE([[
#include <float.h>
#include <math.h>
+float (* volatile my_fmaf) (float, float, float) = fmaf;
float p0 = 0.0f;
int main()
{
and is closer to (2^23 + 1) * 2^2, therefore the rounding
must round up and produce (2^23 + 1) * 2^2. */
volatile float expected = z + 4.0f;
- volatile float result = fmaf (x, y, z);
+ volatile float result = my_fmaf (x, y, z);
if (result != expected)
failed_tests |= 1;
}
and is closer to (2^24 - 1) * 2^1, therefore the rounding
must round down and produce (2^24 - 1) * 2^1. */
volatile float expected = (ldexpf (1.0f, FLT_MANT_DIG) - 1.0f) * 2.0f;
- volatile float result = fmaf (x, y, z);
+ volatile float result = my_fmaf (x, y, z);
if (result != expected)
failed_tests |= 2;
}
and is closer to (2^23 + 2^21 + 1) * 2^-21, therefore the rounding
must round up and produce (2^23 + 2^21 + 1) * 2^-21. */
volatile float expected = 4.0f + 1.0f + ldexpf (1.0f, 3 - FLT_MANT_DIG);
- volatile float result = fmaf (x, y, z);
+ volatile float result = my_fmaf (x, y, z);
if (result != expected)
failed_tests |= 4;
}
(2^23 + 2^22 + 2^21 - 1) * 2^-21, therefore the rounding
must round down and produce (2^23 + 2^22 + 2^21 - 1) * 2^-21. */
volatile float expected = 7.0f - ldexpf (1.0f, 3 - FLT_MANT_DIG);
- volatile float result = fmaf (x, y, z);
+ volatile float result = my_fmaf (x, y, z);
if (result != expected)
failed_tests |= 8;
}
Lies between (2^24 - 2^0) and 2^24 and is closer to (2^24 - 2^0),
therefore the rounding must round down and produce (2^24 - 2^0). */
volatile float expected = ldexpf (1.0f, FLT_MANT_DIG) - 1.0f;
- volatile float result = fmaf (x, y, z);
+ volatile float result = my_fmaf (x, y, z);
if (result != expected)
failed_tests |= 16;
}
+ /* This test fails on OpenBSD 7.4/arm64. */
if ((FLT_MANT_DIG % 2) == 0)
{
volatile float x = 1.0f + ldexpf (1.0f, - FLT_MANT_DIG / 2); /* 2^0 + 2^-12 */
must round up and produce (2^23 + 2^12 + 1) * 2^-23. */
volatile float expected =
1.0f + ldexpf (1.0f, 1 - FLT_MANT_DIG / 2) + ldexpf (1.0f, 1 - FLT_MANT_DIG);
- volatile float result = fmaf (x, y, z);
+ volatile float result = my_fmaf (x, y, z);
if (result != expected)
failed_tests |= 32;
}
- {
- float minus_inf = -1.0f / p0;
- volatile float x = ldexpf (1.0f, FLT_MAX_EXP - 1);
- volatile float y = ldexpf (1.0f, FLT_MAX_EXP - 1);
- volatile float z = minus_inf;
- volatile float result = fmaf (x, y, z);
- if (!(result == minus_inf))
- failed_tests |= 64;
- }
/* This test fails on FreeBSD 12.2/arm. */
if ((FLT_MANT_DIG % 2) == 0)
{
volatile float x = 1.0f + ldexpf (1.0f, - FLT_MANT_DIG / 2); /* 2^0 + 2^-12 */
volatile float y = x;
- volatile float z = - ldexpf (1.0f, FLT_MIN_EXP - FLT_MANT_DIG); /* 2^-149 */
+ volatile float z = - ldexpf (1.0f, FLT_MIN_EXP - FLT_MANT_DIG); /* - 2^-149 */
/* x * y + z with infinite precision: 2^0 + 2^-11 + 2^-24 - 2^-149.
Lies between (2^23 + 2^12 + 0) * 2^-23 and (2^23 + 2^12 + 1) * 2^-23
and is closer to (2^23 + 2^12 + 0) * 2^-23, therefore the rounding
must round down and produce (2^23 + 2^12 + 0) * 2^-23. */
volatile float expected = 1.0f + ldexpf (1.0f, 1 - FLT_MANT_DIG / 2);
- volatile float result = fmaf (x, y, z);
+ volatile float result = my_fmaf (x, y, z);
if (result != expected)
failed_tests |= 32;
}
+ {
+ float minus_inf = -1.0f / p0;
+ volatile float x = ldexpf (1.0f, FLT_MAX_EXP - 1);
+ volatile float y = ldexpf (1.0f, FLT_MAX_EXP - 1);
+ volatile float z = minus_inf;
+ volatile float result = my_fmaf (x, y, z);
+ if (!(result == minus_inf))
+ failed_tests |= 64;
+ }
return failed_tests;
}]])],
[gl_cv_func_fmaf_works=yes],
-# fmal.m4 serial 10
+# fmal.m4 serial 10.1
dnl Copyright (C) 2011-2024 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
# define LDBL_MIN_EXP DBL_MIN_EXP
# endif
#endif
+long double (* volatile my_fmal) (long double, long double, long double) = fmal;
long double p0 = 0.0L;
int main()
{
and is closer to (2^63 + 1) * 2^2, therefore the rounding
must round up and produce (2^63 + 1) * 2^2. */
volatile long double expected = z + 4.0L;
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 1;
}
and is closer to (2^64 - 1) * 2^1, therefore the rounding
must round down and produce (2^64 - 1) * 2^1. */
volatile long double expected = (ldexpl (1.0L, LDBL_MANT_DIG) - 1.0L) * 2.0L;
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 1;
}
and is closer to (2^63 + 2^61 + 1) * 2^-61, therefore the rounding
must round up and produce (2^63 + 2^61 + 1) * 2^-61. */
volatile long double expected = 4.0L + 1.0L + ldexpl (1.0L, 3 - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 2;
}
/* This test fails on glibc 2.11 x86,x86_64,powerpc glibc 2.7 hppa,sparc,
- OSF/1 5.1, mingw. */
+ OpenBSD 7.4/arm64, OSF/1 5.1, mingw. */
{
volatile long double x = 1.0L + ldexpl (1.0L, 1 - LDBL_MANT_DIG); /* 2^0 + 2^-63 */
volatile long double y = - x;
(2^63 + 2^62 + 2^61 - 1) * 2^-61, therefore the rounding
must round down and produce (2^63 + 2^62 + 2^61 - 1) * 2^-61. */
volatile long double expected = 7.0L - ldexpl (1.0L, 3 - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 2;
}
Lies between (2^64 - 2^0) and 2^64 and is closer to (2^64 - 2^0),
therefore the rounding must round down and produce (2^64 - 2^0). */
volatile long double expected = ldexpl (1.0L, LDBL_MANT_DIG) - 1.0L;
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 1;
}
if ((LDBL_MANT_DIG % 2) == 1)
{
- /* These tests fail on glibc 2.7 hppa,sparc, OSF/1 5.1. */
+ /* These tests fail on glibc 2.7 hppa,sparc, OpenBSD 7.4/arm64, OSF/1 5.1. */
{
volatile long double x = 1.0L + ldexpl (1.0L, - (LDBL_MANT_DIG + 1) / 2); /* 2^0 + 2^-27 */
volatile long double y = 1.0L - ldexpl (1.0L, - (LDBL_MANT_DIG + 1) / 2); /* 2^0 - 2^-27 */
(2^53 - 1) * 2^-53, therefore the rounding must round down and
produce (2^53 - 1) * 2^-53. */
volatile long double expected = 1.0L - ldexpl (1.0L, - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 4;
}
must round up and produce (2^112 + 2^56 + 1) * 2^-112. */
volatile long double expected =
1.0L + ldexpl (1.0L, - (LDBL_MANT_DIG - 1) / 2) + ldexpl (1.0L, 1 - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 4;
}
must round up and produce (2^63 + 2^32 + 1) * 2^-63. */
volatile long double expected =
1.0L + ldexpl (1.0L, 1 - LDBL_MANT_DIG / 2) + ldexpl (1.0L, 1 - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
/* x * y + z with infinite precision: 2^0 + 2^-31 + 2^-63.
Rounding must return this value unchanged. */
volatile long double expected = 1.0L + ldexpl (1.0L, 1 - LDBL_MANT_DIG / 2) + ldexpl (1.0L, 1 - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
and is at the same distance from each. According to the round-to-even
rule, the rounding must round up and produce (2^63 + 2^32 + 2) * 2^-63. */
volatile long double expected = 1.0L + ldexpl (1.0L, -31) + ldexpl (1.0L, -62);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
and is closer to (2^63 + 2^30 + 1) * 2^-30, therefore the rounding
must round up and produce (2^63 + 2^30 + 1) * 2^-30. */
volatile long double expected = z + 1.0L + ldexp (1.0L, 2 - LDBL_MANT_DIG / 2);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
and is at the same distance from each. According to the round-to-even
rule, the rounding must round up and produce (2^63 + 2^32) * 2^-63. */
volatile long double expected = 1.0L + ldexpl (1.0L, 1 - LDBL_MANT_DIG / 2);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
/* x * y + z with infinite precision: 2^-31 + 2^-64.
Rounding must return this value unchanged. */
volatile long double expected = ldexpl (1.0L, 1 - LDBL_MANT_DIG / 2) + ldexpl (1.0L, - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
/* x * y + z with infinite precision: 2^0 - 2^31 - 2^-64.
Rounding must return this value unchanged. */
volatile long double expected = 1.0L - ldexpl (1.0L, 1 - LDBL_MANT_DIG / 2) - ldexpl (1.0L, - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
and is closer to (2^64 - 2^30 - 1) * 2^-30, therefore the rounding
must round down and produce (2^64 - 2^30 - 1) * 2^-30. */
volatile long double expected = z - 1.0L - ldexpl (1.0L, 2 - LDBL_MANT_DIG / 2);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
(2^64 - 1) * 2^-64, therefore the rounding must round down and
produce (2^64 - 1) * 2^-64. */
volatile long double expected = 1.0L - ldexpl (1.0L, - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
/* x * y + z with infinite precision: - 2^-66.
Rounding must return this value unchanged. */
volatile long double expected = - ldexpl (1.0L, - LDBL_MANT_DIG - 2);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 8;
}
volatile long double x = ldexpl (1.0L, LDBL_MAX_EXP - 1);
volatile long double y = ldexpl (1.0L, LDBL_MAX_EXP - 1);
volatile long double z = minus_inf;
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (!(result == minus_inf))
failed_tests |= 16;
}
volatile long double z =
- ldexpl (ldexpl (1.0L, LDBL_MAX_EXP - 1) - ldexpl (1.0L, LDBL_MAX_EXP - LDBL_MANT_DIG - 1), 1);
volatile long double expected = ldexpl (1.0L, LDBL_MAX_EXP - LDBL_MANT_DIG);
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 32;
}
According to the round-to-even rule, the rounding must round up and
produce 2^0. */
volatile long double expected = 1.0L;
- volatile long double result = fmal (x, y, z);
+ volatile long double result = my_fmal (x, y, z);
if (result != expected)
failed_tests |= 64;
}