From patchwork Mon Jul 2 15:11:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 28191 Received: (qmail 84926 invoked by alias); 2 Jul 2018 15:11:49 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 84905 invoked by uid 89); 2 Jul 2018 15:11:48 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=Switch, 30a, Still, erf X-HELO: mx1.redhat.com To: GNU C Library From: Florian Weimer Subject: RFC: Testing different long double formats Message-ID: <7a7a6812-d24b-2018-b875-d85cbccb8eed@redhat.com> Date: Mon, 2 Jul 2018 17:11:40 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0 MIME-Version: 1.0 The attached patch attempts to cover the -mlong-double-64 case. Is this a direction in which we want to move? The new test compares the 64-bit long double implementation against the double implementation on a few arbitrary test values, assuming that discrepancy due to incorrect redirection would show up very quickly. The test needs Jakub's patch add: I've tested this on ppc64 only so far. Thanks, Florian Subject: [PATCH] math: Add test-nldbl To: libc-alpha@sourceware.org 2018-07-02 Florian Weimer * 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. diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile index ef790adc77..1a9227bf0a 100644 --- a/sysdeps/ieee754/ldbl-opt/Makefile +++ b/sysdeps/ieee754/ldbl-opt/Makefile @@ -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 diff --git a/sysdeps/ieee754/ldbl-opt/test-nldbl-check1.c b/sysdeps/ieee754/ldbl-opt/test-nldbl-check1.c new file mode 100644 index 0000000000..3765e93df3 --- /dev/null +++ b/sysdeps/ieee754/ldbl-opt/test-nldbl-check1.c @@ -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 + . */ + +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 diff --git a/sysdeps/ieee754/ldbl-opt/test-nldbl-check2.c b/sysdeps/ieee754/ldbl-opt/test-nldbl-check2.c new file mode 100644 index 0000000000..4dd63c5211 --- /dev/null +++ b/sysdeps/ieee754/ldbl-opt/test-nldbl-check2.c @@ -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 + . */ + +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 diff --git a/sysdeps/ieee754/ldbl-opt/test-nldbl-check3.c b/sysdeps/ieee754/ldbl-opt/test-nldbl-check3.c new file mode 100644 index 0000000000..eac9fdd543 --- /dev/null +++ b/sysdeps/ieee754/ldbl-opt/test-nldbl-check3.c @@ -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 + . */ + +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 diff --git a/sysdeps/ieee754/ldbl-opt/test-nldbl.c b/sysdeps/ieee754/ldbl-opt/test-nldbl.c new file mode 100644 index 0000000000..7cb507a716 --- /dev/null +++ b/sysdeps/ieee754/ldbl-opt/test-nldbl.c @@ -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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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