Subject: [PATCH] math: Add test-nldbl
To: libc-alpha@sourceware.org
2018-07-02 Florian Weimer <fweimer@redhat.com>
* sysdeps/ieee754/ldbl-opt/test-nldbl.c: New file.
* sysdeps/ieee754/ldbl-opt/test-nldbl-check1.c: Likewise.
* sysdeps/ieee754/ldbl-opt/test-nldbl-check2.c: Likewise.
* sysdeps/ieee754/ldbl-opt/test-nldbl-check3.c: Likewise.
* sysdeps/ieee754/ldbl-opt/Makefile (tests): Add test-nldbl.
(CFLAGS-test-nldbl.c): Switch to 64-bit long double and disable
built-ins.
@@ -175,4 +175,7 @@ CFLAGS-nldbl-yn.c = -fno-builtin-ynl
tests += test-narrow-macros-ldbl-64
CFLAGS-test-narrow-macros-ldbl-64.c += -mlong-double-64
+tests += test-nldbl
+CFLAGS-test-nldbl.c += -mlong-double-64 -fno-builtin
+
endif
new file mode 100644
@@ -0,0 +1,48 @@
+/* Verify single-argument functions.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+static void
+NAME (const char *name, RETURN_TYPE_L (*func) (ARG0_TYPE_L),
+ RETURN_TYPE (*reference) (ARG0_TYPE))
+{
+ for (int do_negative = 0; do_negative < 2; ++do_negative)
+ for (size_t i = 0; i < array_length (VALUES); ++i)
+ {
+ ARG0_TYPE value = VALUES[i];
+ if (do_negative)
+ value = -value;
+
+ /* volatile to avoid excess precision. */
+ volatile RETURN_TYPE expected = reference (value);
+ RETURN_TYPE_L actual = func (value);
+ if (!RESULT_EQUAL (expected, actual))
+ {
+ support_record_failure ();
+ REPORT_ERROR (name, value, expected, actual);
+ }
+ }
+}
+
+#undef NAME
+#undef ARG0_TYPE
+#undef ARG0_TYPE_L
+#undef RETURN_TYPE_L
+#undef RETURN_TYPE
+#undef VALUES
+#undef RESULT_EQUAL
+#undef REPORT_ERROR
new file mode 100644
@@ -0,0 +1,59 @@
+/* Verify two-argument functions.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+static void
+NAME (const char *name, RETURN_TYPE_L (*func) (ARG0_TYPE_L, ARG1_TYPE_L),
+ RETURN_TYPE (*reference) (ARG0_TYPE, ARG1_TYPE))
+{
+ for (int do_negative = 0; do_negative < 2; ++do_negative)
+ for (size_t i = 0; i < array_length (VALUES0); ++i)
+ {
+ ARG0_TYPE value0 = VALUES0[i];
+ if (do_negative)
+ value0 = -value0;
+
+ for (int do_negative1 = 0; do_negative1 < 2; ++do_negative1)
+ for (size_t i1 = 0; i1 < array_length (VALUES1); ++i1)
+ {
+ ARG1_TYPE value1 = VALUES1[i1];
+ if (do_negative1)
+ value1 = -value1;
+
+ /* volatile to avoid excess precision. */
+ volatile RETURN_TYPE expected = reference (value0, value1);
+ RETURN_TYPE_L actual = func (value0, value1);
+ if (!RESULT_EQUAL (expected, actual))
+ {
+ support_record_failure ();
+ REPORT_ERROR (name, value0, value1, expected, actual);
+ }
+ }
+ }
+}
+
+#undef NAME
+#undef ARG0_TYPE
+#undef ARG0_TYPE_L
+#undef ARG1_TYPE
+#undef ARG1_TYPE_L
+#undef RETURN_TYPE_L
+#undef RETURN_TYPE
+#undef VALUES0
+#undef VALUES1
+#undef RESULT_EQUAL
+#undef REPORT_ERROR
new file mode 100644
@@ -0,0 +1,73 @@
+/* Verify three-argument functions.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+static void
+NAME (const char *name,
+ RETURN_TYPE_L (*func) (ARG0_TYPE_L, ARG1_TYPE_L, ARG2_TYPE_L),
+ RETURN_TYPE (*reference) (ARG0_TYPE, ARG1_TYPE, ARG2_TYPE))
+{
+ for (int do_negative = 0; do_negative < 2; ++do_negative)
+ for (size_t i = 0; i < array_length (VALUES0); ++i)
+ {
+ ARG0_TYPE value0 = VALUES0[i];
+ if (do_negative)
+ value0 = -value0;
+
+ for (int do_negative1 = 0; do_negative1 < 2; ++do_negative1)
+ for (size_t i1 = 0; i1 < array_length (VALUES1); ++i1)
+ {
+ ARG1_TYPE value1 = VALUES1[i1];
+ if (do_negative1)
+ value1 = -value1;
+
+ for (int do_negative2 = 0; do_negative2 < 2; ++do_negative2)
+ for (size_t i2 = 0; i2 < array_length (VALUES2); ++i2)
+ {
+ ARG2_TYPE value2 = VALUES2[i2];
+ if (do_negative2)
+ value2 = -value2;
+
+ /* volatile to avoid excess precision. */
+ volatile RETURN_TYPE expected
+ = reference (value0, value1, value2);
+ RETURN_TYPE_L actual = func (value0, value1, value2);
+ if (!RESULT_EQUAL (expected, actual))
+ {
+ support_record_failure ();
+ REPORT_ERROR (name, value0, value1, value2,
+ expected, actual);
+ }
+ }
+ }
+ }
+}
+
+#undef NAME
+#undef ARG0_TYPE
+#undef ARG0_TYPE_L
+#undef ARG1_TYPE
+#undef ARG1_TYPE_L
+#undef ARG2_TYPE
+#undef ARG2_TYPE_L
+#undef RETURN_TYPE_L
+#undef RETURN_TYPE
+#undef VALUES0
+#undef VALUES1
+#undef VALUES2
+#undef RESULT_EQUAL
+#undef REPORT_ERROR
new file mode 100644
@@ -0,0 +1,925 @@
+/* Tests for nldbl redirects.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <complex.h>
+#include <float.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+/* These are lists of arbitrary values which are used to check that
+ the long double functions yield identical results to double
+ functions (so they are redirected to the right variant). */
+static const double double_values[] =
+ {
+ 0.0, DBL_MIN, FLT_MIN, 0.5,
+ 1.0, 1.5, M_SQRT2, 2.0, M_E, 3.0, M_PI, 4.0, 5.0,
+ 1.0e10, FLT_MAX, 1.0e100, DBL_MAX, HUGE_VAL,
+ };
+static const int int_values[] =
+ {
+ 0, 1, 2, 10
+ };
+
+static double complex complex_values[2
+ * sizeof (double_values)
+ / sizeof (double_values[0])
+ * sizeof (double_values)
+ / sizeof (double_values[0])];
+static void
+init_complex_values (void)
+{
+ size_t pos = 0;
+ for (size_t i = 0; i < array_length (double_values); ++i)
+ for (size_t j = 0; j < array_length (double_values); ++j)
+ for (int do_negative = 0; do_negative < 2; ++do_negative)
+ {
+ double imag = double_values[j];
+ if (do_negative)
+ imag = -imag;
+ complex_values[pos] = double_values[i] + imag * I;
+ ++pos;
+ }
+}
+
+static void
+print_double (double value)
+{
+ if (value != value)
+ printf ("NaN");
+ else
+ printf ("%.17e (%.14a)", value, value);
+}
+
+static void
+print_complex (double complex value)
+{
+ if (value != value)
+ printf ("NaN");
+ else
+ printf ("%.17e+%.17eI (%.14a+%.14aI)",
+ creal (value), cimag (value), creal (value), cimag (value));
+}
+
+/* Format codes used here:
+
+ i int
+ f float
+ d double
+ D long double
+ c double complex
+ C long double complex
+
+ We cannot use printf codes because there is none for float. */
+
+static bool
+result_equal_i (int expected, int actual)
+{
+ return expected == actual;
+}
+
+static bool
+result_equal_d (double expected, double actual)
+{
+ bool expected_nan = expected != expected;
+ bool actual_nan = actual != actual;
+ return expected_nan == actual_nan && (expected_nan || expected == actual);
+}
+
+static bool
+result_equal_f (float expected, float actual)
+{
+ bool expected_nan = expected != expected;
+ bool actual_nan = actual != actual;
+ return expected_nan == actual_nan && (expected_nan || expected == actual);
+}
+
+static bool
+result_equal_D (double expected, long double actual)
+{
+ bool expected_nan = expected != expected;
+ bool actual_nan = actual != actual;
+ return expected_nan == actual_nan && (expected_nan || expected == actual);
+}
+
+static bool
+result_equal_C (double complex expected, long double complex actual)
+{
+ bool expected_nan = expected != expected;
+ bool actual_nan = actual != actual;
+ return expected_nan == actual_nan && (expected_nan || expected == actual);
+}
+
+static void
+report_error_iD (const char *name, double value, int expected, int actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_double (value);
+ printf ("\n expected: %d\n actual: %d\n", expected, actual);
+}
+
+static void
+report_error_DD (const char *name, double value, double expected,
+ long double actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_double (value);
+ printf ("\n expected: ");
+ print_double (expected);
+ printf ("\n actual: ");
+ print_double (actual);
+ putchar ('\n');
+}
+
+static void
+report_error_DC (const char *name, double complex value,
+ double complex expected, long double actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_complex (value);
+ printf ("\n expected: ");
+ print_double (expected);
+ printf ("\n actual: ");
+ print_double (actual);
+ putchar ('\n');
+}
+
+static void
+report_error_CC (const char *name, double complex value,
+ double complex expected, long double complex actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_complex (value);
+ printf ("\n expected: ");
+ print_complex (expected);
+ printf ("\n actual: ");
+ print_complex (actual);
+ putchar ('\n');
+}
+
+static void
+report_error_DDD (const char *name, double value0, double value1,
+ double expected, long double actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_double (value0);
+ printf (", ");
+ print_double (value1);
+ printf ("\n expected: ");
+ print_double (expected);
+ printf ("\n actual: ");
+ print_double (actual);
+ putchar ('\n');
+}
+
+static void
+report_error_CCC (const char *name, double complex value0,
+ double complex value1,
+ double complex expected, long double complex actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_complex (value0);
+ printf (", ");
+ print_complex (value1);
+ printf ("\n expected: ");
+ print_complex (expected);
+ printf ("\n actual: ");
+ print_complex (actual);
+ putchar ('\n');
+}
+
+static void
+report_error_DDDD (const char *name, double value0, double value1,
+ double value2, double expected, long double actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_double (value0);
+ printf (", ");
+ print_double (value1);
+ printf (", ");
+ print_double (value2);
+ printf ("\n expected: ");
+ print_double (expected);
+ printf ("\n actual: ");
+ print_double (actual);
+ putchar ('\n');
+}
+
+static void
+report_error_iDD (const char *name, double value0, double value1,
+ int expected, int actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_double (value0);
+ printf (", ");
+ print_double (value1);
+ printf ("\n expected: %d\n actual: %d\n", expected, actual);
+}
+
+static void
+report_error_DDi (const char *name, double value0, int value1,
+ double expected, long double actual)
+{
+ printf ("error: %s result differs at ", name);
+ print_double (value0);
+ printf (", %d\n expected: ", value1);
+ print_double (expected);
+ printf ("\n actual: ");
+ print_double (actual);
+ putchar ('\n');
+}
+
+static void
+report_error_DiD (const char *name, double value0, int value1,
+ double expected, long double actual)
+{
+ printf ("error: %s result differs at %d, ", value0);
+ print_double (value1);
+ printf ("\n expected: ");
+ print_double (expected);
+ printf ("\n actual: ");
+ print_double (actual);
+ putchar ('\n');
+}
+
+#define NAME check_DD
+#define RETURN_TYPE_L long double
+#define ARG0_TYPE_L long double
+#define RETURN_TYPE double
+#define ARG0_TYPE double
+#define VALUES double_values
+#define RESULT_EQUAL result_equal_D
+#define REPORT_ERROR report_error_DD
+#include "test-nldbl-check1.c"
+
+#define NAME check_iD
+#define RETURN_TYPE_L int
+#define ARG0_TYPE_L long double
+#define RETURN_TYPE int
+#define ARG0_TYPE double
+#define VALUES double_values
+#define RESULT_EQUAL result_equal_i
+#define REPORT_ERROR report_error_iD
+#include "test-nldbl-check1.c"
+
+#define NAME check_DC
+#define RETURN_TYPE_L long double
+#define ARG0_TYPE_L long double complex
+#define RETURN_TYPE double
+#define ARG0_TYPE double complex
+#define VALUES complex_values
+#define RESULT_EQUAL result_equal_D
+#define REPORT_ERROR report_error_DC
+#include "test-nldbl-check1.c"
+
+#define NAME check_CC
+#define RETURN_TYPE_L long double complex
+#define ARG0_TYPE_L long double complex
+#define RETURN_TYPE double complex
+#define ARG0_TYPE double complex
+#define VALUES complex_values
+#define RESULT_EQUAL result_equal_C
+#define REPORT_ERROR report_error_CC
+#include "test-nldbl-check1.c"
+
+#define NAME check_DDD
+#define RETURN_TYPE_L long double
+#define ARG0_TYPE_L long double
+#define ARG1_TYPE_L long double
+#define RETURN_TYPE double
+#define ARG0_TYPE double
+#define ARG1_TYPE double
+#define VALUES0 double_values
+#define VALUES1 double_values
+#define RESULT_EQUAL result_equal_D
+#define REPORT_ERROR report_error_DDD
+#include "test-nldbl-check2.c"
+
+#define NAME check_iDD
+#define RETURN_TYPE_L int
+#define ARG0_TYPE_L long double
+#define ARG1_TYPE_L long double
+#define RETURN_TYPE int
+#define ARG0_TYPE double
+#define ARG1_TYPE double
+#define VALUES0 double_values
+#define VALUES1 double_values
+#define RESULT_EQUAL result_equal_i
+#define REPORT_ERROR report_error_iDD
+#include "test-nldbl-check2.c"
+
+#define NAME check_dDD
+#define RETURN_TYPE_L double
+#define ARG0_TYPE_L long double
+#define ARG1_TYPE_L long double
+#define RETURN_TYPE double
+#define ARG0_TYPE double
+#define ARG1_TYPE double
+#define VALUES0 double_values
+#define VALUES1 double_values
+#define RESULT_EQUAL result_equal_d
+#define REPORT_ERROR report_error_DDD
+#include "test-nldbl-check2.c"
+
+#define NAME check_fDD
+#define RETURN_TYPE_L float
+#define ARG0_TYPE_L long double
+#define ARG1_TYPE_L long double
+#define RETURN_TYPE float
+#define ARG0_TYPE double
+#define ARG1_TYPE double
+#define VALUES0 double_values
+#define VALUES1 double_values
+#define RESULT_EQUAL result_equal_f
+#define REPORT_ERROR report_error_DDD
+#include "test-nldbl-check2.c"
+
+#define NAME check_DDi
+#define RETURN_TYPE_L long double
+#define ARG0_TYPE_L long double
+#define ARG1_TYPE_L int
+#define RETURN_TYPE double
+#define ARG0_TYPE double
+#define ARG1_TYPE int
+#define VALUES0 double_values
+#define VALUES1 int_values
+#define RESULT_EQUAL result_equal_D
+#define REPORT_ERROR report_error_DDi
+#include "test-nldbl-check2.c"
+
+#define NAME check_DiD
+#define RETURN_TYPE_L long double
+#define ARG0_TYPE_L int
+#define ARG1_TYPE_L long double
+#define RETURN_TYPE double
+#define ARG0_TYPE int
+#define ARG1_TYPE double
+#define VALUES0 int_values
+#define VALUES1 double_values
+#define RESULT_EQUAL result_equal_D
+#define REPORT_ERROR report_error_DiD
+#include "test-nldbl-check2.c"
+
+#define NAME check_CCC
+#define RETURN_TYPE_L long double complex
+#define ARG0_TYPE_L long double complex
+#define ARG1_TYPE_L long double complex
+#define RETURN_TYPE double complex
+#define ARG0_TYPE double complex
+#define ARG1_TYPE double complex
+#define VALUES0 complex_values
+#define VALUES1 complex_values
+#define RESULT_EQUAL result_equal_C
+#define REPORT_ERROR report_error_CCC
+#include "test-nldbl-check2.c"
+
+#define NAME check_DDDD
+#define RETURN_TYPE_L long double
+#define ARG0_TYPE_L long double
+#define ARG1_TYPE_L long double
+#define ARG2_TYPE_L long double
+#define RETURN_TYPE double
+#define ARG0_TYPE double
+#define ARG1_TYPE double
+#define ARG2_TYPE double
+#define VALUES0 double_values
+#define VALUES1 double_values
+#define VALUES2 double_values
+#define RESULT_EQUAL result_equal_D
+#define REPORT_ERROR report_error_DDDD
+#include "test-nldbl-check3.c"
+
+/* Wrappers for type-generic functions. */
+
+static int
+signbit_iD (long double x)
+{
+ return signbit (x);
+}
+
+static int
+signbit_id (double x)
+{
+ return signbit (x);
+}
+
+static int
+fpclassify_iD (long double x)
+{
+ return fpclassify (x);
+}
+
+static int
+fpclassify_id (double x)
+{
+ return fpclassify (x);
+}
+
+static void
+single_argument_functions (void)
+{
+ check_DD ("acosl", &acosl, &acos);
+ check_DD ("acoshl", &acoshl, &acosh);
+ check_DD ("asinl", &asinl, &asin);
+ check_DD ("asinhl", &asinhl, &asinh);
+ check_DD ("atanl", &atanl, &atan);
+ check_DD ("atanhl", &atanhl, &atanh);
+ check_DD ("cbrtl", &cbrtl, &cbrt);
+ check_DD ("ceill", &ceill, &ceil);
+ check_DD ("cosl", &cosl, &cos);
+ check_DD ("coshl", &coshl, &cosh);
+ check_DD ("erfl", &erfl, &erf);
+ check_DD ("erfcl", &erfcl, &erfc);
+ check_DD ("exp10l", &exp10l, &exp10);
+ check_DD ("exp2l", &exp2l, &exp2);
+ check_DD ("expl", &expl, &exp);
+ check_DD ("expm1l", &expm1l, &expm1);
+ check_DD ("fabsl", &fabsl, &fabs);
+ check_DD ("floorl", &floorl, &floor);
+ check_DD ("gammal", &gammal, &gamma);
+ check_DD ("j0l", &j0l, &j0);
+ check_DD ("j1l", &j1l, &j1);
+ check_DD ("lgammal", &lgammal, &lgamma);
+ check_DD ("log10l", &log10l, &log10);
+ check_DD ("log1pl", &log1pl, &log1p);
+ check_DD ("log2l", &log2l, &log2);
+ check_DD ("logbl", &logbl, &logb);
+ check_DD ("logl", &logl, &log);
+ check_DD ("nearbyintl", &nearbyintl, &nearbyint);
+ check_DD ("nextdownl", &nextdownl, &nextdown);
+ check_DD ("nextupl", &nextupl, &nextup);
+ check_DD ("roundl", &roundl, &round);
+ check_DD ("roundevenl", &roundevenl, &roundeven);
+ check_DD ("significandl", &significandl, &significand);
+ check_DD ("sinl", &sinl, &sin);
+ check_DD ("sinhl", &sinhl, &sinh);
+ check_DD ("sqrtl", &sqrtl, &sqrt);
+ check_DD ("tanl", &tanl, &tan);
+ check_DD ("tanhl", &tanhl, &tanh);
+ check_DD ("tgammal", &tgammal, &tgamma);
+ check_DD ("truncl", &truncl, &trunc);
+ check_DD ("y0l", &y0l, &y0);
+ check_DD ("y1l", &y1l, &y1);
+
+ check_iD ("finitel", &finitel, &finite);
+ check_iD ("fpclassify", &fpclassify_iD, &fpclassify_id);
+ check_iD ("isinfl", &isinfl, &isinf);
+ check_iD ("isnanl", &isnanl, &isnan);
+ check_iD ("signbit", &signbit_iD, &signbit_id);
+
+ check_DC ("cabsl", &cabsl, &cabs);
+ check_DC ("cargl", &cargl, &carg);
+ check_DC ("cimagl", &cimagl, &cimag);
+ check_DC ("creal", &creall, &creal);
+
+ check_CC ("cacosl", &cacosl, &cacos);
+ check_CC ("cacoshl", &cacoshl, &cacosh);
+ check_CC ("casinl", &casinl, &casin);
+ check_CC ("casinhl", &casinhl, &casinh);
+ check_CC ("catanl", &catanl, &catan);
+ check_CC ("catanhl", &catanhl, &catanh);
+ check_CC ("ccosl", &ccosl, &ccos);
+ check_CC ("ccoshl", &ccoshl, &ccosh);
+ check_CC ("cexpl", &cexpl, &cexp);
+ check_CC ("clog10l", &clog10l, &clog10);
+ check_CC ("clogl", &clogl, &clog);
+ check_CC ("conjl", &conjl, &conj);
+ check_CC ("cprojl", &cprojl, &cproj);
+ check_CC ("csinl", &csinl, &csin);
+ check_CC ("csinhl", &csinhl, &csinh);
+ check_CC ("csqrtl", &csqrtl, &csqrt);
+ check_CC ("ctanl", &ctanl, &ctan);
+ check_CC ("ctanhl", &ctanhl, &ctanh);
+}
+
+/* Helper functions for result checking. Not implemented in libm
+ because they are trivial. */
+
+static double
+dadd (double x, double y)
+{
+ return x + y;
+}
+
+static double
+dsub (double x, double y)
+{
+ return x - y;
+}
+
+static double
+dmul (double x, double y)
+{
+ return x * y;
+}
+
+static double
+ddiv (double x, double y)
+{
+ return x / y;
+}
+
+static void
+two_argument_functions (void)
+{
+ check_DDD ("atan2l", atan2l, atan2);
+ check_DDD ("copysignl", copysignl, copysign);
+ check_DDD ("fdiml", &fdiml, &fdim);
+ check_DDD ("fmaxl", &fmaxl, &fmax);
+ check_DDD ("fmaxmagl", &fmaxmagl, &fmaxmag);
+ check_DDD ("fminl", &fminl, &fmin);
+ check_DDD ("fminmagl", &fminmagl, &fminmag);
+ check_DDD ("fmodl", &fmodl, &fmod);
+ check_DDD ("hypotl", &hypotl, &hypot);
+ check_DDD ("nextafterl", &nextafterl, &nextafter);
+ check_DDD ("powl", &powl, &pow);
+ check_DDD ("remainderl", &remainderl, &remainder);
+ check_DDD ("scalbl", &scalbl, &scalb);
+
+ check_dDD ("daddl", &daddl, &dadd);
+ check_dDD ("ddivl", &ddivl, &ddiv);
+ check_dDD ("dmull", &dmull, &dmul);
+ check_dDD ("dsubl", &dsubl, &dsub);
+
+ check_fDD ("faddl", &faddl, &fadd);
+ check_fDD ("fdivl", &fdivl, &fdiv);
+ check_fDD ("fmull", &fmull, &fmul);
+ check_fDD ("fsubl", &fsubl, &fsub);
+
+ check_DDi ("ldexpl", &ldexpl, &ldexp);
+
+ check_DiD ("jnl", &jnl, &jn);
+ check_DiD ("ynl", &ynl, &yn);
+
+ check_iDD ("totalorderl", &totalorderl, &totalorder);
+ check_iDD ("totalordermagl", &totalordermagl, &totalordermag);
+
+ check_CCC ("cpowl", &cpowl, &cpow);
+}
+
+/* Wrappers for printf-style functions. */
+
+static struct xmemstream stdout_replacement;
+static FILE *original_stdout;
+
+static void
+replace_stdout_start (void)
+{
+ TEST_VERIFY (stdout_replacement.buffer == NULL);
+ xopen_memstream (&stdout_replacement);
+ original_stdout = stdout;
+ stdout = stdout_replacement.out;
+}
+
+static void
+replace_stdout_stop (char **result)
+{
+ stdout = original_stdout;
+ xfclose_memstream (&stdout_replacement);
+ *result = stdout_replacement.buffer;
+ stdout_replacement = (struct xmemstream) { NULL };
+}
+
+static int
+printf_Dd (char **result, const char *format, ...)
+{
+ replace_stdout_start ();
+ va_list ap;
+ va_start (ap, format);
+ long double arg0 = va_arg (ap, long double);
+ double arg1 = va_arg (ap, double);
+ int ret = printf (format, arg0, arg1);
+ va_end (ap);
+ replace_stdout_stop (result);
+ return ret;
+}
+
+static int
+vprintf_Dd (char **result, const char *format, ...)
+{
+ replace_stdout_start ();
+ va_list ap;
+ va_start (ap, format);
+ int ret = vprintf (format, ap);
+ va_end (ap);
+ replace_stdout_stop (result);
+ return ret;
+}
+
+static int
+fprintf_Dd (char **result, const char *format, ...)
+{
+ replace_stdout_start ();
+ va_list ap;
+ va_start (ap, format);
+ long double arg0 = va_arg (ap, long double);
+ double arg1 = va_arg (ap, double);
+ int ret = fprintf (stdout, format, arg0, arg1);
+ va_end (ap);
+ replace_stdout_stop (result);
+ return ret;
+}
+
+static int
+vfprintf_Dd (char **result, const char *format, ...)
+{
+ replace_stdout_start ();
+ va_list ap;
+ va_start (ap, format);
+ int ret = vfprintf (stdout, format, ap);
+ va_end (ap);
+ replace_stdout_stop (result);
+ return ret;
+}
+
+static int
+sprintf_Dd (char **result, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ long double arg0 = va_arg (ap, long double);
+ double arg1 = va_arg (ap, double);
+ char buf[128];
+ int ret = sprintf (buf, format, arg0, arg1);
+ va_end (ap);
+ *result = xstrdup (buf);
+ return ret;
+}
+
+static int
+vsprintf_Dd (char **result, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ char buf[128];
+ int ret = vsprintf (buf, format, ap);
+ va_end (ap);
+ *result = xstrdup (buf);
+ return ret;
+}
+
+static int
+snprintf_Dd (char **result, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ long double arg0 = va_arg (ap, long double);
+ double arg1 = va_arg (ap, double);
+ char buf[1024];
+ int ret = snprintf (buf, sizeof (buf), format, arg0, arg1);
+ va_end (ap);
+ *result = xstrdup (buf);
+ return ret;
+}
+
+static int
+vsnprintf_Dd (char **result, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ char buf[1024];
+ int ret = vsnprintf (buf, sizeof (buf), format, ap);
+ va_end (ap);
+ *result = xstrdup (buf);
+ return ret;
+}
+
+static int
+asprintf_Dd (char **result, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ long double arg0 = va_arg (ap, long double);
+ double arg1 = va_arg (ap, double);
+ int ret = asprintf (result, format, arg0, arg1);
+ va_end (ap);
+ return ret;
+}
+
+static int
+vasprintf_Dd (char **result, const char *format, ...)
+{
+ va_list ap;
+ va_start (ap, format);
+ int ret = vasprintf (result, format, ap);
+ va_end (ap);
+ return ret;
+}
+
+struct printf_wrapper
+{
+ char name[12];
+ int (*func) (char **, const char *, ...);
+};
+
+static struct printf_wrapper printf_wrappers[] =
+ {
+ { "printf", printf_Dd },
+ { "vprintf", vprintf_Dd },
+ { "fprintf", fprintf_Dd },
+ { "vfprintf", vfprintf_Dd },
+ { "sprintf", sprintf_Dd },
+ { "vsprintf", vsprintf_Dd },
+ { "snprintf", snprintf_Dd },
+ { "vsnprintf", vsnprintf_Dd },
+ { "asprintf", asprintf_Dd },
+ { "vasprintf", vasprintf_Dd },
+ };
+
+static void
+check_printf_Dd (const char *format_D, const char *format_d)
+{
+ for (int do_negative = 0; do_negative < 2; ++do_negative)
+ for (size_t i = 0; i < array_length (double_values); ++i)
+ {
+ double value = double_values[i];
+ if (do_negative)
+ value = -value;
+
+ /* Value to detect argument list corruption. */
+ double sentinel = 1234.5;
+
+ char buf_d[1024];
+ int result_d
+ = snprintf (buf_d, sizeof (buf_d), format_d, value, sentinel);
+ TEST_VERIFY (result_d < sizeof (buf_d));
+
+ for (size_t j; j < array_length (printf_wrappers); ++j)
+ {
+ char *buf_D;
+ int result_D
+ = printf_wrappers[j].func (&buf_D, format_D, value, sentinel);
+ if (result_d != result_D || strcmp (buf_d, buf_D) != 0)
+ {
+ support_record_failure ();
+ char *quoted_format_D
+ = support_quote_blob (format_D, strlen (format_D));
+ char *quoted_d = support_quote_blob (buf_d, strlen (buf_d));
+ char *quoted_D = support_quote_blob (buf_D, strlen (buf_D));
+ printf ("error: output mismatch for %s (\"%s\"):\n"
+ " expected: \"%s\" (return value %d)\n"
+ " actual: \"%s\" (return value %d)\n",
+ printf_wrappers[j].name, quoted_format_D,
+ quoted_d, result_d, quoted_D, result_D);
+ free (quoted_D);
+ free (quoted_d);
+ free (quoted_format_D);
+ }
+ free (buf_D);
+ }
+ }
+}
+
+static void
+check_printf (void)
+{
+ check_printf_Dd ("%Lf %f", "%f %f");
+ check_printf_Dd ("%.30Lf %f", "%.30f %f");
+ check_printf_Dd ("%La %f", "%a %f");
+ check_printf_Dd ("%.30La %f", "%.30a %f");
+}
+
+static int
+do_test (void)
+{
+ init_complex_values ();
+
+ single_argument_functions ();
+ two_argument_functions ();
+ check_printf ();
+
+ /* Special cases. */
+ check_DDDD ("fmal", &fmal, &fma);
+
+/* Still not tested:
+
+ asprintf_chk
+ canonicalize
+ dprintf
+ dprintf_chk
+ fprintf
+ fprintf_chk
+ frexp
+ fromfp
+ fromfpx
+ fscanf
+ fwprintf
+ fwprintf_chk
+ fwscanf
+ getpayload
+ ilogb
+ iovfscanf
+ isoc99_fscanf
+ isoc99_fwscanf
+ isoc99_scanf
+ isoc99_sscanf
+ isoc99_swscanf
+ isoc99_vfscanf
+ isoc99_vfwscanf
+ isoc99_vscanf
+ isoc99_vsscanf
+ isoc99_vswscanf
+ isoc99_vwscanf
+ isoc99_wscanf
+ lgamma_r
+ llogb
+ llrint
+ llround
+ lrint
+ lroundl
+ modfl
+ nan
+ nexttowardfl
+ nexttowardl
+ obstack_printf
+ obstack_printf_chk
+ obstack_vprintf
+ obstack_vprintf_chk
+ printf_chk
+ printf_fp
+ printf_size
+ qecvt
+ qecvt_r
+ qfcvt
+ qfcvt_r
+ qgcvt
+ remquo
+ rint
+ scalbln
+ scalbn
+ scanf
+ setpayload
+ setpayloadsig
+ sincos
+ snprintf_chk
+ sprintf_chk
+ sscanf
+ strfmon
+ strfmon_l
+ strfroml
+ strtold
+ strtold_l
+ strtoldint
+ swprintf
+ swprintf_chk
+ swscanf
+ syslog
+ syslog_chk
+ ufromfp
+ ufromfpx
+ vasprintf_chk
+ vdprintf
+ vdprintf_chk
+ vfprintf
+ vfprintf_chk
+ vfscanf
+ vfwprintf
+ vfwprintf_chk
+ vfwscanf
+ vprintf_chk
+ vscanf
+ vsnprintf_chk
+ vsprintf_chk
+ vsscanf
+ vswprintf
+ vswprintf_chk
+ vswscanf
+ vsyslog
+ vsyslog_chk
+ vwprintf
+ vwprintf_chk
+ vwscanf
+ wcstold
+ wcstold_l
+ wcstoldint
+ wprintf
+ wprintf_chk
+ wscanf
+*/
+
+ return 0;
+}
+
+#include <support/test-driver.c>