mbstowcs: Remove outdated comment
[glibc.git] / math / gen-libm-test.py
blob8d156ea8d13e5be88b2df1b0f33d53371c515578
1 #!/usr/bin/python
2 # Generate tests for libm functions.
3 # Copyright (C) 2018 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 # <http://www.gnu.org/licenses/>.
20 import argparse
21 from collections import defaultdict
22 import re
25 # Sorted list of all float types in ulps files.
26 ALL_FLOATS = ('double', 'float', 'float128', 'idouble',
27 'ifloat', 'ifloat128', 'ildouble', 'ldouble')
29 # Map float types in ulps files to C-like prefix for macros.
30 ALL_FLOATS_PFX = {'double': 'DBL',
31 'ldouble': 'LDBL',
32 'float': 'FLT',
33 'float128': 'FLT128'}
35 # Number of arguments in structure (as opposed to arguments that are
36 # pointers to return values) for an argument descriptor.
37 DESCR_NUM_ARGS = {'f': 1, 'a': 1, 'j': 1, 'i': 1, 'u': 1, 'l': 1, 'L': 1,
38 'p': 0, 'F': 0, 'I': 0,
39 'c': 2}
41 # Number of results in structure for a result descriptor.
42 DESCR_NUM_RES = {'f': 1, 'i': 1, 'l': 1, 'L': 1, 'M': 1, 'U': 1, 'b': 1,
43 '1': 1,
44 'c': 2}
46 # Rounding modes, in the form in which they appear in
47 # auto-libm-test-out-* and the order in which expected results appear
48 # in structures and TEST_* calls.
49 ROUNDING_MODES = ('downward', 'tonearest', 'towardzero', 'upward')
51 # Map from special text in TEST_* calls for rounding-mode-specific
52 # results and flags, to those results for each mode.
53 ROUNDING_MAP = {
54 'plus_oflow': ('max_value', 'plus_infty', 'max_value', 'plus_infty'),
55 'minus_oflow': ('minus_infty', 'minus_infty', '-max_value', '-max_value'),
56 'plus_uflow': ('plus_zero', 'plus_zero', 'plus_zero', 'min_subnorm_value'),
57 'minus_uflow': ('-min_subnorm_value', 'minus_zero', 'minus_zero',
58 'minus_zero'),
59 'ERRNO_PLUS_OFLOW': ('0', 'ERRNO_ERANGE', '0', 'ERRNO_ERANGE'),
60 'ERRNO_MINUS_OFLOW': ('ERRNO_ERANGE', 'ERRNO_ERANGE', '0', '0'),
61 'ERRNO_PLUS_UFLOW': ('ERRNO_ERANGE', 'ERRNO_ERANGE', 'ERRNO_ERANGE', '0'),
62 'ERRNO_MINUS_UFLOW': ('0', 'ERRNO_ERANGE', 'ERRNO_ERANGE', 'ERRNO_ERANGE'),
63 'XFAIL_ROUNDING_IBM128_LIBGCC': ('XFAIL_IBM128_LIBGCC', '0',
64 'XFAIL_IBM128_LIBGCC',
65 'XFAIL_IBM128_LIBGCC')
68 # Map from raw test arguments to a nicer form to use when displaying
69 # test results.
70 BEAUTIFY_MAP = {'minus_zero': '-0',
71 'plus_zero': '+0',
72 '-0x0p+0f': '-0',
73 '-0x0p+0': '-0',
74 '-0x0p+0L': '-0',
75 '0x0p+0f': '+0',
76 '0x0p+0': '+0',
77 '0x0p+0L': '+0',
78 'minus_infty': '-inf',
79 'plus_infty': 'inf',
80 'qnan_value': 'qNaN',
81 'snan_value': 'sNaN',
82 'snan_value_ld': 'sNaN'}
84 # Flags in auto-libm-test-out that map directly to C flags.
85 FLAGS_SIMPLE = {'ignore-zero-inf-sign': 'IGNORE_ZERO_INF_SIGN',
86 'no-test-inline': 'NO_TEST_INLINE',
87 'xfail': 'XFAIL_TEST'}
89 # Exceptions in auto-libm-test-out, and their corresponding C flags
90 # for being required, OK or required to be absent.
91 EXC_EXPECTED = {'divbyzero': 'DIVBYZERO_EXCEPTION',
92 'inexact': 'INEXACT_EXCEPTION',
93 'invalid': 'INVALID_EXCEPTION',
94 'overflow': 'OVERFLOW_EXCEPTION',
95 'underflow': 'UNDERFLOW_EXCEPTION'}
96 EXC_OK = {'divbyzero': 'DIVBYZERO_EXCEPTION_OK',
97 'inexact': '0',
98 'invalid': 'INVALID_EXCEPTION_OK',
99 'overflow': 'OVERFLOW_EXCEPTION_OK',
100 'underflow': 'UNDERFLOW_EXCEPTION_OK'}
101 EXC_NO = {'divbyzero': '0',
102 'inexact': 'NO_INEXACT_EXCEPTION',
103 'invalid': '0',
104 'overflow': '0',
105 'underflow': '0'}
108 class Ulps(object):
109 """Maximum expected errors of libm functions."""
111 def __init__(self):
112 """Initialize an Ulps object."""
113 # normal[function][float_type] is the ulps value, and likewise
114 # for real and imag.
115 self.normal = defaultdict(lambda: defaultdict(lambda: 0))
116 self.real = defaultdict(lambda: defaultdict(lambda: 0))
117 self.imag = defaultdict(lambda: defaultdict(lambda: 0))
118 # List of ulps kinds, in the order in which they appear in
119 # sorted ulps files.
120 self.ulps_kinds = (('Real part of ', self.real),
121 ('Imaginary part of ', self.imag),
122 ('', self.normal))
123 self
125 def read(self, ulps_file):
126 """Read ulps from a file into an Ulps object."""
127 self.ulps_file = ulps_file
128 with open(ulps_file, 'r') as f:
129 ulps_dict = None
130 ulps_fn = None
131 for line in f:
132 # Ignore comments.
133 if line.startswith('#'):
134 continue
135 line = line.rstrip()
136 # Ignore empty lines.
137 if line == '':
138 continue
139 m = re.match(r'([^:]*): (.*)\Z', line)
140 if not m:
141 raise ValueError('bad ulps line: %s' % line)
142 line_first = m.group(1)
143 line_second = m.group(2)
144 if line_first == 'Function':
145 fn = None
146 ulps_dict = None
147 for k_prefix, k_dict in self.ulps_kinds:
148 if line_second.startswith(k_prefix):
149 ulps_dict = k_dict
150 fn = line_second[len(k_prefix):]
151 break
152 if not fn.startswith('"') or not fn.endswith('":'):
153 raise ValueError('bad ulps line: %s' % line)
154 ulps_fn = fn[1:-2]
155 else:
156 if line_first not in ALL_FLOATS:
157 raise ValueError('bad ulps line: %s' % line)
158 ulps_val = int(line_second)
159 if ulps_val > 0:
160 ulps_dict[ulps_fn][line_first] = max(
161 ulps_dict[ulps_fn][line_first],
162 ulps_val)
164 def write(self, ulps_file):
165 """Write ulps back out as a sorted ulps file."""
166 # Output is sorted first by function name, then by (real,
167 # imag, normal), then by float type.
168 out_data = {}
169 for order, (prefix, d) in enumerate(self.ulps_kinds):
170 for fn in d.keys():
171 fn_data = ['%s: %d' % (f, d[fn][f])
172 for f in sorted(d[fn].keys())]
173 fn_text = 'Function: %s"%s":\n%s' % (prefix, fn,
174 '\n'.join(fn_data))
175 out_data[(fn, order)] = fn_text
176 out_list = [out_data[fn_order] for fn_order in sorted(out_data.keys())]
177 out_text = ('# Begin of automatic generation\n\n'
178 '# Maximal error of functions:\n'
179 '%s\n\n'
180 '# end of automatic generation\n'
181 % '\n\n'.join(out_list))
182 with open(ulps_file, 'w') as f:
183 f.write(out_text)
185 @staticmethod
186 def ulps_table(name, ulps_dict):
187 """Return text of a C table of ulps."""
188 ulps_list = []
189 for fn in sorted(ulps_dict.keys()):
190 fn_ulps = [str(ulps_dict[fn][f]) for f in ALL_FLOATS]
191 ulps_list.append(' { "%s", {%s} },' % (fn, ', '.join(fn_ulps)))
192 ulps_text = ('static const struct ulp_data %s[] =\n'
193 ' {\n'
194 '%s\n'
195 ' };'
196 % (name, '\n'.join(ulps_list)))
197 return ulps_text
199 def write_header(self, ulps_header):
200 """Write header file with ulps data."""
201 header_text_1 = ('/* This file is automatically generated\n'
202 ' from %s with gen-libm-test.py.\n'
203 ' Don\'t change it - change instead the master '
204 'files. */\n\n'
205 'struct ulp_data\n'
206 '{\n'
207 ' const char *name;\n'
208 ' FLOAT max_ulp[%d];\n'
209 '};'
210 % (self.ulps_file, len(ALL_FLOATS)))
211 macro_list = []
212 for i, f in enumerate(ALL_FLOATS):
213 if f.startswith('i'):
214 itxt = 'I_'
215 f = f[1:]
216 else:
217 itxt = ''
218 macro_list.append('#define ULP_%s%s %d'
219 % (itxt, ALL_FLOATS_PFX[f], i))
220 header_text = ('%s\n\n'
221 '%s\n\n'
222 '/* Maximal error of functions. */\n'
223 '%s\n'
224 '%s\n'
225 '%s\n'
226 % (header_text_1, '\n'.join(macro_list),
227 self.ulps_table('func_ulps', self.normal),
228 self.ulps_table('func_real_ulps', self.real),
229 self.ulps_table('func_imag_ulps', self.imag)))
230 with open(ulps_header, 'w') as f:
231 f.write(header_text)
234 def read_auto_tests(test_file):
235 """Read tests from auto-libm-test-out-<function> (possibly None)."""
236 auto_tests = defaultdict(lambda: defaultdict(dict))
237 if test_file is None:
238 return auto_tests
239 with open(test_file, 'r') as f:
240 for line in f:
241 if not line.startswith('= '):
242 continue
243 line = line[len('= '):].rstrip()
244 # Function, rounding mode, condition and inputs, outputs
245 # and flags.
246 m = re.match(r'([^ ]+) ([^ ]+) ([^: ][^ ]* [^:]*) : (.*)\Z', line)
247 if not m:
248 raise ValueError('bad automatic test line: %s' % line)
249 auto_tests[m.group(1)][m.group(2)][m.group(3)] = m.group(4)
250 return auto_tests
253 def beautify(arg):
254 """Return a nicer representation of a test argument."""
255 if arg in BEAUTIFY_MAP:
256 return BEAUTIFY_MAP[arg]
257 if arg.startswith('-') and arg[1:] in BEAUTIFY_MAP:
258 return '-' + BEAUTIFY_MAP[arg[1:]]
259 if re.match(r'-?0x[0-9a-f.]*p[-+][0-9]+f\Z', arg):
260 return arg[:-1]
261 if re.search(r'[0-9]L\Z', arg):
262 return arg[:-1]
263 return arg
266 def complex_beautify(arg_real, arg_imag):
267 """Return a nicer representation of a complex test argument."""
268 res_real = beautify(arg_real)
269 res_imag = beautify(arg_imag)
270 if res_imag.startswith('-'):
271 return '%s - %s i' % (res_real, res_imag[1:])
272 else:
273 return '%s + %s i' % (res_real, res_imag)
276 def apply_lit_token(arg, macro):
277 """Apply the LIT or ARG_LIT macro to a single token."""
278 # The macro must only be applied to a floating-point constant, not
279 # to an integer constant or lit_* value.
280 sign_re = r'[+-]?'
281 exp_re = r'([+-])?[0-9]+'
282 suffix_re = r'[lLfF]?'
283 dec_exp_re = r'[eE]' + exp_re
284 hex_exp_re = r'[pP]' + exp_re
285 dec_frac_re = r'(?:[0-9]*\.[0-9]+|[0-9]+\.)'
286 hex_frac_re = r'(?:[0-9a-fA-F]*\.[0-9a-fA-F]+|[0-9a-fA-F]+\.)'
287 dec_int_re = r'[0-9]+'
288 hex_int_re = r'[0-9a-fA-F]+'
289 dec_cst_re = r'(?:%s(?:%s)?|%s%s)' % (dec_frac_re, dec_exp_re,
290 dec_int_re, dec_exp_re)
291 hex_cst_re = r'0[xX](?:%s|%s)%s' % (hex_frac_re, hex_int_re, hex_exp_re)
292 fp_cst_re = r'(%s(?:%s|%s))%s\Z' % (sign_re, dec_cst_re, hex_cst_re,
293 suffix_re)
294 m = re.match(fp_cst_re, arg)
295 if m:
296 return '%s (%s)' % (macro, m.group(1))
297 else:
298 return arg
301 def apply_lit(arg, macro):
302 """Apply the LIT or ARG_LIT macro to constants within an expression."""
303 # Assume expressions follow the GNU Coding Standards, with tokens
304 # separated by spaces.
305 return ' '.join([apply_lit_token(t, macro) for t in arg.split()])
308 def gen_test_args_res(descr_args, descr_res, args, res_rm):
309 """Generate a test given the arguments and per-rounding-mode results."""
310 # Determine whether any arguments or results, for any rounding
311 # mode, are non-finite. (For consistency with the old perl
312 # script, this does not handle infinities resulting from
313 # ROUNDING_MAP.)
314 non_finite = False
315 test_snan = False
316 all_args_res = list(args)
317 for r in res_rm:
318 all_args_res.extend(r[:len(r)-1])
319 for a in all_args_res:
320 if 'snan_value' in a:
321 test_snan = True
322 non_finite = True
323 elif 'qnan_value' in a or 'plus_infty' in a or 'minus_infty' in a:
324 non_finite = True
325 # Process the arguments.
326 args_disp = []
327 args_c = []
328 arg_pos = 0
329 for d in descr_args:
330 if DESCR_NUM_ARGS[d] == 0:
331 continue
332 if d == 'c':
333 args_disp.append(complex_beautify(args[arg_pos],
334 args[arg_pos + 1]))
335 args_c.append(apply_lit(args[arg_pos], 'LIT'))
336 args_c.append(apply_lit(args[arg_pos + 1], 'LIT'))
337 else:
338 args_disp.append(beautify(args[arg_pos]))
339 if d == 'f':
340 args_c.append(apply_lit(args[arg_pos], 'LIT'))
341 elif d == 'a':
342 args_c.append(apply_lit(args[arg_pos], 'ARG_LIT'))
343 else:
344 args_c.append(args[arg_pos])
345 arg_pos += DESCR_NUM_ARGS[d]
346 args_disp_text = ', '.join(args_disp).replace('"', '\\"')
347 # Process the results.
348 for rm in range(len(ROUNDING_MODES)):
349 res = res_rm[rm]
350 res_pos = 0
351 rm_args = []
352 ignore_result_any = False
353 ignore_result_all = True
354 special = []
355 for d in descr_res:
356 if d == '1':
357 special.append(res[res_pos])
358 elif DESCR_NUM_RES[d] == 1:
359 result = res[res_pos]
360 if result == 'IGNORE':
361 ignore_result_any = True
362 result = '0'
363 else:
364 ignore_result_all = False
365 if d == 'f':
366 result = apply_lit(result, 'LIT')
367 rm_args.append(result)
368 else:
369 # Complex result.
370 result1 = res[res_pos]
371 if result1 == 'IGNORE':
372 ignore_result_any = True
373 result1 = '0'
374 else:
375 ignore_result_all = False
376 result1 = apply_lit(result1, 'LIT')
377 rm_args.append(result1)
378 result2 = res[res_pos + 1]
379 if result2 == 'IGNORE':
380 ignore_result_any = True
381 result2 = '0'
382 else:
383 ignore_result_all = False
384 result2 = apply_lit(result2, 'LIT')
385 rm_args.append(result2)
386 res_pos += DESCR_NUM_RES[d]
387 if ignore_result_any and not ignore_result_all:
388 raise ValueError('some but not all function results ignored')
389 flags = []
390 if ignore_result_any:
391 flags.append('IGNORE_RESULT')
392 if non_finite:
393 flags.append('NON_FINITE')
394 if test_snan:
395 flags.append('TEST_SNAN')
396 flags.append(res[res_pos])
397 rm_args.append('|'.join(flags))
398 for sp in special:
399 if sp == 'IGNORE':
400 rm_args.extend(['0', '0'])
401 else:
402 rm_args.extend(['1', apply_lit(sp, 'LIT')])
403 for k in sorted(ROUNDING_MAP.keys()):
404 rm_args = [arg.replace(k, ROUNDING_MAP[k][rm]) for arg in rm_args]
405 args_c.append('{ %s }' % ', '.join(rm_args))
406 return ' { "%s", %s },\n' % (args_disp_text, ', '.join(args_c))
409 def convert_condition(cond):
410 """Convert a condition from auto-libm-test-out to C form."""
411 conds = cond.split(':')
412 conds_c = []
413 for c in conds:
414 if not c.startswith('arg_fmt('):
415 c = c.replace('-', '_')
416 conds_c.append('TEST_COND_' + c)
417 return '(%s)' % ' && '.join(conds_c)
420 def cond_value(cond, if_val, else_val):
421 """Return a C conditional expression between two values."""
422 if cond == '1':
423 return if_val
424 elif cond == '0':
425 return else_val
426 else:
427 return '(%s ? %s : %s)' % (cond, if_val, else_val)
430 def gen_auto_tests(auto_tests, descr_args, descr_res, fn):
431 """Generate C code for the auto-libm-test-out-* tests for a function."""
432 for rm_idx, rm_name in enumerate(ROUNDING_MODES):
433 this_tests = sorted(auto_tests[fn][rm_name].keys())
434 if rm_idx == 0:
435 rm_tests = this_tests
436 if not rm_tests:
437 raise ValueError('no automatic tests for %s' % fn)
438 else:
439 if rm_tests != this_tests:
440 raise ValueError('inconsistent lists of tests of %s' % fn)
441 test_list = []
442 for test in rm_tests:
443 fmt_args = test.split()
444 fmt = fmt_args[0]
445 args = fmt_args[1:]
446 test_list.append('#if %s\n' % convert_condition(fmt))
447 res_rm = []
448 for rm in ROUNDING_MODES:
449 test_out = auto_tests[fn][rm][test]
450 out_str, flags_str = test_out.split(':', 1)
451 this_res = out_str.split()
452 flags = flags_str.split()
453 flag_cond = {}
454 for flag in flags:
455 m = re.match(r'([^:]*):(.*)\Z', flag)
456 if m:
457 f_name = m.group(1)
458 cond = convert_condition(m.group(2))
459 if f_name in flag_cond:
460 if flag_cond[f_name] != '1':
461 flag_cond[f_name] = ('%s || %s'
462 % (flag_cond[f_name], cond))
463 else:
464 flag_cond[f_name] = cond
465 else:
466 flag_cond[flag] = '1'
467 flags_c = []
468 for flag in sorted(FLAGS_SIMPLE.keys()):
469 if flag in flag_cond:
470 flags_c.append(cond_value(flag_cond[flag],
471 FLAGS_SIMPLE[flag], '0'))
472 for exc in sorted(EXC_EXPECTED.keys()):
473 exc_expected = EXC_EXPECTED[exc]
474 exc_ok = EXC_OK[exc]
475 no_exc = EXC_NO[exc]
476 exc_cond = flag_cond.get(exc, '0')
477 exc_ok_cond = flag_cond.get(exc + '-ok', '0')
478 flags_c.append(cond_value(exc_cond,
479 cond_value(exc_ok_cond, exc_ok,
480 exc_expected),
481 cond_value(exc_ok_cond, exc_ok,
482 no_exc)))
483 if 'errno-edom' in flag_cond and 'errno-erange' in flag_cond:
484 raise ValueError('multiple errno values expected')
485 if 'errno-edom' in flag_cond:
486 if flag_cond['errno-edom'] != '1':
487 raise ValueError('unexpected condition for errno-edom')
488 errno_expected = 'ERRNO_EDOM'
489 elif 'errno-erange' in flag_cond:
490 if flag_cond['errno-erange'] != '1':
491 raise ValueError('unexpected condition for errno-erange')
492 errno_expected = 'ERRNO_ERANGE'
493 else:
494 errno_expected = 'ERRNO_UNCHANGED'
495 if 'errno-edom-ok' in flag_cond:
496 if ('errno-erange-ok' in flag_cond
497 and (flag_cond['errno-erange-ok']
498 != flag_cond['errno-edom-ok'])):
499 errno_unknown_cond = ('%s || %s'
500 % (flag_cond['errno-edom-ok'],
501 flag_cond['errno-erange-ok']))
502 else:
503 errno_unknown_cond = flag_cond['errno-edom-ok']
504 else:
505 errno_unknown_cond = flag_cond.get('errno-erange-ok', '0')
506 flags_c.append(cond_value(errno_unknown_cond, '0', errno_expected))
507 flags_c = [flag for flag in flags_c if flag != '0']
508 if not flags_c:
509 flags_c = ['NO_EXCEPTION']
510 this_res.append(' | '.join(flags_c))
511 res_rm.append(this_res)
512 test_list.append(gen_test_args_res(descr_args, descr_res, args,
513 res_rm))
514 test_list.append('#endif\n')
515 return ''.join(test_list)
518 def gen_test_line(descr_args, descr_res, args_str):
519 """Generate C code for the tests for a single TEST_* line."""
520 test_args = args_str.split(',')
521 test_args = test_args[1:]
522 test_args = [a.strip() for a in test_args]
523 num_args = sum([DESCR_NUM_ARGS[c] for c in descr_args])
524 num_res = sum([DESCR_NUM_RES[c] for c in descr_res])
525 args = test_args[:num_args]
526 res = test_args[num_args:]
527 if len(res) == num_res:
528 # One set of results for all rounding modes, no flags.
529 res.append('0')
530 res_rm = [res, res, res, res]
531 elif len(res) == num_res + 1:
532 # One set of results for all rounding modes, with flags.
533 if not ('EXCEPTION' in res[-1]
534 or 'ERRNO' in res[-1]
535 or 'IGNORE_ZERO_INF_SIGN' in res[-1]
536 or 'TEST_NAN_SIGN' in res[-1]
537 or 'NO_TEST_INLINE' in res[-1]
538 or 'XFAIL' in res[-1]):
539 raise ValueError('wrong number of arguments: %s' % args_str)
540 res_rm = [res, res, res, res]
541 elif len(res) == (num_res + 1) * 4:
542 # One set of results per rounding mode, with flags.
543 nr_plus = num_res + 1
544 res_rm = [res[:nr_plus], res[nr_plus:2*nr_plus],
545 res[2*nr_plus:3*nr_plus], res[3*nr_plus:]]
546 return gen_test_args_res(descr_args, descr_res, args, res_rm)
549 def generate_testfile(inc_input, auto_tests, c_output):
550 """Generate test .c file from .inc input."""
551 test_list = []
552 with open(inc_input, 'r') as f:
553 for line in f:
554 line_strip = line.strip()
555 if line_strip.startswith('AUTO_TESTS_'):
556 m = re.match(r'AUTO_TESTS_([^_]*)_([^_ ]*) *\(([^)]*)\),\Z',
557 line_strip)
558 if not m:
559 raise ValueError('bad AUTO_TESTS line: %s' % line)
560 test_list.append(gen_auto_tests(auto_tests, m.group(1),
561 m.group(2), m.group(3)))
562 elif line_strip.startswith('TEST_'):
563 m = re.match(r'TEST_([^_]*)_([^_ ]*) *\((.*)\),\Z', line_strip)
564 if not m:
565 raise ValueError('bad TEST line: %s' % line)
566 test_list.append(gen_test_line(m.group(1), m.group(2),
567 m.group(3)))
568 else:
569 test_list.append(line)
570 with open(c_output, 'w') as f:
571 f.write(''.join(test_list))
574 def main():
575 """The main entry point."""
576 parser = argparse.ArgumentParser(description='Generate libm tests.')
577 parser.add_argument('-a', dest='auto_input', metavar='FILE',
578 help='input file with automatically generated tests')
579 parser.add_argument('-c', dest='inc_input', metavar='FILE',
580 help='input file .inc file with tests')
581 parser.add_argument('-u', dest='ulps_file', metavar='FILE',
582 help='input file with ulps')
583 parser.add_argument('-n', dest='ulps_output', metavar='FILE',
584 help='generate sorted ulps file FILE')
585 parser.add_argument('-C', dest='c_output', metavar='FILE',
586 help='generate output C file FILE from .inc file')
587 parser.add_argument('-H', dest='ulps_header', metavar='FILE',
588 help='generate output ulps header FILE')
589 args = parser.parse_args()
590 ulps = Ulps()
591 if args.ulps_file is not None:
592 ulps.read(args.ulps_file)
593 auto_tests = read_auto_tests(args.auto_input)
594 if args.ulps_output is not None:
595 ulps.write(args.ulps_output)
596 if args.ulps_header is not None:
597 ulps.write_header(args.ulps_header)
598 if args.c_output is not None:
599 generate_testfile(args.inc_input, auto_tests, args.c_output)
602 if __name__ == '__main__':
603 main()