diff options
author | Joseph Myers <joseph@codesourcery.com> | 2013-11-29 16:27:55 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2013-11-29 16:27:55 +0000 |
commit | ffb536d0ac914a110c160c48d01097d132e20531 (patch) | |
tree | aaf8d810651e89fa739d42791d66ce1c6df0885e /math/gen-libm-test.pl | |
parent | 97161a937370c6a20f93647b3260a7d1a87f2645 (diff) | |
download | glibc-ffb536d0ac914a110c160c48d01097d132e20531.zip glibc-ffb536d0ac914a110c160c48d01097d132e20531.tar.gz glibc-ffb536d0ac914a110c160c48d01097d132e20531.tar.bz2 |
Start generating libm tests automatically with MPFR.
Diffstat (limited to 'math/gen-libm-test.pl')
-rwxr-xr-x | math/gen-libm-test.pl | 185 |
1 files changed, 181 insertions, 4 deletions
diff --git a/math/gen-libm-test.pl b/math/gen-libm-test.pl index bd701d7..81f5fab 100755 --- a/math/gen-libm-test.pl +++ b/math/gen-libm-test.pl @@ -39,10 +39,11 @@ use Getopt::Std; use strict; -use vars qw ($input $output); +use vars qw ($input $output $auto_input); use vars qw (%results); use vars qw (%beautify @all_floats); use vars qw ($output_dir $ulps_file); +use vars qw (%auto_tests); # all_floats is sorted and contains all recognised float types @all_floats = ('double', 'float', 'idouble', @@ -51,6 +52,12 @@ use vars qw ($output_dir $ulps_file); %beautify = ( "minus_zero" => "-0", "plus_zero" => "+0", + "-0x0p+0f" => "-0", + "-0x0p+0" => "-0", + "-0x0p+0L" => "-0", + "0x0p+0f" => "+0", + "0x0p+0" => "+0", + "0x0p+0L" => "+0", "minus_infty" => "-inf", "plus_infty" => "inf", "qnan_value" => "qNaN", @@ -99,9 +106,11 @@ $ulps_file = $opt_u if ($opt_u); $output_dir = $opt_o if ($opt_o); $input = "libm-test.inc"; +$auto_input = "auto-libm-test-out"; $output = "${output_dir}libm-test.c"; &parse_ulps ($ulps_file); +&parse_auto_input ($auto_input); &generate_testfile ($input, $output) unless ($opt_n); &output_ulps ("${output_dir}libm-test-ulps.h", $ulps_file) unless ($opt_n); &print_ulps_file ("${output_dir}NewUlps") if ($opt_n); @@ -121,6 +130,9 @@ sub beautify { return '-' . $beautify{$tmp}; } } + if ($arg =~ /^-?0x[0-9a-f.]*p[-+][0-9]+f$/) { + $arg =~ s/f$//; + } if ($arg =~ /[0-9]L$/) { $arg =~ s/L$//; } @@ -218,7 +230,7 @@ sub parse_args { # consistency check if ($current_arg == $#args) { die ("wrong number of arguments") - unless ($args[$current_arg] =~ /EXCEPTION|ERRNO|IGNORE_ZERO_INF_SIGN|TEST_NAN_SIGN|NO_TEST_INLINE/); + unless ($args[$current_arg] =~ /EXCEPTION|ERRNO|IGNORE_ZERO_INF_SIGN|TEST_NAN_SIGN|NO_TEST_INLINE|XFAIL_TEST/); } elsif ($current_arg < $#args) { die ("wrong number of arguments"); } elsif ($current_arg > ($#args+1)) { @@ -309,17 +321,165 @@ sub parse_args { print $file " $cline },\n"; } +# Convert a condition from auto-libm-test-out to C form. +sub convert_condition { + my ($cond) = @_; + my (@conds, $ret); + @conds = split /:/, $cond; + foreach (@conds) { + s/-/_/g; + s/^/TEST_COND_/; + } + $ret = join " && ", @conds; + return "($ret)"; +} + +# Return text to OR a value into an accumulated flags string. +sub or_value { + my ($cond) = @_; + if ($cond eq "0") { + return ""; + } else { + return " | $cond"; + } +} + +# Return text to OR a conditional expression between two values into +# an accumulated flags string. +sub or_cond_value { + my ($cond, $if, $else) = @_; + if ($cond eq "1") { + return or_value ($if); + } elsif ($cond eq "0") { + return or_value ($else); + } else { + return or_value ("($cond ? $if : $else)"); + } +} + # Generate libm-test.c sub generate_testfile { my ($input, $output) = @_; - my ($lasttext); - my (@args, $i); open INPUT, $input or die ("Can't open $input: $!"); open OUTPUT, ">$output" or die ("Can't open $output: $!"); # Replace the special macros while (<INPUT>) { + # AUTO_TESTS (function, mode), + if (/^\s*AUTO_TESTS_/) { + my ($descr, $func, $mode, $auto_test, $num_auto_tests); + ($descr, $func, $mode) = ($_ =~ /AUTO_TESTS_(\w+)\s*\((\w+),\s*(\w+)\)/); + $num_auto_tests = 0; + foreach $auto_test (sort keys %{$auto_tests{$func}{$mode}}) { + my ($finputs, $format, $inputs, $outputs, $flags); + my ($format_conv, $flags_conv, @flags, %flag_cond); + $num_auto_tests++; + ($finputs, $outputs, $flags) = split / : */, $auto_test; + ($format, $inputs) = split / /, $finputs, 2; + $inputs =~ s/ /, /g; + $outputs =~ s/ /, /g; + $format_conv = convert_condition ($format); + print OUTPUT "#if $format_conv\n"; + @flags = split / /, $flags; + foreach (@flags) { + if (/^([^:]*):(.*)$/) { + my ($flag, $cond); + $flag = $1; + $cond = convert_condition ($2); + if (defined ($flag_cond{$flag})) { + if ($flag_cond{$flag} ne "1") { + $flag_cond{$flag} .= " || $cond"; + } + } else { + $flag_cond{$flag} = $cond; + } + } else { + $flag_cond{$_} = "1"; + } + } + $flags_conv = ""; + if (defined ($flag_cond{"no-test-inline"})) { + $flags_conv .= or_cond_value ($flag_cond{"no-test-inline"}, + "NO_TEST_INLINE", "0"); + } + if (defined ($flag_cond{"xfail"})) { + $flags_conv .= or_cond_value ($flag_cond{"xfail"}, + "XFAIL_TEST", "0"); + } + my (@exc_list) = qw(divbyzero inexact invalid overflow underflow); + my ($exc); + foreach $exc (@exc_list) { + my ($exc_expected, $exc_ok, $no_exc); + $exc_expected = "\U$exc\E_EXCEPTION"; + $exc_ok = "\U$exc\E_EXCEPTION_OK"; + $no_exc = "0"; + if ($exc eq "inexact") { + $exc_ok = "0"; + $no_exc = "NO_INEXACT_EXCEPTION"; + } + if (defined ($flag_cond{$exc})) { + if ($flag_cond{$exc} ne "1") { + die ("unexpected condition for $exc\n"); + } + if (defined ($flag_cond{"$exc-ok"})) { + $flags_conv .= or_cond_value ($flag_cond{"$exc-ok"}, + $exc_ok, $exc_expected); + } else { + $flags_conv .= or_value ($exc_expected); + } + } else { + if (defined ($flag_cond{"$exc-ok"})) { + $flags_conv .= or_cond_value ($flag_cond{"$exc-ok"}, + $exc_ok, $no_exc); + } else { + $flags_conv .= or_value ($no_exc); + } + } + } + my ($errno_expected, $errno_unknown_cond); + if (defined ($flag_cond{"errno-edom"})) { + if ($flag_cond{"errno-edom"} ne "1") { + die ("unexpected condition for errno-edom"); + } + if (defined ($flag_cond{"errno-erange"})) { + die ("multiple errno values expected"); + } + $errno_expected = "ERRNO_EDOM"; + } elsif (defined ($flag_cond{"errno-erange"})) { + if ($flag_cond{"errno-erange"} ne "1") { + die ("unexpected condition for errno-erange"); + } + $errno_expected = "ERRNO_ERANGE"; + } else { + $errno_expected = "ERRNO_UNCHANGED"; + } + if (defined ($flag_cond{"errno-edom-ok"})) { + if (defined ($flag_cond{"errno-erange-ok"}) + && $flag_cond{"errno-erange-ok"} ne $flag_cond{"errno-edom-ok"}) { + $errno_unknown_cond = "($flag_cond{\"errno-edom-ok\"} || $flag_cond{\"errno-erange-ok\"})"; + } else { + $errno_unknown_cond = $flag_cond{"errno-edom-ok"}; + } + } elsif (defined ($flag_cond{"errno-erange-ok"})) { + $errno_unknown_cond = $flag_cond{"errno-erange-ok"}; + } else { + $errno_unknown_cond = "0"; + } + $flags_conv .= or_cond_value ($errno_unknown_cond, + "0", $errno_expected); + if ($flags_conv ne "") { + $flags_conv =~ s/^ \|/,/; + } + &parse_args (\*OUTPUT, $descr, + "$func, $inputs, $outputs$flags_conv"); + print OUTPUT "#endif\n"; + } + if ($num_auto_tests == 0) { + die ("no automatic tests for $func, $mode\n"); + } + next; + } # TEST_... if (/^\s*TEST_/) { @@ -573,3 +733,20 @@ sub output_ulps { print ULP " };\n"; close ULP; } + +# Parse auto-libm-test-out. +sub parse_auto_input { + my ($file) = @_; + open AUTO, $file or die ("Can't open $file: $!"); + while (<AUTO>) { + chop; + next if !/^= /; + s/^= //; + if (/^(\S+) (\S+) (.*)$/) { + $auto_tests{$1}{$2}{$3} = 1; + } else { + die ("bad automatic test line: $_\n"); + } + } + close AUTO; +} |