packaging: add 64bit libs on 32bit build env
[platform/upstream/linaro-glibc.git] / math / gen-libm-test.pl
1 #!/usr/bin/perl -w
2 # Copyright (C) 1999-2014 Free Software Foundation, Inc.
3 # This file is part of the GNU C Library.
4 # Contributed by Andreas Jaeger <aj@suse.de>, 1999.
5
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
10
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <http://www.gnu.org/licenses/>.
19
20 # This file needs to be tidied up
21 # Note that functions and tests share the same namespace.
22
23 # Information about tests are stored in: %results
24 # $results{$test}{"type"} is the result type, e.g. normal or complex.
25 # $results{$test}{"has_ulps"} is set if deltas exist.
26 # In the following description $type and $float are:
27 # - $type is either "normal", "real" (for the real part of a complex number)
28 #   or "imag" (for the imaginary part # of a complex number).
29 # - $float is either of float, ifloat, double, idouble, ldouble, ildouble;
30 #   It represents the underlying floating point type (float, double or long
31 #   double) and if inline functions (the leading i stands for inline)
32 #   are used.
33 # $results{$test}{$type}{"ulp"}{$float} is defined and has a delta as value
34
35
36 use Getopt::Std;
37
38 use strict;
39
40 use vars qw ($input $output $auto_input);
41 use vars qw (%results);
42 use vars qw (%beautify @all_floats);
43 use vars qw ($output_dir $ulps_file $srcdir);
44 use vars qw (%auto_tests);
45
46 # all_floats is sorted and contains all recognised float types
47 @all_floats = ('double', 'float', 'idouble',
48                'ifloat', 'ildouble', 'ldouble');
49
50 %beautify =
51   ( "minus_zero" => "-0",
52     "plus_zero" => "+0",
53     "-0x0p+0f" => "-0",
54     "-0x0p+0" => "-0",
55     "-0x0p+0L" => "-0",
56     "0x0p+0f" => "+0",
57     "0x0p+0" => "+0",
58     "0x0p+0L" => "+0",
59     "minus_infty" => "-inf",
60     "plus_infty" => "inf",
61     "qnan_value" => "qNaN",
62   );
63
64
65 # get Options
66 # Options:
67 # u: ulps-file
68 # h: help
69 # o: output-directory
70 # n: generate new ulps file
71 use vars qw($opt_u $opt_h $opt_o $opt_n);
72 getopts('u:o:nh');
73
74 $ulps_file = 'libm-test-ulps';
75 $output_dir = '';
76 ($srcdir = $0) =~ s{[^/]*$}{};
77
78 if ($opt_h) {
79   print "Usage: gen-libm-test.pl [OPTIONS]\n";
80   print " -h         print this help, then exit\n";
81   print " -o DIR     directory where generated files will be placed\n";
82   print " -n         only generate sorted file NewUlps from libm-test-ulps\n";
83   print " -u FILE    input file with ulps\n";
84   exit 0;
85 }
86
87 $ulps_file = $opt_u if ($opt_u);
88 $output_dir = $opt_o if ($opt_o);
89
90 $input = "libm-test.inc";
91 $auto_input = "${srcdir}auto-libm-test-out";
92 $output = "${output_dir}libm-test.c";
93
94 &parse_ulps ($ulps_file);
95 &parse_auto_input ($auto_input);
96 &generate_testfile ($input, $output) unless ($opt_n);
97 &output_ulps ("${output_dir}libm-test-ulps.h", $ulps_file) unless ($opt_n);
98 &print_ulps_file ("${output_dir}NewUlps") if ($opt_n);
99
100 # Return a nicer representation
101 sub beautify {
102   my ($arg) = @_;
103   my ($tmp);
104
105   if (exists $beautify{$arg}) {
106     return $beautify{$arg};
107   }
108   if ($arg =~ /^-/) {
109     $tmp = $arg;
110     $tmp =~ s/^-//;
111     if (exists $beautify{$tmp}) {
112       return '-' . $beautify{$tmp};
113     }
114   }
115   if ($arg =~ /^-?0x[0-9a-f.]*p[-+][0-9]+f$/) {
116     $arg =~ s/f$//;
117   }
118   if ($arg =~ /[0-9]L$/) {
119     $arg =~ s/L$//;
120   }
121   return $arg;
122 }
123
124 # Return a nicer representation of a complex number
125 sub build_complex_beautify {
126   my ($r, $i) = @_;
127   my ($str1, $str2);
128
129   $str1 = &beautify ($r);
130   $str2 = &beautify ($i);
131   if ($str2 =~ /^-/) {
132     $str2 =~ s/^-//;
133     $str1 .= ' - ' . $str2;
134   } else {
135     $str1 .= ' + ' . $str2;
136   }
137   $str1 .= ' i';
138   return $str1;
139 }
140
141 # Return the text to put in an initializer for a test's exception
142 # information.
143 sub show_exceptions {
144   my ($ignore_result, $exception) = @_;
145   $ignore_result = ($ignore_result ? "IGNORE_RESULT|" : "");
146   if (defined $exception) {
147     return ", ${ignore_result}$exception";
148   } else {
149     return ", ${ignore_result}0";
150   }
151 }
152
153 # Parse the arguments to TEST_x_y
154 sub parse_args {
155   my ($file, $descr, $args) = @_;
156   my (@args, $descr_args, $descr_res, @descr);
157   my ($current_arg, $cline, $cline_res, $i);
158   my (@special);
159   my ($call_args);
160   my ($ignore_result_any, $ignore_result_all);
161   my ($num_res, @args_res, @start_rm, $rm);
162   my (@plus_oflow, @minus_oflow, @plus_uflow, @minus_uflow);
163   my (@errno_plus_oflow, @errno_minus_oflow);
164   my (@errno_plus_uflow, @errno_minus_uflow);
165
166   ($descr_args, $descr_res) = split /_/,$descr, 2;
167
168   @args = split /,\s*/, $args;
169
170   $call_args = "";
171
172   # Generate first the string that's shown to the user
173   $current_arg = 1;
174   @descr = split //,$descr_args;
175   for ($i = 0; $i <= $#descr; $i++) {
176     my $comma = "";
177     if ($current_arg > 1) {
178       $comma = ', ';
179     }
180     # FLOAT, int, long int, long long int
181     if ($descr[$i] =~ /f|i|l|L/) {
182       $call_args .= $comma . &beautify ($args[$current_arg]);
183       ++$current_arg;
184       next;
185     }
186     # &FLOAT, &int - simplify call by not showing argument.
187     if ($descr[$i] =~ /F|I/) {
188       next;
189     }
190     # complex
191     if ($descr[$i] eq 'c') {
192       $call_args .= $comma . &build_complex_beautify ($args[$current_arg], $args[$current_arg+1]);
193       $current_arg += 2;
194       next;
195     }
196
197     die ("$descr[$i] is unknown");
198   }
199
200   # Result
201   @args_res = @args[$current_arg .. $#args];
202   $num_res = 0;
203   @descr = split //,$descr_res;
204   foreach (@descr) {
205     if ($_ =~ /f|i|l|L/) {
206       ++$num_res;
207     } elsif ($_ eq 'c') {
208       $num_res += 2;
209     } elsif ($_ eq 'b') {
210       # boolean
211       ++$num_res;
212     } elsif ($_ eq '1') {
213       ++$num_res;
214     } else {
215       die ("$_ is unknown");
216     }
217   }
218   # consistency check
219   if ($#args_res == $num_res - 1) {
220     # One set of results for all rounding modes, no flags.
221     @start_rm = ( 0, 0, 0, 0 );
222   } elsif ($#args_res == $num_res) {
223     # One set of results for all rounding modes, with flags.
224     die ("wrong number of arguments")
225       unless ($args_res[$#args_res] =~ /EXCEPTION|ERRNO|IGNORE_ZERO_INF_SIGN|TEST_NAN_SIGN|NO_TEST_INLINE|XFAIL_TEST/);
226     @start_rm = ( 0, 0, 0, 0 );
227   } elsif ($#args_res == 4 * $num_res + 3) {
228     # One set of results per rounding mode, with flags.
229     @start_rm = ( 0, $num_res + 1, 2 * $num_res + 2, 3 * $num_res + 3 );
230   } else {
231     die ("wrong number of arguments");
232   }
233
234   # Put the C program line together
235   # Reset some variables to start again
236   $current_arg = 1;
237   $cline = "{ \"$call_args\"";
238   @descr = split //,$descr_args;
239   for ($i=0; $i <= $#descr; $i++) {
240     # FLOAT, int, long int, long long int
241     if ($descr[$i] =~ /f|i|l|L/) {
242       $cline .= ", $args[$current_arg]";
243       $current_arg++;
244       next;
245     }
246     # &FLOAT, &int
247     if ($descr[$i] =~ /F|I/) {
248       next;
249     }
250     # complex
251     if ($descr[$i] eq 'c') {
252       $cline .= ", $args[$current_arg], $args[$current_arg+1]";
253       $current_arg += 2;
254       next;
255     }
256   }
257
258   @descr = split //,$descr_res;
259   @plus_oflow = qw(max_value plus_infty max_value plus_infty);
260   @minus_oflow = qw(minus_infty minus_infty -max_value -max_value);
261   @plus_uflow = qw(plus_zero plus_zero plus_zero min_subnorm_value);
262   @minus_uflow = qw(-min_subnorm_value minus_zero minus_zero minus_zero);
263   @errno_plus_oflow = qw(0 ERRNO_ERANGE 0 ERRNO_ERANGE);
264   @errno_minus_oflow = qw(ERRNO_ERANGE ERRNO_ERANGE 0 0);
265   @errno_plus_uflow = qw(ERRNO_ERANGE ERRNO_ERANGE ERRNO_ERANGE 0);
266   @errno_minus_uflow = qw(0 ERRNO_ERANGE ERRNO_ERANGE ERRNO_ERANGE);
267   for ($rm = 0; $rm <= 3; $rm++) {
268     $current_arg = $start_rm[$rm];
269     $ignore_result_any = 0;
270     $ignore_result_all = 1;
271     $cline_res = "";
272     @special = ();
273     foreach (@descr) {
274       if ($_ =~ /b|f|i|l|L/ ) {
275         my ($result) = $args_res[$current_arg];
276         if ($result eq "IGNORE") {
277           $ignore_result_any = 1;
278           $result = "0";
279         } else {
280           $ignore_result_all = 0;
281         }
282         $cline_res .= ", $result";
283         $current_arg++;
284       } elsif ($_ eq 'c') {
285         my ($result1) = $args_res[$current_arg];
286         if ($result1 eq "IGNORE") {
287           $ignore_result_any = 1;
288           $result1 = "0";
289         } else {
290           $ignore_result_all = 0;
291         }
292         my ($result2) = $args_res[$current_arg + 1];
293         if ($result2 eq "IGNORE") {
294           $ignore_result_any = 1;
295           $result2 = "0";
296         } else {
297           $ignore_result_all = 0;
298         }
299         $cline_res .= ", $result1, $result2";
300         $current_arg += 2;
301       } elsif ($_ eq '1') {
302         push @special, $args_res[$current_arg];
303         ++$current_arg;
304       }
305     }
306     if ($ignore_result_any && !$ignore_result_all) {
307       die ("some but not all function results ignored\n");
308     }
309     # Add exceptions.
310     $cline_res .= show_exceptions ($ignore_result_any,
311                                    ($current_arg <= $#args_res)
312                                    ? $args_res[$current_arg]
313                                    : undef);
314
315     # special treatment for some functions
316     $i = 0;
317     foreach (@special) {
318       ++$i;
319       my ($extra_expected) = $_;
320       my ($run_extra) = ($extra_expected ne "IGNORE" ? 1 : 0);
321       if (!$run_extra) {
322         $extra_expected = "0";
323       }
324       $cline_res .= ", $run_extra, $extra_expected";
325     }
326     $cline_res =~ s/^, //;
327     $cline_res =~ s/plus_oflow/$plus_oflow[$rm]/g;
328     $cline_res =~ s/minus_oflow/$minus_oflow[$rm]/g;
329     $cline_res =~ s/plus_uflow/$plus_uflow[$rm]/g;
330     $cline_res =~ s/minus_uflow/$minus_uflow[$rm]/g;
331     $cline_res =~ s/ERRNO_PLUS_OFLOW/$errno_plus_oflow[$rm]/g;
332     $cline_res =~ s/ERRNO_MINUS_OFLOW/$errno_minus_oflow[$rm]/g;
333     $cline_res =~ s/ERRNO_PLUS_UFLOW/$errno_plus_uflow[$rm]/g;
334     $cline_res =~ s/ERRNO_MINUS_UFLOW/$errno_minus_uflow[$rm]/g;
335     $cline .= ", { $cline_res }";
336   }
337   print $file "    $cline },\n";
338 }
339
340 # Convert a condition from auto-libm-test-out to C form.
341 sub convert_condition {
342   my ($cond) = @_;
343   my (@conds, $ret);
344   @conds = split /:/, $cond;
345   foreach (@conds) {
346     s/-/_/g;
347     s/^/TEST_COND_/;
348   }
349   $ret = join " && ", @conds;
350   return "($ret)";
351 }
352
353 # Return text to OR a value into an accumulated flags string.
354 sub or_value {
355   my ($cond) = @_;
356   if ($cond eq "0") {
357     return "";
358   } else {
359     return " | $cond";
360   }
361 }
362
363 # Return a conditional expression between two values.
364 sub cond_value {
365   my ($cond, $if, $else) = @_;
366   if ($cond eq "1") {
367     return $if;
368   } elsif ($cond eq "0") {
369     return $else;
370   } else {
371     return "($cond ? $if : $else)";
372   }
373 }
374
375 # Return text to OR a conditional expression between two values into
376 # an accumulated flags string.
377 sub or_cond_value {
378   my ($cond, $if, $else) = @_;
379   return or_value (cond_value ($cond, $if, $else));
380 }
381
382 # Generate libm-test.c
383 sub generate_testfile {
384   my ($input, $output) = @_;
385
386   open INPUT, $input or die ("Can't open $input: $!");
387   open OUTPUT, ">$output" or die ("Can't open $output: $!");
388
389   # Replace the special macros
390   while (<INPUT>) {
391     # AUTO_TESTS (function),
392     if (/^\s*AUTO_TESTS_/) {
393       my ($descr, $func, @modes, $auto_test, $num_auto_tests);
394       my (@rm_tests, $rm, $i);
395       @modes = qw(downward tonearest towardzero upward);
396       ($descr, $func) = ($_ =~ /AUTO_TESTS_(\w+)\s*\((\w+)\)/);
397       for ($rm = 0; $rm <= 3; $rm++) {
398         $rm_tests[$rm] = [sort keys %{$auto_tests{$func}{$modes[$rm]}}];
399       }
400       $num_auto_tests = scalar @{$rm_tests[0]};
401       for ($rm = 1; $rm <= 3; $rm++) {
402         if ($num_auto_tests != scalar @{$rm_tests[$rm]}) {
403           die ("inconsistent numbers of tests for $func\n");
404         }
405         for ($i = 0; $i < $num_auto_tests; $i++) {
406           if ($rm_tests[0][$i] ne $rm_tests[$rm][$i]) {
407             die ("inconsistent list of tests of $func\n");
408           }
409         }
410       }
411       if ($num_auto_tests == 0) {
412         die ("no automatic tests for $func\n");
413       }
414       foreach $auto_test (@{$rm_tests[0]}) {
415         my ($format, $inputs, $format_conv, $args_str);
416         ($format, $inputs) = split / /, $auto_test, 2;
417         $inputs =~ s/ /, /g;
418         $format_conv = convert_condition ($format);
419         print OUTPUT "#if $format_conv\n";
420         $args_str = "$func, $inputs";
421         for ($rm = 0; $rm <= 3; $rm++) {
422           my ($auto_test_out, $outputs, $flags);
423           my ($flags_conv, @flags, %flag_cond);
424           $auto_test_out = $auto_tests{$func}{$modes[$rm]}{$auto_test};
425           ($outputs, $flags) = split / : */, $auto_test_out;
426           $outputs =~ s/ /, /g;
427           @flags = split / /, $flags;
428           foreach (@flags) {
429             if (/^([^:]*):(.*)$/) {
430               my ($flag, $cond);
431               $flag = $1;
432               $cond = convert_condition ($2);
433               if (defined ($flag_cond{$flag})) {
434                 if ($flag_cond{$flag} ne "1") {
435                   $flag_cond{$flag} .= " || $cond";
436                 }
437               } else {
438                 $flag_cond{$flag} = $cond;
439               }
440             } else {
441               $flag_cond{$_} = "1";
442             }
443           }
444           $flags_conv = "";
445           if (defined ($flag_cond{"ignore-zero-inf-sign"})) {
446             $flags_conv .= or_cond_value ($flag_cond{"ignore-zero-inf-sign"},
447                                           "IGNORE_ZERO_INF_SIGN", "0");
448           }
449           if (defined ($flag_cond{"no-test-inline"})) {
450             $flags_conv .= or_cond_value ($flag_cond{"no-test-inline"},
451                                           "NO_TEST_INLINE", "0");
452           }
453           if (defined ($flag_cond{"xfail"})) {
454             $flags_conv .= or_cond_value ($flag_cond{"xfail"},
455                                           "XFAIL_TEST", "0");
456           }
457           my (@exc_list) = qw(divbyzero inexact invalid overflow underflow);
458           my ($exc);
459           foreach $exc (@exc_list) {
460             my ($exc_expected, $exc_ok, $no_exc, $exc_cond, $exc_ok_cond);
461             $exc_expected = "\U$exc\E_EXCEPTION";
462             $exc_ok = "\U$exc\E_EXCEPTION_OK";
463             $no_exc = "0";
464             if ($exc eq "inexact") {
465               $exc_ok = "0";
466               $no_exc = "NO_INEXACT_EXCEPTION";
467             }
468             if (defined ($flag_cond{$exc})) {
469               $exc_cond = $flag_cond{$exc};
470             } else {
471               $exc_cond = "0";
472             }
473             if (defined ($flag_cond{"$exc-ok"})) {
474               $exc_ok_cond = $flag_cond{"$exc-ok"};
475             } else {
476               $exc_ok_cond = "0";
477             }
478             $flags_conv .= or_cond_value ($exc_cond,
479                                           cond_value ($exc_ok_cond,
480                                                       $exc_ok, $exc_expected),
481                                           cond_value ($exc_ok_cond,
482                                                       $exc_ok, $no_exc));
483           }
484           my ($errno_expected, $errno_unknown_cond);
485           if (defined ($flag_cond{"errno-edom"})) {
486             if ($flag_cond{"errno-edom"} ne "1") {
487               die ("unexpected condition for errno-edom");
488             }
489             if (defined ($flag_cond{"errno-erange"})) {
490               die ("multiple errno values expected");
491             }
492             $errno_expected = "ERRNO_EDOM";
493           } elsif (defined ($flag_cond{"errno-erange"})) {
494             if ($flag_cond{"errno-erange"} ne "1") {
495               die ("unexpected condition for errno-erange");
496             }
497             $errno_expected = "ERRNO_ERANGE";
498           } else {
499             $errno_expected = "ERRNO_UNCHANGED";
500           }
501           if (defined ($flag_cond{"errno-edom-ok"})) {
502             if (defined ($flag_cond{"errno-erange-ok"})
503                 && ($flag_cond{"errno-erange-ok"}
504                     ne $flag_cond{"errno-edom-ok"})) {
505               $errno_unknown_cond = "($flag_cond{\"errno-edom-ok\"} || $flag_cond{\"errno-erange-ok\"})";
506             } else {
507               $errno_unknown_cond = $flag_cond{"errno-edom-ok"};
508             }
509           } elsif (defined ($flag_cond{"errno-erange-ok"})) {
510             $errno_unknown_cond = $flag_cond{"errno-erange-ok"};
511           } else {
512             $errno_unknown_cond = "0";
513           }
514           $flags_conv .= or_cond_value ($errno_unknown_cond,
515                                         "0", $errno_expected);
516           if ($flags_conv eq "") {
517             $flags_conv = ", NO_EXCEPTION";
518           } else {
519             $flags_conv =~ s/^ \|/,/;
520           }
521           $args_str .= ", $outputs$flags_conv";
522         }
523         &parse_args (\*OUTPUT, $descr, $args_str);
524         print OUTPUT "#endif\n";
525       }
526       next;
527     }
528
529     # TEST_...
530     if (/^\s*TEST_/) {
531       my ($descr, $args);
532       chop;
533       ($descr, $args) = ($_ =~ /TEST_(\w+)\s*\((.*)\)/);
534       &parse_args (\*OUTPUT, $descr, $args);
535       next;
536     }
537     print OUTPUT;
538   }
539   close INPUT;
540   close OUTPUT;
541 }
542
543
544
545 # Parse ulps file
546 sub parse_ulps {
547   my ($file) = @_;
548   my ($test, $type, $float, $eps);
549
550   # $type has the following values:
551   # "normal": No complex variable
552   # "real": Real part of complex result
553   # "imag": Imaginary part of complex result
554   open ULP, $file  or die ("Can't open $file: $!");
555   while (<ULP>) {
556     chop;
557     # ignore comments and empty lines
558     next if /^#/;
559     next if /^\s*$/;
560     if (/^Function: /) {
561       if (/Real part of/) {
562         s/Real part of //;
563         $type = 'real';
564       } elsif (/Imaginary part of/) {
565         s/Imaginary part of //;
566         $type = 'imag';
567       } else {
568         $type = 'normal';
569       }
570       ($test) = ($_ =~ /^Function:\s*\"([a-zA-Z0-9_]+)\"/);
571       next;
572     }
573     if (/^i?(float|double|ldouble):/) {
574       ($float, $eps) = split /\s*:\s*/,$_,2;
575
576       if ($eps eq "0") {
577         # ignore
578         next;
579       } else {
580         $results{$test}{$type}{'ulp'}{$float} = $eps;
581         $results{$test}{'has_ulps'} = 1;
582       }
583       if ($type =~ /^real|imag$/) {
584         $results{$test}{'type'} = 'complex';
585       } elsif ($type eq 'normal') {
586         $results{$test}{'type'} = 'normal';
587       }
588       next;
589     }
590     print "Skipping unknown entry: `$_'\n";
591   }
592   close ULP;
593 }
594
595
596 # Clean up a floating point number
597 sub clean_up_number {
598   my ($number) = @_;
599
600   # Remove trailing zeros after the decimal point
601   if ($number =~ /\./) {
602     $number =~ s/0+$//;
603     $number =~ s/\.$//;
604   }
605   return $number;
606 }
607
608 # Output a file which can be read in as ulps file.
609 sub print_ulps_file {
610   my ($file) = @_;
611   my ($test, $type, $float, $eps, $fct, $last_fct);
612
613   $last_fct = '';
614   open NEWULP, ">$file" or die ("Can't open $file: $!");
615   print NEWULP "# Begin of automatic generation\n";
616   print NEWULP "\n# Maximal error of functions:\n";
617
618   foreach $fct (sort keys %results) {
619     foreach $type ('real', 'imag', 'normal') {
620       if (exists $results{$fct}{$type}) {
621         if ($type eq 'normal') {
622           print NEWULP "Function: \"$fct\":\n";
623         } elsif ($type eq 'real') {
624           print NEWULP "Function: Real part of \"$fct\":\n";
625         } elsif ($type eq 'imag') {
626           print NEWULP "Function: Imaginary part of \"$fct\":\n";
627         }
628         foreach $float (@all_floats) {
629           if (exists $results{$fct}{$type}{'ulp'}{$float}) {
630             print NEWULP "$float: ",
631             &clean_up_number ($results{$fct}{$type}{'ulp'}{$float}),
632             "\n";
633           }
634         }
635         print NEWULP "\n";
636       }
637     }
638   }
639   print NEWULP "# end of automatic generation\n";
640   close NEWULP;
641 }
642
643 sub get_ulps {
644   my ($test, $type, $float) = @_;
645
646   return (exists $results{$test}{$type}{'ulp'}{$float}
647           ? $results{$test}{$type}{'ulp'}{$float} : "0");
648 }
649
650 # Return the ulps value for a single test.
651 sub get_all_ulps_for_test {
652   my ($test, $type) = @_;
653   my ($ldouble, $double, $float, $ildouble, $idouble, $ifloat);
654
655   if (exists $results{$test}{'has_ulps'}) {
656     # XXX use all_floats (change order!)
657     $ldouble = &get_ulps ($test, $type, "ldouble");
658     $double = &get_ulps ($test, $type, "double");
659     $float = &get_ulps ($test, $type, "float");
660     $ildouble = &get_ulps ($test, $type, "ildouble");
661     $idouble = &get_ulps ($test, $type, "idouble");
662     $ifloat = &get_ulps ($test, $type, "ifloat");
663     return "CHOOSE ($ldouble, $double, $float, $ildouble, $idouble, $ifloat)";
664   } else {
665     die "get_all_ulps_for_test called for \"$test\" with no ulps\n";
666   }
667 }
668
669 # Print include file
670 sub output_ulps {
671   my ($file, $ulps_filename) = @_;
672   my ($i, $fct, $type, $ulp, $ulp_real, $ulp_imag);
673   my (%func_ulps, %func_real_ulps, %func_imag_ulps);
674
675   open ULP, ">$file" or die ("Can't open $file: $!");
676
677   print ULP "/* This file is automatically generated\n";
678   print ULP "   from $ulps_filename with gen-libm-test.pl.\n";
679   print ULP "   Don't change it - change instead the master files.  */\n\n";
680
681   foreach $fct (keys %results) {
682     $type = $results{$fct}{'type'};
683     if ($type eq 'normal') {
684       $ulp = get_all_ulps_for_test ($fct, 'normal');
685     } elsif ($type eq 'complex') {
686       $ulp_real = get_all_ulps_for_test ($fct, 'real');
687       $ulp_imag = get_all_ulps_for_test ($fct, 'imag');
688     } else {
689       die "unknown results ($fct) type $type\n";
690     }
691     if ($type eq 'normal') {
692       $func_ulps{$fct} = $ulp;
693     } else {
694       $func_real_ulps{$fct} = $ulp_real;
695       $func_imag_ulps{$fct} = $ulp_imag;
696     }
697   }
698   print ULP "\n/* Maximal error of functions.  */\n";
699   print ULP "static const struct ulp_data func_ulps[] =\n  {\n";
700   foreach $fct (sort keys %func_ulps) {
701     print ULP "    { \"$fct\", $func_ulps{$fct} },\n";
702   }
703   print ULP "  };\n";
704   print ULP "static const struct ulp_data func_real_ulps[] =\n  {\n";
705   foreach $fct (sort keys %func_real_ulps) {
706     print ULP "    { \"$fct\", $func_real_ulps{$fct} },\n";
707   }
708   print ULP "  };\n";
709   print ULP "static const struct ulp_data func_imag_ulps[] =\n  {\n";
710   foreach $fct (sort keys %func_imag_ulps) {
711     print ULP "    { \"$fct\", $func_imag_ulps{$fct} },\n";
712   }
713   print ULP "  };\n";
714   close ULP;
715 }
716
717 # Parse auto-libm-test-out.
718 sub parse_auto_input {
719   my ($file) = @_;
720   open AUTO, $file or die ("Can't open $file: $!");
721   while (<AUTO>) {
722     chop;
723     next if !/^= /;
724     s/^= //;
725     if (/^(\S+) (\S+) ([^:]*) : (.*)$/) {
726       $auto_tests{$1}{$2}{$3} = $4;
727     } else {
728       die ("bad automatic test line: $_\n");
729     }
730   }
731   close AUTO;
732 }