2 # Generate tests for libm functions.
3 # Copyright (C) 2018-2019 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
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.
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.
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 # <https://www.gnu.org/licenses/>.
21 from collections
import defaultdict
26 # Sorted list of all float types in ulps files.
27 ALL_FLOATS
= ('double', 'float', 'float128', 'idouble',
28 'ifloat', 'ifloat128', 'ildouble', 'ldouble')
30 # Map float types in ulps files to C-like prefix for macros.
31 ALL_FLOATS_PFX
= {'double': 'DBL',
36 # Float types in the order used in the generated ulps tables in the
38 ALL_FLOATS_MANUAL
= ('float', 'double', 'ldouble', 'float128')
40 # Map float types in ulps files to C function suffix.
41 ALL_FLOATS_SUFFIX
= {'double': '',
46 # Number of arguments in structure (as opposed to arguments that are
47 # pointers to return values) for an argument descriptor.
48 DESCR_NUM_ARGS
= {'f': 1, 'a': 1, 'j': 1, 'i': 1, 'u': 1, 'l': 1, 'L': 1,
49 'p': 0, 'F': 0, 'I': 0,
52 # Number of results in structure for a result descriptor.
53 DESCR_NUM_RES
= {'f': 1, 'i': 1, 'l': 1, 'L': 1, 'M': 1, 'U': 1, 'b': 1,
57 # Rounding modes, in the form in which they appear in
58 # auto-libm-test-out-* and the order in which expected results appear
59 # in structures and TEST_* calls.
60 ROUNDING_MODES
= ('downward', 'tonearest', 'towardzero', 'upward')
62 # Map from special text in TEST_* calls for rounding-mode-specific
63 # results and flags, to those results for each mode.
65 'plus_oflow': ('max_value', 'plus_infty', 'max_value', 'plus_infty'),
66 'minus_oflow': ('minus_infty', 'minus_infty', '-max_value', '-max_value'),
67 'plus_uflow': ('plus_zero', 'plus_zero', 'plus_zero', 'min_subnorm_value'),
68 'minus_uflow': ('-min_subnorm_value', 'minus_zero', 'minus_zero',
70 'ERRNO_PLUS_OFLOW': ('0', 'ERRNO_ERANGE', '0', 'ERRNO_ERANGE'),
71 'ERRNO_MINUS_OFLOW': ('ERRNO_ERANGE', 'ERRNO_ERANGE', '0', '0'),
72 'ERRNO_PLUS_UFLOW': ('ERRNO_ERANGE', 'ERRNO_ERANGE', 'ERRNO_ERANGE', '0'),
73 'ERRNO_MINUS_UFLOW': ('0', 'ERRNO_ERANGE', 'ERRNO_ERANGE', 'ERRNO_ERANGE'),
74 'XFAIL_ROUNDING_IBM128_LIBGCC': ('XFAIL_IBM128_LIBGCC', '0',
75 'XFAIL_IBM128_LIBGCC',
76 'XFAIL_IBM128_LIBGCC')
79 # Map from raw test arguments to a nicer form to use when displaying
81 BEAUTIFY_MAP
= {'minus_zero': '-0',
89 'minus_infty': '-inf',
93 'snan_value_ld': 'sNaN'}
95 # Flags in auto-libm-test-out that map directly to C flags.
96 FLAGS_SIMPLE
= {'ignore-zero-inf-sign': 'IGNORE_ZERO_INF_SIGN',
97 'no-test-inline': 'NO_TEST_INLINE',
98 'xfail': 'XFAIL_TEST'}
100 # Exceptions in auto-libm-test-out, and their corresponding C flags
101 # for being required, OK or required to be absent.
102 EXC_EXPECTED
= {'divbyzero': 'DIVBYZERO_EXCEPTION',
103 'inexact': 'INEXACT_EXCEPTION',
104 'invalid': 'INVALID_EXCEPTION',
105 'overflow': 'OVERFLOW_EXCEPTION',
106 'underflow': 'UNDERFLOW_EXCEPTION'}
107 EXC_OK
= {'divbyzero': 'DIVBYZERO_EXCEPTION_OK',
109 'invalid': 'INVALID_EXCEPTION_OK',
110 'overflow': 'OVERFLOW_EXCEPTION_OK',
111 'underflow': 'UNDERFLOW_EXCEPTION_OK'}
112 EXC_NO
= {'divbyzero': '0',
113 'inexact': 'NO_INEXACT_EXCEPTION',
120 """Maximum expected errors of libm functions."""
123 """Initialize an Ulps object."""
124 # normal[function][float_type] is the ulps value, and likewise
126 self
.normal
= defaultdict(lambda: defaultdict(lambda: 0))
127 self
.real
= defaultdict(lambda: defaultdict(lambda: 0))
128 self
.imag
= defaultdict(lambda: defaultdict(lambda: 0))
129 # List of ulps kinds, in the order in which they appear in
131 self
.ulps_kinds
= (('Real part of ', self
.real
),
132 ('Imaginary part of ', self
.imag
),
136 def read(self
, ulps_file
):
137 """Read ulps from a file into an Ulps object."""
138 self
.ulps_file
= ulps_file
139 with
open(ulps_file
, 'r') as f
:
144 if line
.startswith('#'):
147 # Ignore empty lines.
150 m
= re
.match(r
'([^:]*): (.*)\Z', line
)
152 raise ValueError('bad ulps line: %s' % line
)
153 line_first
= m
.group(1)
154 line_second
= m
.group(2)
155 if line_first
== 'Function':
158 for k_prefix
, k_dict
in self
.ulps_kinds
:
159 if line_second
.startswith(k_prefix
):
161 fn
= line_second
[len(k_prefix
):]
163 if not fn
.startswith('"') or not fn
.endswith('":'):
164 raise ValueError('bad ulps line: %s' % line
)
167 if line_first
not in ALL_FLOATS
:
168 raise ValueError('bad ulps line: %s' % line
)
169 ulps_val
= int(line_second
)
171 ulps_dict
[ulps_fn
][line_first
] = max(
172 ulps_dict
[ulps_fn
][line_first
],
175 def all_functions(self
):
176 """Return the set of functions with ulps and whether they are
180 for k_prefix
, k_dict
in self
.ulps_kinds
:
183 complex[f
] = True if k_prefix
else False
184 return funcs
, complex
186 def write(self
, ulps_file
):
187 """Write ulps back out as a sorted ulps file."""
188 # Output is sorted first by function name, then by (real,
189 # imag, normal), then by float type.
191 for order
, (prefix
, d
) in enumerate(self
.ulps_kinds
):
193 fn_data
= ['%s: %d' % (f
, d
[fn
][f
])
194 for f
in sorted(d
[fn
].keys())]
195 fn_text
= 'Function: %s"%s":\n%s' % (prefix
, fn
,
197 out_data
[(fn
, order
)] = fn_text
198 out_list
= [out_data
[fn_order
] for fn_order
in sorted(out_data
.keys())]
199 out_text
= ('# Begin of automatic generation\n\n'
200 '# Maximal error of functions:\n'
202 '# end of automatic generation\n'
203 % '\n\n'.join(out_list
))
204 with
open(ulps_file
, 'w') as f
:
208 def ulps_table(name
, ulps_dict
):
209 """Return text of a C table of ulps."""
211 for fn
in sorted(ulps_dict
.keys()):
212 fn_ulps
= [str(ulps_dict
[fn
][f
]) for f
in ALL_FLOATS
]
213 ulps_list
.append(' { "%s", {%s} },' % (fn
, ', '.join(fn_ulps
)))
214 ulps_text
= ('static const struct ulp_data %s[] =\n'
218 % (name
, '\n'.join(ulps_list
)))
221 def write_header(self
, ulps_header
):
222 """Write header file with ulps data."""
223 header_text_1
= ('/* This file is automatically generated\n'
224 ' from %s with gen-libm-test.py.\n'
225 ' Don\'t change it - change instead the master '
229 ' const char *name;\n'
230 ' FLOAT max_ulp[%d];\n'
232 % (self
.ulps_file
, len(ALL_FLOATS
)))
234 for i
, f
in enumerate(ALL_FLOATS
):
235 if f
.startswith('i'):
240 macro_list
.append('#define ULP_%s%s %d'
241 % (itxt
, ALL_FLOATS_PFX
[f
], i
))
242 header_text
= ('%s\n\n'
244 '/* Maximal error of functions. */\n'
248 % (header_text_1
, '\n'.join(macro_list
),
249 self
.ulps_table('func_ulps', self
.normal
),
250 self
.ulps_table('func_real_ulps', self
.real
),
251 self
.ulps_table('func_imag_ulps', self
.imag
)))
252 with
open(ulps_header
, 'w') as f
:
256 def read_all_ulps(srcdir
):
257 """Read all platforms' libm-test-ulps files."""
259 for dirpath
, dirnames
, filenames
in os
.walk(srcdir
):
260 if 'libm-test-ulps' in filenames
:
261 with
open(os
.path
.join(dirpath
, 'libm-test-ulps-name')) as f
:
262 name
= f
.read().rstrip()
263 all_ulps
[name
] = Ulps()
264 all_ulps
[name
].read(os
.path
.join(dirpath
, 'libm-test-ulps'))
268 def read_auto_tests(test_file
):
269 """Read tests from auto-libm-test-out-<function> (possibly None)."""
270 auto_tests
= defaultdict(lambda: defaultdict(dict))
271 if test_file
is None:
273 with
open(test_file
, 'r') as f
:
275 if not line
.startswith('= '):
277 line
= line
[len('= '):].rstrip()
278 # Function, rounding mode, condition and inputs, outputs
280 m
= re
.match(r
'([^ ]+) ([^ ]+) ([^: ][^ ]* [^:]*) : (.*)\Z', line
)
282 raise ValueError('bad automatic test line: %s' % line
)
283 auto_tests
[m
.group(1)][m
.group(2)][m
.group(3)] = m
.group(4)
288 """Return a nicer representation of a test argument."""
289 if arg
in BEAUTIFY_MAP
:
290 return BEAUTIFY_MAP
[arg
]
291 if arg
.startswith('-') and arg
[1:] in BEAUTIFY_MAP
:
292 return '-' + BEAUTIFY_MAP
[arg
[1:]]
293 if re
.match(r
'-?0x[0-9a-f.]*p[-+][0-9]+f\Z', arg
):
295 if re
.search(r
'[0-9]L\Z', arg
):
300 def complex_beautify(arg_real
, arg_imag
):
301 """Return a nicer representation of a complex test argument."""
302 res_real
= beautify(arg_real
)
303 res_imag
= beautify(arg_imag
)
304 if res_imag
.startswith('-'):
305 return '%s - %s i' % (res_real
, res_imag
[1:])
307 return '%s + %s i' % (res_real
, res_imag
)
310 def apply_lit_token(arg
, macro
):
311 """Apply the LIT or ARG_LIT macro to a single token."""
312 # The macro must only be applied to a floating-point constant, not
313 # to an integer constant or lit_* value.
315 exp_re
= r
'([+-])?[0-9]+'
316 suffix_re
= r
'[lLfF]?'
317 dec_exp_re
= r
'[eE]' + exp_re
318 hex_exp_re
= r
'[pP]' + exp_re
319 dec_frac_re
= r
'(?:[0-9]*\.[0-9]+|[0-9]+\.)'
320 hex_frac_re
= r
'(?:[0-9a-fA-F]*\.[0-9a-fA-F]+|[0-9a-fA-F]+\.)'
321 dec_int_re
= r
'[0-9]+'
322 hex_int_re
= r
'[0-9a-fA-F]+'
323 dec_cst_re
= r
'(?:%s(?:%s)?|%s%s)' % (dec_frac_re
, dec_exp_re
,
324 dec_int_re
, dec_exp_re
)
325 hex_cst_re
= r
'0[xX](?:%s|%s)%s' % (hex_frac_re
, hex_int_re
, hex_exp_re
)
326 fp_cst_re
= r
'(%s(?:%s|%s))%s\Z' % (sign_re
, dec_cst_re
, hex_cst_re
,
328 m
= re
.match(fp_cst_re
, arg
)
330 return '%s (%s)' % (macro
, m
.group(1))
335 def apply_lit(arg
, macro
):
336 """Apply the LIT or ARG_LIT macro to constants within an expression."""
337 # Assume expressions follow the GNU Coding Standards, with tokens
338 # separated by spaces.
339 return ' '.join([apply_lit_token(t
, macro
) for t
in arg
.split()])
342 def gen_test_args_res(descr_args
, descr_res
, args
, res_rm
):
343 """Generate a test given the arguments and per-rounding-mode results."""
345 all_args_res
= list(args
)
347 all_args_res
.extend(r
[:len(r
)-1])
348 for a
in all_args_res
:
349 if 'snan_value' in a
:
351 # Process the arguments.
356 if DESCR_NUM_ARGS
[d
] == 0:
359 args_disp
.append(complex_beautify(args
[arg_pos
],
361 args_c
.append(apply_lit(args
[arg_pos
], 'LIT'))
362 args_c
.append(apply_lit(args
[arg_pos
+ 1], 'LIT'))
364 args_disp
.append(beautify(args
[arg_pos
]))
366 args_c
.append(apply_lit(args
[arg_pos
], 'LIT'))
368 args_c
.append(apply_lit(args
[arg_pos
], 'ARG_LIT'))
370 args_c
.append(args
[arg_pos
])
371 arg_pos
+= DESCR_NUM_ARGS
[d
]
372 args_disp_text
= ', '.join(args_disp
).replace('"', '\\"')
373 # Process the results.
374 for rm
in range(len(ROUNDING_MODES
)):
378 ignore_result_any
= False
379 ignore_result_all
= True
383 special
.append(res
[res_pos
])
384 elif DESCR_NUM_RES
[d
] == 1:
385 result
= res
[res_pos
]
386 if result
== 'IGNORE':
387 ignore_result_any
= True
390 ignore_result_all
= False
392 result
= apply_lit(result
, 'LIT')
393 rm_args
.append(result
)
396 result1
= res
[res_pos
]
397 if result1
== 'IGNORE':
398 ignore_result_any
= True
401 ignore_result_all
= False
402 result1
= apply_lit(result1
, 'LIT')
403 rm_args
.append(result1
)
404 result2
= res
[res_pos
+ 1]
405 if result2
== 'IGNORE':
406 ignore_result_any
= True
409 ignore_result_all
= False
410 result2
= apply_lit(result2
, 'LIT')
411 rm_args
.append(result2
)
412 res_pos
+= DESCR_NUM_RES
[d
]
413 if ignore_result_any
and not ignore_result_all
:
414 raise ValueError('some but not all function results ignored')
416 if ignore_result_any
:
417 flags
.append('IGNORE_RESULT')
419 flags
.append('TEST_SNAN')
420 flags
.append(res
[res_pos
])
421 rm_args
.append('|'.join(flags
))
424 rm_args
.extend(['0', '0'])
426 rm_args
.extend(['1', apply_lit(sp
, 'LIT')])
427 for k
in sorted(ROUNDING_MAP
.keys()):
428 rm_args
= [arg
.replace(k
, ROUNDING_MAP
[k
][rm
]) for arg
in rm_args
]
429 args_c
.append('{ %s }' % ', '.join(rm_args
))
430 return ' { "%s", %s },\n' % (args_disp_text
, ', '.join(args_c
))
433 def convert_condition(cond
):
434 """Convert a condition from auto-libm-test-out to C form."""
435 conds
= cond
.split(':')
438 if not c
.startswith('arg_fmt('):
439 c
= c
.replace('-', '_')
440 conds_c
.append('TEST_COND_' + c
)
441 return '(%s)' % ' && '.join(conds_c
)
444 def cond_value(cond
, if_val
, else_val
):
445 """Return a C conditional expression between two values."""
451 return '(%s ? %s : %s)' % (cond
, if_val
, else_val
)
454 def gen_auto_tests(auto_tests
, descr_args
, descr_res
, fn
):
455 """Generate C code for the auto-libm-test-out-* tests for a function."""
456 for rm_idx
, rm_name
in enumerate(ROUNDING_MODES
):
457 this_tests
= sorted(auto_tests
[fn
][rm_name
].keys())
459 rm_tests
= this_tests
461 raise ValueError('no automatic tests for %s' % fn
)
463 if rm_tests
!= this_tests
:
464 raise ValueError('inconsistent lists of tests of %s' % fn
)
466 for test
in rm_tests
:
467 fmt_args
= test
.split()
470 test_list
.append('#if %s\n' % convert_condition(fmt
))
472 for rm
in ROUNDING_MODES
:
473 test_out
= auto_tests
[fn
][rm
][test
]
474 out_str
, flags_str
= test_out
.split(':', 1)
475 this_res
= out_str
.split()
476 flags
= flags_str
.split()
479 m
= re
.match(r
'([^:]*):(.*)\Z', flag
)
482 cond
= convert_condition(m
.group(2))
483 if f_name
in flag_cond
:
484 if flag_cond
[f_name
] != '1':
485 flag_cond
[f_name
] = ('%s || %s'
486 % (flag_cond
[f_name
], cond
))
488 flag_cond
[f_name
] = cond
490 flag_cond
[flag
] = '1'
492 for flag
in sorted(FLAGS_SIMPLE
.keys()):
493 if flag
in flag_cond
:
494 flags_c
.append(cond_value(flag_cond
[flag
],
495 FLAGS_SIMPLE
[flag
], '0'))
496 for exc
in sorted(EXC_EXPECTED
.keys()):
497 exc_expected
= EXC_EXPECTED
[exc
]
500 exc_cond
= flag_cond
.get(exc
, '0')
501 exc_ok_cond
= flag_cond
.get(exc
+ '-ok', '0')
502 flags_c
.append(cond_value(exc_cond
,
503 cond_value(exc_ok_cond
, exc_ok
,
505 cond_value(exc_ok_cond
, exc_ok
,
507 if 'errno-edom' in flag_cond
and 'errno-erange' in flag_cond
:
508 raise ValueError('multiple errno values expected')
509 if 'errno-edom' in flag_cond
:
510 if flag_cond
['errno-edom'] != '1':
511 raise ValueError('unexpected condition for errno-edom')
512 errno_expected
= 'ERRNO_EDOM'
513 elif 'errno-erange' in flag_cond
:
514 if flag_cond
['errno-erange'] != '1':
515 raise ValueError('unexpected condition for errno-erange')
516 errno_expected
= 'ERRNO_ERANGE'
518 errno_expected
= 'ERRNO_UNCHANGED'
519 if 'errno-edom-ok' in flag_cond
:
520 if ('errno-erange-ok' in flag_cond
521 and (flag_cond
['errno-erange-ok']
522 != flag_cond
['errno-edom-ok'])):
523 errno_unknown_cond
= ('%s || %s'
524 % (flag_cond
['errno-edom-ok'],
525 flag_cond
['errno-erange-ok']))
527 errno_unknown_cond
= flag_cond
['errno-edom-ok']
529 errno_unknown_cond
= flag_cond
.get('errno-erange-ok', '0')
530 flags_c
.append(cond_value(errno_unknown_cond
, '0', errno_expected
))
531 flags_c
= [flag
for flag
in flags_c
if flag
!= '0']
533 flags_c
= ['NO_EXCEPTION']
534 this_res
.append(' | '.join(flags_c
))
535 res_rm
.append(this_res
)
536 test_list
.append(gen_test_args_res(descr_args
, descr_res
, args
,
538 test_list
.append('#endif\n')
539 return ''.join(test_list
)
542 def gen_test_line(descr_args
, descr_res
, args_str
):
543 """Generate C code for the tests for a single TEST_* line."""
544 test_args
= args_str
.split(',')
545 test_args
= test_args
[1:]
546 test_args
= [a
.strip() for a
in test_args
]
547 num_args
= sum([DESCR_NUM_ARGS
[c
] for c
in descr_args
])
548 num_res
= sum([DESCR_NUM_RES
[c
] for c
in descr_res
])
549 args
= test_args
[:num_args
]
550 res
= test_args
[num_args
:]
551 if len(res
) == num_res
:
552 # One set of results for all rounding modes, no flags.
554 res_rm
= [res
, res
, res
, res
]
555 elif len(res
) == num_res
+ 1:
556 # One set of results for all rounding modes, with flags.
557 if not ('EXCEPTION' in res
[-1]
558 or 'ERRNO' in res
[-1]
559 or 'IGNORE_ZERO_INF_SIGN' in res
[-1]
560 or 'TEST_NAN_SIGN' in res
[-1]
561 or 'NO_TEST_INLINE' in res
[-1]
562 or 'XFAIL' in res
[-1]):
563 raise ValueError('wrong number of arguments: %s' % args_str
)
564 res_rm
= [res
, res
, res
, res
]
565 elif len(res
) == (num_res
+ 1) * 4:
566 # One set of results per rounding mode, with flags.
567 nr_plus
= num_res
+ 1
568 res_rm
= [res
[:nr_plus
], res
[nr_plus
:2*nr_plus
],
569 res
[2*nr_plus
:3*nr_plus
], res
[3*nr_plus
:]]
570 return gen_test_args_res(descr_args
, descr_res
, args
, res_rm
)
573 def generate_testfile(inc_input
, auto_tests
, c_output
):
574 """Generate test .c file from .inc input."""
576 with
open(inc_input
, 'r') as f
:
578 line_strip
= line
.strip()
579 if line_strip
.startswith('AUTO_TESTS_'):
580 m
= re
.match(r
'AUTO_TESTS_([^_]*)_([^_ ]*) *\(([^)]*)\),\Z',
583 raise ValueError('bad AUTO_TESTS line: %s' % line
)
584 test_list
.append(gen_auto_tests(auto_tests
, m
.group(1),
585 m
.group(2), m
.group(3)))
586 elif line_strip
.startswith('TEST_'):
587 m
= re
.match(r
'TEST_([^_]*)_([^_ ]*) *\((.*)\),\Z', line_strip
)
589 raise ValueError('bad TEST line: %s' % line
)
590 test_list
.append(gen_test_line(m
.group(1), m
.group(2),
593 test_list
.append(line
)
594 with
open(c_output
, 'w') as f
:
595 f
.write(''.join(test_list
))
598 def generate_err_table_sub(all_ulps
, all_functions
, fns_complex
, platforms
):
599 """Generate a single table within the overall ulps table section."""
600 plat_width
= [' {1000 + i 1000}' for p
in platforms
]
601 plat_header
= [' @tab %s' % p
for p
in platforms
]
602 table_list
= ['@multitable {nexttowardf} %s\n' % ''.join(plat_width
),
603 '@item Function %s\n' % ''.join(plat_header
)]
604 for func
in all_functions
:
605 for flt
in ALL_FLOATS_MANUAL
:
609 if fns_complex
[func
]:
610 ulp_real
= p_ulps
.real
[func
][flt
]
611 ulp_imag
= p_ulps
.imag
[func
][flt
]
612 ulp_str
= '%d + i %d' % (ulp_real
, ulp_imag
)
613 ulp_str
= ulp_str
if ulp_real
or ulp_imag
else '-'
615 ulp
= p_ulps
.normal
[func
][flt
]
616 ulp_str
= str(ulp
) if ulp
else '-'
617 func_ulps
.append(ulp_str
)
618 table_list
.append('@item %s%s @tab %s\n'
619 % (func
, ALL_FLOATS_SUFFIX
[flt
],
620 ' @tab '.join(func_ulps
)))
621 table_list
.append('@end multitable\n')
622 return ''.join(table_list
)
625 def generate_err_table(all_ulps
, err_table
):
626 """Generate ulps table for manual."""
627 all_platforms
= sorted(all_ulps
.keys())
628 functions_set
= set()
629 functions_complex
= {}
630 for p
in all_platforms
:
631 p_functions
, p_complex
= all_ulps
[p
].all_functions()
632 functions_set
.update(p_functions
)
633 functions_complex
.update(p_complex
)
634 all_functions
= sorted([f
for f
in functions_set
635 if ('_downward' not in f
636 and '_towardzero' not in f
637 and '_upward' not in f
638 and '_vlen' not in f
)])
640 # Print five platforms at a time.
641 num_platforms
= len(all_platforms
)
642 for i
in range((num_platforms
+ 4) // 5):
644 end
= i
* 5 + 5 if num_platforms
>= i
* 5 + 5 else num_platforms
645 err_table_list
.append(generate_err_table_sub(all_ulps
, all_functions
,
647 all_platforms
[start
:end
]))
648 with
open(err_table
, 'w') as f
:
649 f
.write(''.join(err_table_list
))
653 """The main entry point."""
654 parser
= argparse
.ArgumentParser(description
='Generate libm tests.')
655 parser
.add_argument('-a', dest
='auto_input', metavar
='FILE',
656 help='input file with automatically generated tests')
657 parser
.add_argument('-c', dest
='inc_input', metavar
='FILE',
658 help='input file .inc file with tests')
659 parser
.add_argument('-u', dest
='ulps_file', metavar
='FILE',
660 help='input file with ulps')
661 parser
.add_argument('-s', dest
='srcdir', metavar
='DIR',
662 help='input source directory with all ulps')
663 parser
.add_argument('-n', dest
='ulps_output', metavar
='FILE',
664 help='generate sorted ulps file FILE')
665 parser
.add_argument('-C', dest
='c_output', metavar
='FILE',
666 help='generate output C file FILE from .inc file')
667 parser
.add_argument('-H', dest
='ulps_header', metavar
='FILE',
668 help='generate output ulps header FILE')
669 parser
.add_argument('-m', dest
='err_table', metavar
='FILE',
670 help='generate output ulps table for manual FILE')
671 args
= parser
.parse_args()
673 if args
.ulps_file
is not None:
674 ulps
.read(args
.ulps_file
)
675 auto_tests
= read_auto_tests(args
.auto_input
)
676 if args
.srcdir
is not None:
677 all_ulps
= read_all_ulps(args
.srcdir
)
678 if args
.ulps_output
is not None:
679 ulps
.write(args
.ulps_output
)
680 if args
.ulps_header
is not None:
681 ulps
.write_header(args
.ulps_header
)
682 if args
.c_output
is not None:
683 generate_testfile(args
.inc_input
, auto_tests
, args
.c_output
)
684 if args
.err_table
is not None:
685 generate_err_table(all_ulps
, args
.err_table
)
688 if __name__
== '__main__':