From 51df539d98c5906c325f73b0436f444a86818770 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 10 May 2013 16:45:04 +0000 Subject: Start converting libm tests from code to data. --- ChangeLog | 25 +++++++++ math/gen-libm-test.pl | 101 +++++++++++++++++++++++++++-------- math/libm-test.inc | 142 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 196 insertions(+), 72 deletions(-) diff --git a/ChangeLog b/ChangeLog index e2945b24a9..a7e4b253d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2013-05-10 Joseph Myers + + * math/gen-libm-test.pl (adjust_arg): New function. + (special_functions): Handle generating output in both functions + and arrays. + (parse_args): Likewise. + (generate_testfile): Handle START_DATA and END_DATA. Pass extra + $in_func argument to parse_args. + * math/libm-test.inc (struct test_f_f_data): New type. + (IF_ROUND_INIT_): New macro. + (IF_ROUND_INIT_FE_DOWNWARD): Likewise. + (IF_ROUND_INIT_FE_TONEAREST): Likewise. + (IF_ROUND_INIT_FE_TOWARDZERO): Likewise. + (IF_ROUND_INIT_FE_UPWARD): Likewise. + (ROUND_RESTORE_): Likewise. + (ROUND_RESTORE_FE_DOWNWARD): Likewise. + (ROUND_RESTORE_FE_TONEAREST): Likewise. + (ROUND_RESTORE_FE_TOWARDZERO): Likewise. + (ROUND_RESTORE_FE_UPWARD): Likewise. + (RUN_TEST_LOOP_f_f): New macro. + (acos_test_data): New variable. + (acos_test): Run tests with RUN_TEST_LOOP_f_f. + (acos_tonearest_test_data): New variable. + (acos_test_tonearest): Run tests with RUN_TEST_LOOP_f_f. + 2013-05-10 Siddhesh Poyarekar * benchtests/bench-skeleton.c (startup): Fix coding style. diff --git a/math/gen-libm-test.pl b/math/gen-libm-test.pl index 3170b05dd6..656c9ceaff 100755 --- a/math/gen-libm-test.pl +++ b/math/gen-libm-test.pl @@ -185,10 +185,21 @@ sub new_test { return $rest; } +# Adjust an argument or expected value for use in a constant +# initializer. +sub adjust_arg { + my ($arg, $in_func) = @_; + if (!$in_func) { + $arg =~ s/(plus_zero|minus_zero|plus_infty|minus_infty|qnan_value + |max_value|min_value|min_subnorm_value)/\U$1\E_INIT/xg; + } + return $arg; +} + # Treat some functions especially. # Currently only sincos needs extra treatment. sub special_functions { - my ($file, $args) = @_; + my ($file, $in_func, $args) = @_; my (@args, $str, $test, $cline); @args = split /,\s*/, $args; @@ -196,33 +207,43 @@ sub special_functions { unless ($args[0] =~ /sincos/) { die ("Don't know how to handle $args[0] extra."); } - $cline = " RUN_TEST_sincos ($args[1]"; + if ($in_func) { + $cline = " RUN_TEST_sincos (" . adjust_arg ($args[1], $in_func); + } else { + $cline = " { " . adjust_arg ($args[1], $in_func); + } $str = 'sincos (' . &beautify ($args[1]) . ', &sin_res, &cos_res)'; # handle sin $test = $str . ' puts ' . &beautify ($args[2]) . ' in sin_res'; - $cline .= ", \"$test\", sin_res, $args[2]"; + my ($sin_res_var) = ($in_func ? ", sin_res" : ""); + $cline .= ", \"$test\"$sin_res_var, " . adjust_arg ($args[2], $in_func); $cline .= &new_test ($test, $args[4], 0); # handle cos $test = $str . ' puts ' . &beautify ($args[3]) . ' in cos_res'; - $cline .= ", \"$test\", cos_res, $args[3]"; + my ($cos_res_var) = ($in_func ? ", cos_res" : ""); + $cline .= ", \"$test\"$cos_res_var, " . adjust_arg ($args[3], $in_func); $cline .= &new_test ($test, $args[4], 1); - $cline .= ");\n"; + if ($in_func) { + $cline .= ");\n"; + } else { + $cline .= " },\n"; + } print $file $cline; } # Parse the arguments to TEST_x_y sub parse_args { - my ($file, $descr, $fct, $args) = @_; + my ($file, $descr, $fct, $in_func, $args) = @_; my (@args, $str, $descr_args, $descr_res, @descr); my ($current_arg, $cline, $i); my (@special); my ($extra_var, $call); if ($descr eq 'extra') { - &special_functions ($file, $args); + &special_functions ($file, $in_func, $args); return; } ($descr_args, $descr_res) = split /_/,$descr, 2; @@ -297,19 +318,29 @@ sub parse_args { # Reset some variables to start again $current_arg = 1; $extra_var = 0; - $cline = "RUN_TEST_$descr"; + if ($in_func) { + $cline = "RUN_TEST_$descr"; + } else { + $cline = "{ "; + } # Special handling for some macros: - if ($args[0] =~ /fpclassify|isnormal|isfinite|isinf|isnan|issignaling|signbit - |isgreater|isgreaterequal|isless|islessequal + if ($in_func && $args[0] =~ /fpclassify|isnormal|isfinite|isinf|isnan + |issignaling|signbit|isgreater|isgreaterequal|isless|islessequal |islessgreater|isunordered/x) { - $cline = "${cline}_tg"; + $cline = "${cline}_tg"; + } + if ($in_func) { + $cline .= " ("; + } + $cline .= "\"$str\""; + if ($in_func) { + $cline .= ", $args[0]"; } - $cline .= " (\"$str\", $args[0]"; @descr = split //,$descr_args; for ($i=0; $i <= $#descr; $i++) { # FLOAT, int, long int, long long int if ($descr[$i] =~ /f|i|l|L/) { - $cline .= ", $args[$current_arg]"; + $cline .= ", " . adjust_arg ($args[$current_arg], $in_func); $current_arg++; next; } @@ -319,7 +350,8 @@ sub parse_args { } # complex if ($descr[$i] eq 'c') { - $cline .= ", $args[$current_arg], $args[$current_arg+1]"; + $cline .= ", " . adjust_arg ($args[$current_arg], $in_func); + $cline .= ", " . adjust_arg ($args[$current_arg+1], $in_func); $current_arg += 2; next; } @@ -329,10 +361,11 @@ sub parse_args { @descr = split //,$descr_res; foreach (@descr) { if ($_ =~ /b|f|i|l|L/ ) { - $cline .= $args[$current_arg]; + $cline .= adjust_arg ($args[$current_arg], $in_func); $current_arg++; } elsif ($_ eq 'c') { - $cline .= "$args[$current_arg], $args[$current_arg+1]"; + $cline .= adjust_arg ($args[$current_arg], $in_func); + $cline .= ", " . adjust_arg ($args[$current_arg+1], $in_func); $current_arg += 2; } elsif ($_ eq '1') { push @special, $args[$current_arg]; @@ -348,11 +381,12 @@ sub parse_args { my ($extra_expected) = $special[0]; my ($run_extra) = ($extra_expected ne "IGNORE" ? 1 : 0); my ($str) = "$call sets x to $extra_expected"; + my ($out_var) = ($in_func ? ", x" : ""); if (!$run_extra) { $str = ""; $extra_expected = "0"; } - $cline .= ", \"$str\", x, 123456789, $run_extra, $extra_expected"; + $cline .= ", \"$str\"$out_var, 123456789, $run_extra, $extra_expected"; if ($run_extra) { $cline .= &new_test ($str, undef, 0); } else { @@ -364,11 +398,12 @@ sub parse_args { my ($extra_expected) = $special[0]; my ($run_extra) = ($extra_expected ne "IGNORE" ? 1 : 0); my ($str) = "$call sets signgam to $extra_expected"; + my ($out_var) = ($in_func ? ", signgam" : ""); if (!$run_extra) { $str = ""; $extra_expected = "0"; } - $cline .= ", \"$str\", signgam, 0, $run_extra, $extra_expected"; + $cline .= ", \"$str\"$out_var, 0, $run_extra, $extra_expected"; if ($run_extra) { $cline .= &new_test ($str, undef, 0); } else { @@ -380,11 +415,13 @@ sub parse_args { my ($extra_expected) = $special[0]; my ($run_extra) = ($extra_expected ne "IGNORE" ? 1 : 0); my ($str) = "$call sets x to $extra_expected"; + my ($out_var) = ($in_func ? ", x" : ""); if (!$run_extra) { $str = ""; $extra_expected = "0"; } - $cline .= ", \"$str\", x, 123.456789, $run_extra, $extra_expected"; + $extra_expected = adjust_arg ($extra_expected, $in_func); + $cline .= ", \"$str\"$out_var, 123.456789, $run_extra, $extra_expected"; if ($run_extra) { $cline .= &new_test ($str, undef, 0); } else { @@ -396,11 +433,12 @@ sub parse_args { my ($extra_expected) = $special[0]; my ($run_extra) = ($extra_expected ne "IGNORE" ? 1 : 0); my ($str) = "$call sets x to $extra_expected"; + my ($out_var) = ($in_func ? ", x" : ""); if (!$run_extra) { $str = ""; $extra_expected = "0"; } - $cline .= ", \"$str\", x, 123456789, $run_extra, $extra_expected"; + $cline .= ", \"$str\"$out_var, 123456789, $run_extra, $extra_expected"; if ($run_extra) { $cline .= &new_test ($str, undef, 0); } else { @@ -408,19 +446,24 @@ sub parse_args { } } } - print $file " $cline);\n"; + if ($in_func) { + print $file " $cline);\n"; + } else { + print $file " $cline },\n"; + } } # Generate libm-test.c sub generate_testfile { my ($input, $output) = @_; my ($lasttext); - my (@args, $i, $str, $thisfct); + my (@args, $i, $str, $thisfct, $in_func); open INPUT, $input or die ("Can't open $input: $!"); open OUTPUT, ">$output" or die ("Can't open $output: $!"); # Replace the special macros + $in_func = 0; while () { # TEST_... @@ -428,18 +471,30 @@ sub generate_testfile { my ($descr, $args); chop; ($descr, $args) = ($_ =~ /TEST_(\w+)\s*\((.*)\)/); - &parse_args (\*OUTPUT, $descr, $thisfct, $args); + &parse_args (\*OUTPUT, $descr, $thisfct, $in_func, $args); + next; + } + # START_DATA (function) + if (/START_DATA/) { + ($thisfct) = ($_ =~ /START_DATA\s*\((.*)\)/); + $in_func = 0; next; } # START (function) if (/START/) { ($thisfct) = ($_ =~ /START\s*\((.*)\)/); + $in_func = 1; print OUTPUT " init_max_error ();\n"; next; } + # END_DATA (function) + if (/END_DATA/) { + next; + } # END (function) if (/END/) { my ($fct, $line, $type); + $in_func = 0; if (/complex/) { s/,\s*complex\s*//; $type = 'complex'; diff --git a/math/libm-test.inc b/math/libm-test.inc index 1ff59e0f97..6b4556d368 100644 --- a/math/libm-test.inc +++ b/math/libm-test.inc @@ -863,12 +863,53 @@ check_longlong (const char *test_name, long long int computed, errno = 0; } +/* Structures for each kind of test. */ +struct test_f_f_data +{ + const char *test_name; + FLOAT arg; + FLOAT expected; + FLOAT max_ulp; + int exceptions; +}; + +/* Set the rounding mode, or restore the saved value. */ +#define IF_ROUND_INIT_ /* Empty. */ +#define IF_ROUND_INIT_FE_DOWNWARD \ + int save_round_mode = fegetround (); \ + if (fesetround (FE_DOWNWARD) == 0) +#define IF_ROUND_INIT_FE_TONEAREST \ + int save_round_mode = fegetround (); \ + if (fesetround (FE_TONEAREST) == 0) +#define IF_ROUND_INIT_FE_TOWARDZERO \ + int save_round_mode = fegetround (); \ + if (fesetround (FE_TOWARDZERO) == 0) +#define IF_ROUND_INIT_FE_UPWARD \ + int save_round_mode = fegetround (); \ + if (fesetround (FE_UPWARD) == 0) +#define ROUND_RESTORE_ /* Empty. */ +#define ROUND_RESTORE_FE_DOWNWARD \ + fesetround (save_round_mode) +#define ROUND_RESTORE_FE_TONEAREST \ + fesetround (save_round_mode) +#define ROUND_RESTORE_FE_TOWARDZERO \ + fesetround (save_round_mode) +#define ROUND_RESTORE_FE_UPWARD \ + fesetround (save_round_mode) + /* Run an individual test, including any required setup and checking - of results. */ + of results, or loop over all tests in an array. */ #define RUN_TEST_f_f(TEST_NAME, FUNC_NAME, ARG, EXPECTED, \ MAX_ULP, EXCEPTIONS) \ check_float (TEST_NAME, FUNC (FUNC_NAME) (ARG), EXPECTED, \ MAX_ULP, EXCEPTIONS) +#define RUN_TEST_LOOP_f_f(FUNC_NAME, ARRAY, ROUNDING_MODE) \ + IF_ROUND_INIT_ ## ROUNDING_MODE \ + for (size_t i = 0; i < sizeof (ARRAY) / sizeof (ARRAY)[0]; i++) \ + RUN_TEST_f_f ((ARRAY)[i].test_name, FUNC_NAME, (ARRAY)[i].arg, \ + (ARRAY)[i].expected, (ARRAY)[i].max_ulp, \ + (ARRAY)[i].exceptions); \ + ROUND_RESTORE_ ## ROUNDING_MODE #define RUN_TEST_2_f(TEST_NAME, FUNC_NAME, ARG1, ARG2, EXPECTED, \ MAX_ULP, EXCEPTIONS) \ check_float (TEST_NAME, FUNC (FUNC_NAME) (ARG1, ARG2), EXPECTED, \ @@ -1012,6 +1053,43 @@ matherr (struct exception *x __attribute__ ((unused))) Please keep them alphabetically sorted! ****************************************************************************/ +static const struct test_f_f_data acos_test_data[] = + { + START_DATA (acos), + TEST_f_f (acos, plus_infty, qnan_value, INVALID_EXCEPTION), + TEST_f_f (acos, minus_infty, qnan_value, INVALID_EXCEPTION), + TEST_f_f (acos, qnan_value, qnan_value), + + /* |x| > 1: */ + TEST_f_f (acos, 1.125L, qnan_value, INVALID_EXCEPTION), + TEST_f_f (acos, -1.125L, qnan_value, INVALID_EXCEPTION), + TEST_f_f (acos, max_value, qnan_value, INVALID_EXCEPTION), + TEST_f_f (acos, -max_value, qnan_value, INVALID_EXCEPTION), + + TEST_f_f (acos, 0, M_PI_2l), + TEST_f_f (acos, minus_zero, M_PI_2l), + TEST_f_f (acos, 1, 0), + TEST_f_f (acos, -1, M_PIl), + TEST_f_f (acos, 0.5, M_PI_6l*2.0), + TEST_f_f (acos, -0.5, M_PI_6l*4.0), + TEST_f_f (acos, 0.75L, 0.722734247813415611178377352641333362L), + TEST_f_f (acos, 2e-17L, 1.57079632679489659923132169163975144L), + TEST_f_f (acos, 0.0625L, 1.50825556499840522843072005474337068L), + TEST_f_f (acos, 0x0.ffffffp0L, 3.4526698471620358760324948263873649728491e-4L), + TEST_f_f (acos, -0x0.ffffffp0L, 3.1412473866050770348750401337968641476999L), +#ifndef TEST_FLOAT + TEST_f_f (acos, 0x0.ffffffff8p0L, 1.5258789062648029736620564947844627548516e-5L), + TEST_f_f (acos, -0x0.ffffffff8p0L, 3.1415773948007305904329067627145550395696L), + TEST_f_f (acos, 0x0.ffffffffffffp0L, 8.4293697021788088529885473244391795127130e-8L), + TEST_f_f (acos, -0x0.ffffffffffffp0L, 3.1415925692960962166745548533940296398054L), +#endif +#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64 + TEST_f_f (acos, 0x0.ffffffffffffffffp0L, 3.2927225399135962333718255320079907245059e-10L), + TEST_f_f (acos, -0x0.ffffffffffffffffp0L, 3.1415926532605209844712837599423203309964L), +#endif + END_DATA (acos) + }; + static void acos_test (void) { @@ -1022,46 +1100,26 @@ acos_test (void) return; START (acos); - - TEST_f_f (acos, plus_infty, qnan_value, INVALID_EXCEPTION); - TEST_f_f (acos, minus_infty, qnan_value, INVALID_EXCEPTION); - TEST_f_f (acos, qnan_value, qnan_value); - - /* |x| > 1: */ - TEST_f_f (acos, 1.125L, qnan_value, INVALID_EXCEPTION); - TEST_f_f (acos, -1.125L, qnan_value, INVALID_EXCEPTION); - TEST_f_f (acos, max_value, qnan_value, INVALID_EXCEPTION); - TEST_f_f (acos, -max_value, qnan_value, INVALID_EXCEPTION); - - TEST_f_f (acos, 0, M_PI_2l); - TEST_f_f (acos, minus_zero, M_PI_2l); - TEST_f_f (acos, 1, 0); - TEST_f_f (acos, -1, M_PIl); - TEST_f_f (acos, 0.5, M_PI_6l*2.0); - TEST_f_f (acos, -0.5, M_PI_6l*4.0); - TEST_f_f (acos, 0.75L, 0.722734247813415611178377352641333362L); - TEST_f_f (acos, 2e-17L, 1.57079632679489659923132169163975144L); - TEST_f_f (acos, 0.0625L, 1.50825556499840522843072005474337068L); - TEST_f_f (acos, 0x0.ffffffp0L, 3.4526698471620358760324948263873649728491e-4L); - TEST_f_f (acos, -0x0.ffffffp0L, 3.1412473866050770348750401337968641476999L); -#ifndef TEST_FLOAT - TEST_f_f (acos, 0x0.ffffffff8p0L, 1.5258789062648029736620564947844627548516e-5L); - TEST_f_f (acos, -0x0.ffffffff8p0L, 3.1415773948007305904329067627145550395696L); - TEST_f_f (acos, 0x0.ffffffffffffp0L, 8.4293697021788088529885473244391795127130e-8L); - TEST_f_f (acos, -0x0.ffffffffffffp0L, 3.1415925692960962166745548533940296398054L); -#endif -#if defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64 - TEST_f_f (acos, 0x0.ffffffffffffffffp0L, 3.2927225399135962333718255320079907245059e-10L); - TEST_f_f (acos, -0x0.ffffffffffffffffp0L, 3.1415926532605209844712837599423203309964L); -#endif + RUN_TEST_LOOP_f_f (acos, acos_test_data, ); END (acos); } +static const struct test_f_f_data acos_tonearest_test_data[] = + { + START_DATA (acos_tonearest), + TEST_f_f (acos, 0, M_PI_2l), + TEST_f_f (acos, minus_zero, M_PI_2l), + TEST_f_f (acos, 1, 0), + TEST_f_f (acos, -1, M_PIl), + TEST_f_f (acos, 0.5, M_PI_6l*2.0), + TEST_f_f (acos, -0.5, M_PI_6l*4.0), + END_DATA (acos_tonearest) + }; + static void acos_test_tonearest (void) { - int save_round_mode; errno = 0; FUNC(acos) (0); if (errno == ENOSYS) @@ -1069,21 +1127,7 @@ acos_test_tonearest (void) return; START (acos_tonearest); - - save_round_mode = fegetround (); - - if (!fesetround (FE_TONEAREST)) - { - TEST_f_f (acos, 0, M_PI_2l); - TEST_f_f (acos, minus_zero, M_PI_2l); - TEST_f_f (acos, 1, 0); - TEST_f_f (acos, -1, M_PIl); - TEST_f_f (acos, 0.5, M_PI_6l*2.0); - TEST_f_f (acos, -0.5, M_PI_6l*4.0); - } - - fesetround (save_round_mode); - + RUN_TEST_LOOP_f_f (acos, acos_tonearest_test_data, FE_TONEAREST); END (acos_tonearest); } -- cgit 1.4.1