diff options
author | Joseph Myers <joseph@codesourcery.com> | 2014-03-06 14:11:19 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2014-03-06 14:11:19 +0000 |
commit | aa97dee16e5299bf2b8f7b2d67215361c7c904e2 (patch) | |
tree | 99e45c15390bfa53325b8e8400d1ccfe8c253b40 /math/gen-auto-libm-tests.c | |
parent | 2f0a0f44274808faa6bb55dd28b9ddbda6380f2a (diff) | |
download | glibc-aa97dee16e5299bf2b8f7b2d67215361c7c904e2.tar.gz glibc-aa97dee16e5299bf2b8f7b2d67215361c7c904e2.tar.xz glibc-aa97dee16e5299bf2b8f7b2d67215361c7c904e2.zip |
Adjust how gen-auto-libm-tests handles before-rounding/after-rounding cases.
This patch changes gen-auto-libm-tests so that, when generating test results that depend on whether the architecture has before-rounding or after-rounding tininess detection, the :before-rounding or :after-rounding conditions go on the exception / errno flags generated, rather than generating two separate lines in auto-libm-test-out for e.g. flt-32:before-rounding and flt-32:after-rounding. The rationale for this is as follows. It would be desirable for testing a libm function in all rounding modes to require just one function and array in libm-test.inc, not four (or five), with the array of test data including expected results for all rounding modes rather than separate arrays for each rounding mode that also need to repeat all the test inputs. For gen-libm-test.pl to generate data for such an array from auto-libm-test-out, it would be helpful if each (format, test input) pair has exactly four lines in auto-libm-test-out, one for each rounding mode, rather than some rounding modes having just one line and some having two because the exceptions depend on tininess detection. Tested x86_64 and x86. * math/gen-auto-libm-tests.c: Update comment on output format. (output_for_one_input_case): Generate before-rounding and after-rounding information as conditions on output flags not floating-point format. * math/auto-libm-test-out: Regenerated. * math/gen-libm-test.pl (cond_value): New function. (or_cond_value): Use cond_value. (generate_testfile): Handle conditional exceptions.
Diffstat (limited to 'math/gen-auto-libm-tests.c')
-rw-r--r-- | math/gen-auto-libm-tests.c | 440 |
1 files changed, 231 insertions, 209 deletions
diff --git a/math/gen-auto-libm-tests.c b/math/gen-auto-libm-tests.c index eeec2ab6f0..61097e480c 100644 --- a/math/gen-auto-libm-tests.c +++ b/math/gen-auto-libm-tests.c @@ -104,22 +104,22 @@ ... : flags". rounding-mode is "tonearest", "towardzero", "upward" or "downward". format is a name from the floating_point_formats array, possibly followed by a sequence of ":flag" for flags from - "long32", "long64", "before-rounding" and "after-rounding" (the - last two indicating tests where expectations for underflow - exceptions depend on how the architecture detects tininess). - Inputs and outputs are specified as hex floats with the required - suffix for the floating-point type, or plus_infty or minus_infty - for infinite expected results, or as integer constant expressions - (not necessarily with the right type) or IGNORE for integer inputs - and outputs. Flags are "no-test-inline", "xfail", "<exception>", - "<exception>-ok", "errno-<value>", "errno-<value>-ok", where - "<exception>" and "errno-<value>" are unconditional, indicating - that a correct result means the given exception should be raised or - errno should be set to the given value, and other settings may be - conditional or unconditional; "-ok" means not to test for the given - exception or errno value (whether because it was marked as possibly - missing or spurious, or because the calculation of correct results - indicated it was optional). */ + "long32" and "long64". Inputs and outputs are specified as hex + floats with the required suffix for the floating-point type, or + plus_infty or minus_infty for infinite expected results, or as + integer constant expressions (not necessarily with the right type) + or IGNORE for integer inputs and outputs. Flags are + "no-test-inline", "xfail", "<exception>", "<exception>-ok", + "errno-<value>", "errno-<value>-ok", which may be unconditional or + conditional. "<exception>" indicates that a correct result means + the given exception should be raised. "errno-<value>" indicates + that a correct result means errno should be set to the given value. + "-ok" means not to test for the given exception or errno value + (whether because it was marked as possibly missing or spurious, or + because the calculation of correct results indicated it was + optional). Conditions "before-rounding" and "after-rounding" + indicate tests where expectations for underflow exceptions depend + on how the architecture detects tininess. */ #define _GNU_SOURCE @@ -1882,224 +1882,246 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, { bool before_after_matters = tf->exact && merged_exc_before[m] != merged_exc_after[m]; - for (int after = 0; after <= 1; after++) + if (before_after_matters) { - if (after == 1 && !before_after_matters) - continue; - const char *after_cond; - if (before_after_matters) - after_cond = (after - ? ":after-rounding" - : ":before-rounding"); - else - after_cond = ""; - unsigned int merged_exc = (after - ? merged_exc_after[m] - : merged_exc_before[m]); - if (fprintf (fp, "= %s %s %s%s%s", tf->name, - rounding_modes[m].name, fp_formats[f].name, - long_cond, after_cond) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", filename); - /* Print inputs. */ - for (size_t i = 0; i < tf->num_args; i++) - output_generic_value (fp, filename, &inputs[i], false, - tf->arg_types[i], f, long_bits); - if (fputs (" :", fp) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", filename); - /* Print outputs. */ - bool must_erange = false; - for (size_t i = 0; i < tf->num_ret; i++) + assert ((merged_exc_before[m] ^ merged_exc_after[m]) + == (1U << exc_underflow)); + assert ((merged_exc_before[m] & (1U << exc_underflow)) != 0); + } + unsigned int merged_exc = merged_exc_before[m]; + if (fprintf (fp, "= %s %s %s%s", tf->name, + rounding_modes[m].name, fp_formats[f].name, + long_cond) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", filename); + /* Print inputs. */ + for (size_t i = 0; i < tf->num_args; i++) + output_generic_value (fp, filename, &inputs[i], false, + tf->arg_types[i], f, long_bits); + if (fputs (" :", fp) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", filename); + /* Print outputs. */ + bool must_erange = false; + for (size_t i = 0; i < tf->num_ret; i++) + { + generic_value g; + g.type = generic_outputs[i].type; + switch (g.type) { - generic_value g; - g.type = generic_outputs[i].type; - switch (g.type) - { - case gtype_fp: - if (mpfr_inf_p (all_res[i][m]) - && (all_exc_before[i][m] - & (1U << exc_overflow)) != 0) - must_erange = true; - if (mpfr_zero_p (all_res[i][m]) - && (tf->exact - || mpfr_zero_p (all_res[i][rm_tonearest])) - && (all_exc_before[i][m] - & (1U << exc_underflow)) != 0) - must_erange = true; - mpfr_init2 (g.value.f, fp_formats[f].mant_dig); - assert_exact (mpfr_set (g.value.f, all_res[i][m], - MPFR_RNDN)); - break; + case gtype_fp: + if (mpfr_inf_p (all_res[i][m]) + && (all_exc_before[i][m] + & (1U << exc_overflow)) != 0) + must_erange = true; + if (mpfr_zero_p (all_res[i][m]) + && (tf->exact + || mpfr_zero_p (all_res[i][rm_tonearest])) + && (all_exc_before[i][m] + & (1U << exc_underflow)) != 0) + must_erange = true; + mpfr_init2 (g.value.f, fp_formats[f].mant_dig); + assert_exact (mpfr_set (g.value.f, all_res[i][m], + MPFR_RNDN)); + break; - case gtype_int: - mpz_init (g.value.i); - mpz_set (g.value.i, generic_outputs[i].value.i); - break; + case gtype_int: + mpz_init (g.value.i); + mpz_set (g.value.i, generic_outputs[i].value.i); + break; - default: - abort (); - } - output_generic_value (fp, filename, &g, ignore_output[i], - tf->ret_types[i], f, long_bits); - generic_value_free (&g); + default: + abort (); } - if (fputs (" :", fp) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", filename); - /* Print miscellaneous flags (passed through from - input). */ - for (size_t i = 0; i < it->num_flags; i++) - switch (it->flags[i].type) - { - case flag_no_test_inline: - case flag_xfail: - if (fprintf (fp, " %s%s", - input_flags[it->flags[i].type], - (it->flags[i].cond - ? it->flags[i].cond - : "")) < 0) + output_generic_value (fp, filename, &g, ignore_output[i], + tf->ret_types[i], f, long_bits); + generic_value_free (&g); + } + if (fputs (" :", fp) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", filename); + /* Print miscellaneous flags (passed through from + input). */ + for (size_t i = 0; i < it->num_flags; i++) + switch (it->flags[i].type) + { + case flag_no_test_inline: + case flag_xfail: + if (fprintf (fp, " %s%s", + input_flags[it->flags[i].type], + (it->flags[i].cond + ? it->flags[i].cond + : "")) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + break; + case flag_xfail_rounding: + if (m != rm_tonearest) + if (fprintf (fp, " xfail%s", + (it->flags[i].cond + ? it->flags[i].cond + : "")) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + break; + default: + break; + } + /* Print exception flags and compute errno + expectations where not already computed. */ + bool may_edom = false; + bool must_edom = false; + bool may_erange = must_erange || may_underflow; + for (fp_exception e = exc_first_exception; + e < exc_num_exceptions; + e++) + { + bool expect_e = (merged_exc & (1U << e)) != 0; + bool e_optional = false; + switch (e) + { + case exc_divbyzero: + if (expect_e) + may_erange = must_erange = true; + break; + + case exc_inexact: + if (!tf->exact) + e_optional = true; + break; + + case exc_invalid: + if (expect_e) + may_edom = must_edom = true; + break; + + case exc_overflow: + if (expect_e) + may_erange = true; + break; + + case exc_underflow: + if (expect_e) + may_erange = true; + if (must_underflow) + assert (expect_e); + if (may_underflow && !must_underflow) + e_optional = true; + break; + + default: + abort (); + } + if (e_optional) + { + assert (!before_after_matters); + if (fprintf (fp, " %s-ok", exceptions[e]) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + } + else + { + if (expect_e) + if (fprintf (fp, " %s", exceptions[e]) < 0) error (EXIT_FAILURE, errno, "write to '%s'", filename); - break; - case flag_xfail_rounding: - if (m != rm_tonearest) - if (fprintf (fp, " xfail%s", - (it->flags[i].cond - ? it->flags[i].cond - : "")) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", - filename); - break; - default: - break; - } - /* Print exception flags and compute errno - expectations where not already computed. */ - bool may_edom = false; - bool must_edom = false; - bool may_erange = must_erange || may_underflow; - for (fp_exception e = exc_first_exception; - e < exc_num_exceptions; - e++) - { - bool expect_e = (merged_exc & (1U << e)) != 0; - bool e_optional = false; - switch (e) - { - case exc_divbyzero: - if (expect_e) - may_erange = must_erange = true; - break; - - case exc_inexact: - if (!tf->exact) - e_optional = true; - break; - - case exc_invalid: - if (expect_e) - may_edom = must_edom = true; - break; - - case exc_overflow: - if (expect_e) - may_erange = true; - break; - - case exc_underflow: - if (expect_e) - may_erange = true; - if (must_underflow) - assert (expect_e); - if (may_underflow && !must_underflow) - e_optional = true; - break; - - default: - abort (); - } - if (e_optional) - { - if (fprintf (fp, " %s-ok", exceptions[e]) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", - filename); - } - else + if (before_after_matters && e == exc_underflow) + if (fputs (":before-rounding", fp) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + for (int after = 0; after <= 1; after++) { - if (expect_e) - if (fprintf (fp, " %s", exceptions[e]) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", - filename); + bool expect_e_here = expect_e; + if (after == 1 && (!before_after_matters + || e != exc_underflow)) + continue; + const char *after_cond; + if (before_after_matters && e == exc_underflow) + { + after_cond = (after + ? ":after-rounding" + : ":before-rounding"); + expect_e_here = !after; + } + else + after_cond = ""; input_flag_type okflag; - okflag = (expect_e + okflag = (expect_e_here ? flag_missing_first : flag_spurious_first) + e; for (size_t i = 0; i < it->num_flags; i++) if (it->flags[i].type == okflag) - if (fprintf (fp, " %s-ok%s", + if (fprintf (fp, " %s-ok%s%s", exceptions[e], (it->flags[i].cond ? it->flags[i].cond - : "")) < 0) + : ""), after_cond) < 0) error (EXIT_FAILURE, errno, "write to '%s'", filename); } } - /* Print errno expectations. */ - if (tf->complex_fn) - { - must_edom = false; - must_erange = false; - } - if (may_edom && !must_edom) - { - if (fputs (" errno-edom-ok", fp) < 0) + } + /* Print errno expectations. */ + if (tf->complex_fn) + { + must_edom = false; + must_erange = false; + } + if (may_edom && !must_edom) + { + if (fputs (" errno-edom-ok", fp) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + } + else + { + if (must_edom) + if (fputs (" errno-edom", fp) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + input_flag_type okflag = (must_edom + ? flag_missing_errno + : flag_spurious_errno); + for (size_t i = 0; i < it->num_flags; i++) + if (it->flags[i].type == okflag) + if (fprintf (fp, " errno-edom-ok%s", + (it->flags[i].cond + ? it->flags[i].cond + : "")) < 0) error (EXIT_FAILURE, errno, "write to '%s'", filename); - } - else - { - if (must_edom) - if (fputs (" errno-edom", fp) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", - filename); - input_flag_type okflag = (must_edom - ? flag_missing_errno - : flag_spurious_errno); - for (size_t i = 0; i < it->num_flags; i++) - if (it->flags[i].type == okflag) - if (fprintf (fp, " errno-edom-ok%s", - (it->flags[i].cond - ? it->flags[i].cond - : "")) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", - filename); - } - if (may_erange && !must_erange) - { - if (fputs (" errno-erange-ok", fp) < 0) + } + if (before_after_matters) + assert (may_erange && !must_erange); + if (may_erange && !must_erange) + { + if (fprintf (fp, " errno-erange-ok%s", + (before_after_matters + ? ":before-rounding" + : "")) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + } + if (before_after_matters || !(may_erange && !must_erange)) + { + if (must_erange) + if (fputs (" errno-erange", fp) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", + filename); + input_flag_type okflag = (must_erange + ? flag_missing_errno + : flag_spurious_errno); + for (size_t i = 0; i < it->num_flags; i++) + if (it->flags[i].type == okflag) + if (fprintf (fp, " errno-erange-ok%s%s", + (it->flags[i].cond + ? it->flags[i].cond + : ""), + (before_after_matters + ? ":after-rounding" + : "")) < 0) error (EXIT_FAILURE, errno, "write to '%s'", filename); - } - else - { - if (must_erange) - if (fputs (" errno-erange", fp) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", - filename); - input_flag_type okflag = (must_erange - ? flag_missing_errno - : flag_spurious_errno); - for (size_t i = 0; i < it->num_flags; i++) - if (it->flags[i].type == okflag) - if (fprintf (fp, " errno-erange-ok%s", - (it->flags[i].cond - ? it->flags[i].cond - : "")) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", - filename); - } - if (putc ('\n', fp) < 0) - error (EXIT_FAILURE, errno, "write to '%s'", filename); } + if (putc ('\n', fp) < 0) + error (EXIT_FAILURE, errno, "write to '%s'", filename); } for (size_t i = 0; i < tf->num_ret; i++) { |