From: Bruno Haible Date: Thu, 18 Jan 2024 13:55:25 +0000 (+0100) Subject: fmaf, fma, fmal: Work around bugs on OpenBSD 7.4/arm64. X-Git-Tag: v1.0~512 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=646c3890e144097a8e097090c3256e54503bdca6;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index 40cecde393..bc530c19fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2024-01-18 Bruno Haible + + 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-18 Bruno Haible doc: Update regarding stable branches. diff --git a/doc/posix-functions/fma.texi b/doc/posix-functions/fma.texi index 618f0c962a..039c5bbfdf 100644 --- a/doc/posix-functions/fma.texi +++ b/doc/posix-functions/fma.texi @@ -13,7 +13,7 @@ This function is missing on some platforms: 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: diff --git a/doc/posix-functions/fmaf.texi b/doc/posix-functions/fmaf.texi index 3551d19999..81481e2ef4 100644 --- a/doc/posix-functions/fmaf.texi +++ b/doc/posix-functions/fmaf.texi @@ -13,7 +13,7 @@ This function is missing on some platforms: 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: diff --git a/doc/posix-functions/fmal.texi b/doc/posix-functions/fmal.texi index 99223b317a..65a23d7e7c 100644 --- a/doc/posix-functions/fmal.texi +++ b/doc/posix-functions/fmal.texi @@ -13,7 +13,7 @@ This function is missing on some platforms: 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: diff --git a/m4/fma.m4 b/m4/fma.m4 index 01c2fcf0d3..bf25e7b54f 100644 --- a/m4/fma.m4 +++ b/m4/fma.m4 @@ -1,4 +1,4 @@ -# fma.m4 serial 7 +# fma.m4 serial 8 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, @@ -70,6 +70,7 @@ AC_DEFUN([gl_FUNC_FMA_WORKS], [AC_LANG_SOURCE([[ #include #include +double (* volatile my_fma) (double, double, double) = fma; double p0 = 0.0; int main() { @@ -84,7 +85,7 @@ 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; } @@ -97,7 +98,7 @@ int main() 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; } @@ -110,7 +111,7 @@ int main() 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; } @@ -124,7 +125,7 @@ int main() (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; } @@ -136,10 +137,11 @@ int main() 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 */ @@ -150,7 +152,7 @@ int main() (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; } @@ -159,7 +161,7 @@ int main() 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; } diff --git a/m4/fmaf.m4 b/m4/fmaf.m4 index 2985d925a2..ad3ed288a7 100644 --- a/m4/fmaf.m4 +++ b/m4/fmaf.m4 @@ -1,4 +1,4 @@ -# fmaf.m4 serial 9 +# fmaf.m4 serial 10 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, @@ -73,6 +73,7 @@ AC_DEFUN([gl_FUNC_FMAF_WORKS], [AC_LANG_SOURCE([[ #include #include +float (* volatile my_fmaf) (float, float, float) = fmaf; float p0 = 0.0f; int main() { @@ -87,7 +88,7 @@ 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; } @@ -100,7 +101,7 @@ int main() 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; } @@ -113,7 +114,7 @@ int main() 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; } @@ -127,7 +128,7 @@ int main() (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; } @@ -139,10 +140,11 @@ int main() 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 */ @@ -154,34 +156,34 @@ int main() 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], diff --git a/m4/fmal.m4 b/m4/fmal.m4 index d0f041d891..2b7b3183f4 100644 --- a/m4/fmal.m4 +++ b/m4/fmal.m4 @@ -1,4 +1,4 @@ -# fmal.m4 serial 11 +# fmal.m4 serial 12 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, @@ -109,6 +109,7 @@ AC_DEFUN([gl_FUNC_FMAL_WORKS], # 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() { @@ -123,7 +124,7 @@ 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; } @@ -137,7 +138,7 @@ int main() 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; } @@ -152,12 +153,12 @@ int main() 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; @@ -168,7 +169,7 @@ int main() (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; } @@ -181,13 +182,13 @@ int main() 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 */ @@ -197,7 +198,7 @@ int main() (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; } @@ -211,7 +212,7 @@ int main() 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; } @@ -229,7 +230,7 @@ int main() 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; } @@ -240,7 +241,7 @@ int main() /* 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; } @@ -253,7 +254,7 @@ int main() 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; } @@ -266,7 +267,7 @@ int main() 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; } @@ -279,7 +280,7 @@ int main() 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; } @@ -290,7 +291,7 @@ int main() /* 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; } @@ -301,7 +302,7 @@ int main() /* 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; } @@ -314,7 +315,7 @@ int main() 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; } @@ -327,7 +328,7 @@ int main() (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; } @@ -338,7 +339,7 @@ int main() /* 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; } @@ -350,7 +351,7 @@ int main() 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; } @@ -362,7 +363,7 @@ int main() 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; } @@ -376,7 +377,7 @@ int main() 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; }