stdlib: Optimization qsort{_r} swap implementation
[glibc.git] / math / gen-tgmath-tests.py
blob0882c7341ab6b5b5bcbceed1c2e4f66f13cc1050
1 #!/usr/bin/python3
2 # Generate tests for <tgmath.h> macros.
3 # Copyright (C) 2017-2023 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/>.
20 # As glibc does not support decimal floating point, the types to
21 # consider for generic parameters are standard and binary
22 # floating-point types, and integer types which are treated as
23 # _Float32x if any argument has a _FloatNx type and otherwise as
24 # double. The corresponding complex types may also be used (including
25 # complex integer types, which are a GNU extension, but are currently
26 # disabled here because they do not work properly with tgmath.h).
28 # C2x makes the <tgmath.h> rules for selecting a function to call
29 # correspond to the usual arithmetic conversions (applied successively
30 # to the arguments for generic parameters in order), which choose the
31 # type whose set of values contains that of the other type (undefined
32 # behavior if neither type's set of values is a superset of the
33 # other), with interchange types being preferred to standard types
34 # (long double, double, float), being preferred to extended types
35 # (_Float128x, _Float64x, _Float32x).
37 # For the standard and binary floating-point types supported by GCC 7
38 # on any platform, this means the resulting type is the last of the
39 # given types in one of the following orders, or undefined behavior if
40 # types with both ibm128 and binary128 representation are specified.
42 # If double = long double: _Float16, float, _Float32, _Float32x,
43 # double, long double, _Float64, _Float64x, _Float128.
45 # Otherwise: _Float16, float, _Float32, _Float32x, double, _Float64,
46 # _Float64x, long double, _Float128.
48 # We generate tests to verify the return type is exactly as expected.
49 # We also verify that the function called is real or complex as
50 # expected, and that it is called for the right floating-point format
51 # (but it is OK to call a double function instead of a long double one
52 # if they have the same format, for example). For all the formats
53 # supported on any given configuration of glibc, the MANT_DIG value
54 # uniquely determines the format.
56 import string
57 import sys
59 class Type(object):
60 """A type that may be used as an argument for generic parameters."""
62 # All possible argument or result types.
63 all_types_list = []
64 # All argument types.
65 argument_types_list = []
66 # All real argument types.
67 real_argument_types_list = []
68 # Real argument types that correspond to a standard floating type
69 # (float, double or long double; not _FloatN or _FloatNx).
70 standard_real_argument_types_list = []
71 # The real floating types by their order properties (which are
72 # tuples giving the positions in both the possible orders above).
73 real_types_order = {}
74 # The type double.
75 double_type = None
76 # The type long double.
77 long_double_type = None
78 # The type _Complex double.
79 complex_double_type = None
80 # The type _Float64.
81 float64_type = None
82 # The type _Complex _Float64.
83 complex_float64_type = None
84 # The type _Float32x.
85 float32x_type = None
86 # The type _Complex _Float32x.
87 complex_float32x_type = None
88 # The type _Float64x.
89 float64x_type = None
91 def __init__(self, name, suffix=None, mant_dig=None, condition='1',
92 order=None, integer=False, complex=False, real_type=None,
93 floatnx=False):
94 """Initialize a Type object, creating any corresponding complex type
95 in the process."""
96 self.name = name
97 self.suffix = suffix
98 self.mant_dig = mant_dig
99 self.condition = condition
100 self.order = order
101 self.integer = integer
102 self.complex = complex
103 self.floatnx = floatnx
104 if complex:
105 self.complex_type = self
106 self.real_type = real_type
107 else:
108 # complex_type filled in by the caller once created.
109 self.complex_type = None
110 self.real_type = self
112 def register_type(self, internal):
113 """Record a type in the lists of all types."""
114 Type.all_types_list.append(self)
115 if not internal:
116 Type.argument_types_list.append(self)
117 if not self.complex:
118 Type.real_argument_types_list.append(self)
119 if not self.name.startswith('_Float'):
120 Type.standard_real_argument_types_list.append(self)
121 if self.order is not None:
122 Type.real_types_order[self.order] = self
123 if self.name == 'double':
124 Type.double_type = self
125 if self.name == 'long double':
126 Type.long_double_type = self
127 if self.name == '_Complex double':
128 Type.complex_double_type = self
129 if self.name == '_Float64':
130 Type.float64_type = self
131 if self.name == '_Complex _Float64':
132 Type.complex_float64_type = self
133 if self.name == '_Float32x':
134 Type.float32x_type = self
135 if self.name == '_Complex _Float32x':
136 Type.complex_float32x_type = self
137 if self.name == '_Float64x':
138 Type.float64x_type = self
140 @staticmethod
141 def create_type(name, suffix=None, mant_dig=None, condition='1', order=None,
142 integer=False, complex_name=None, complex_ok=True,
143 floatnx=False, internal=False):
144 """Create and register a Type object for a real type, creating any
145 corresponding complex type in the process."""
146 real_type = Type(name, suffix=suffix, mant_dig=mant_dig,
147 condition=condition, order=order, integer=integer,
148 complex=False, floatnx=floatnx)
149 if complex_ok:
150 if complex_name is None:
151 complex_name = '_Complex %s' % name
152 complex_type = Type(complex_name, condition=condition,
153 integer=integer, complex=True,
154 real_type=real_type, floatnx=floatnx)
155 else:
156 complex_type = None
157 real_type.complex_type = complex_type
158 real_type.register_type(internal)
159 if complex_type is not None:
160 complex_type.register_type(internal)
162 def floating_type(self, integer_float32x):
163 """Return the corresponding floating type."""
164 if self.integer:
165 if integer_float32x:
166 return (Type.complex_float32x_type
167 if self.complex
168 else Type.float32x_type)
169 else:
170 return (Type.complex_double_type
171 if self.complex
172 else Type.double_type)
173 else:
174 return self
176 def real_floating_type(self, integer_float32x):
177 """Return the corresponding real floating type."""
178 return self.real_type.floating_type(integer_float32x)
180 def __str__(self):
181 """Return string representation of a type."""
182 return self.name
184 @staticmethod
185 def init_types():
186 """Initialize all the known types."""
187 Type.create_type('_Float16', 'f16', 'FLT16_MANT_DIG',
188 complex_name='__CFLOAT16',
189 condition='defined HUGE_VAL_F16', order=(0, 0))
190 Type.create_type('float', 'f', 'FLT_MANT_DIG', order=(1, 1))
191 Type.create_type('_Float32', 'f32', 'FLT32_MANT_DIG',
192 complex_name='__CFLOAT32',
193 condition='defined HUGE_VAL_F32', order=(2, 2))
194 Type.create_type('_Float32x', 'f32x', 'FLT32X_MANT_DIG',
195 complex_name='__CFLOAT32X',
196 condition='defined HUGE_VAL_F32X', order=(3, 3),
197 floatnx=True)
198 Type.create_type('double', '', 'DBL_MANT_DIG', order=(4, 4))
199 Type.create_type('long double', 'l', 'LDBL_MANT_DIG', order=(5, 7))
200 Type.create_type('_Float64', 'f64', 'FLT64_MANT_DIG',
201 complex_name='__CFLOAT64',
202 condition='defined HUGE_VAL_F64', order=(6, 5))
203 Type.create_type('_Float64x', 'f64x', 'FLT64X_MANT_DIG',
204 complex_name='__CFLOAT64X',
205 condition='defined HUGE_VAL_F64X', order=(7, 6),
206 floatnx=True)
207 Type.create_type('_Float128', 'f128', 'FLT128_MANT_DIG',
208 complex_name='__CFLOAT128',
209 condition='defined HUGE_VAL_F128', order=(8, 8))
210 Type.create_type('char', integer=True)
211 Type.create_type('signed char', integer=True)
212 Type.create_type('unsigned char', integer=True)
213 Type.create_type('short int', integer=True)
214 Type.create_type('unsigned short int', integer=True)
215 Type.create_type('int', integer=True)
216 Type.create_type('unsigned int', integer=True)
217 Type.create_type('long int', integer=True)
218 Type.create_type('unsigned long int', integer=True)
219 Type.create_type('long long int', integer=True)
220 Type.create_type('unsigned long long int', integer=True)
221 Type.create_type('__int128', integer=True,
222 condition='defined __SIZEOF_INT128__')
223 Type.create_type('unsigned __int128', integer=True,
224 condition='defined __SIZEOF_INT128__')
225 Type.create_type('enum e', integer=True, complex_ok=False)
226 Type.create_type('_Bool', integer=True, complex_ok=False)
227 Type.create_type('bit_field', integer=True, complex_ok=False)
228 # Internal types represent the combination of long double with
229 # _Float64 or _Float64x, for which the ordering depends on
230 # whether long double has the same format as double.
231 Type.create_type('long_double_Float64', None, 'LDBL_MANT_DIG',
232 complex_name='complex_long_double_Float64',
233 condition='defined HUGE_VAL_F64', order=(6, 7),
234 internal=True)
235 Type.create_type('long_double_Float64x', None, 'FLT64X_MANT_DIG',
236 complex_name='complex_long_double_Float64x',
237 condition='defined HUGE_VAL_F64X', order=(7, 7),
238 internal=True)
240 @staticmethod
241 def can_combine_types(types):
242 """Return a C preprocessor conditional for whether the given list of
243 types can be used together as type-generic macro arguments."""
244 have_long_double = False
245 have_float128 = False
246 integer_float32x = any(t.floatnx for t in types)
247 for t in types:
248 t = t.real_floating_type(integer_float32x)
249 if t.name == 'long double':
250 have_long_double = True
251 if t.name == '_Float128' or t.name == '_Float64x':
252 have_float128 = True
253 if have_long_double and have_float128:
254 # If ibm128 format is in use for long double, both
255 # _Float64x and _Float128 are binary128 and the types
256 # cannot be combined.
257 return '(LDBL_MANT_DIG != 106)'
258 return '1'
260 @staticmethod
261 def combine_types(types):
262 """Return the result of combining a set of types."""
263 have_complex = False
264 combined = None
265 integer_float32x = any(t.floatnx for t in types)
266 for t in types:
267 if t.complex:
268 have_complex = True
269 t = t.real_floating_type(integer_float32x)
270 if combined is None:
271 combined = t
272 else:
273 order = (max(combined.order[0], t.order[0]),
274 max(combined.order[1], t.order[1]))
275 combined = Type.real_types_order[order]
276 return combined.complex_type if have_complex else combined
278 def list_product_initial(initial, lists):
279 """Return a list of lists, with an initial sequence from the first
280 argument (a list of lists) followed by each sequence of one
281 element from each successive element of the second argument."""
282 if not lists:
283 return initial
284 return list_product_initial([a + [b] for a in initial for b in lists[0]],
285 lists[1:])
287 def list_product(lists):
288 """Return a list of lists, with each sequence of one element from each
289 successive element of the argument."""
290 return list_product_initial([[]], lists)
292 try:
293 trans_id = str.maketrans(' *', '_p')
294 except AttributeError:
295 trans_id = string.maketrans(' *', '_p')
296 def var_for_type(name):
297 """Return the name of a variable with a given type (name)."""
298 return 'var_%s' % name.translate(trans_id)
300 def vol_var_for_type(name):
301 """Return the name of a variable with a given volatile type (name)."""
302 return 'vol_var_%s' % name.translate(trans_id)
304 def define_vars_for_type(name):
305 """Return the definitions of variables with a given type (name)."""
306 if name == 'bit_field':
307 struct_vars = define_vars_for_type('struct s');
308 return '%s#define %s %s.bf\n' % (struct_vars,
309 vol_var_for_type(name),
310 vol_var_for_type('struct s'))
311 return ('%s %s __attribute__ ((unused));\n'
312 '%s volatile %s __attribute__ ((unused));\n'
313 % (name, var_for_type(name), name, vol_var_for_type(name)))
315 def if_cond_text(conds, text):
316 """Return the result of making some text conditional under #if. The
317 text ends with a newline, as does the return value if not empty."""
318 if '0' in conds:
319 return ''
320 conds = [c for c in conds if c != '1']
321 conds = sorted(set(conds))
322 if not conds:
323 return text
324 return '#if %s\n%s#endif\n' % (' && '.join(conds), text)
326 class Tests(object):
327 """The state associated with testcase generation."""
329 def __init__(self):
330 """Initialize a Tests object."""
331 self.header_list = ['#define __STDC_WANT_IEC_60559_TYPES_EXT__\n'
332 '#include <float.h>\n'
333 '#include <stdbool.h>\n'
334 '#include <stdint.h>\n'
335 '#include <stdio.h>\n'
336 '#include <string.h>\n'
337 '#include <tgmath.h>\n'
338 '\n'
339 'struct test\n'
340 ' {\n'
341 ' void (*func) (void);\n'
342 ' const char *func_name;\n'
343 ' const char *test_name;\n'
344 ' int mant_dig;\n'
345 ' int narrow_mant_dig;\n'
346 ' };\n'
347 'int num_pass, num_fail;\n'
348 'volatile int called_mant_dig;\n'
349 'const char *volatile called_func_name;\n'
350 'enum e { E, F };\n'
351 'struct s\n'
352 ' {\n'
353 ' int bf:2;\n'
354 ' };\n']
355 float64_text = ('# if LDBL_MANT_DIG == DBL_MANT_DIG\n'
356 'typedef _Float64 long_double_Float64;\n'
357 'typedef __CFLOAT64 complex_long_double_Float64;\n'
358 '# else\n'
359 'typedef long double long_double_Float64;\n'
360 'typedef _Complex long double '
361 'complex_long_double_Float64;\n'
362 '# endif\n')
363 float64_text = if_cond_text([Type.float64_type.condition],
364 float64_text)
365 float64x_text = ('# if LDBL_MANT_DIG == DBL_MANT_DIG\n'
366 'typedef _Float64x long_double_Float64x;\n'
367 'typedef __CFLOAT64X complex_long_double_Float64x;\n'
368 '# else\n'
369 'typedef long double long_double_Float64x;\n'
370 'typedef _Complex long double '
371 'complex_long_double_Float64x;\n'
372 '# endif\n')
373 float64x_text = if_cond_text([Type.float64x_type.condition],
374 float64x_text)
375 self.header_list.append(float64_text)
376 self.header_list.append(float64x_text)
377 self.types_seen = set()
378 for t in Type.all_types_list:
379 self.add_type_var(t.name, t.condition)
380 self.test_text_list = []
381 self.test_array_list = []
382 self.macros_seen = set()
384 def add_type_var(self, name, cond):
385 """Add declarations of variables for a type."""
386 if name in self.types_seen:
387 return
388 t_vars = define_vars_for_type(name)
389 self.header_list.append(if_cond_text([cond], t_vars))
390 self.types_seen.add(name)
392 def add_tests(self, macro, ret, args, complex_func=None):
393 """Add tests for a given tgmath.h macro, if that is the macro for
394 which tests are to be generated; otherwise just add it to the
395 list of macros for which test generation is supported."""
396 # 'c' means the function argument or return type is
397 # type-generic and complex only (a complex function argument
398 # may still have a real macro argument). 'g' means it is
399 # type-generic and may be real or complex; 'r' means it is
400 # type-generic and may only be real; 's' means the same as
401 # 'r', but restricted to float, double and long double.
402 self.macros_seen.add(macro)
403 if macro != self.macro:
404 return
405 have_complex = False
406 func = macro
407 narrowing = False
408 narrowing_std = False
409 if ret == 'c' or 'c' in args:
410 # Complex-only.
411 have_complex = True
412 complex_func = func
413 func = None
414 elif ret == 'g' or 'g' in args:
415 # Real and complex.
416 have_complex = True
417 if complex_func == None:
418 complex_func = 'c%s' % func
419 # For narrowing macros, compute narrow_args, the list of
420 # argument types for which there is an actual corresponding
421 # function. If none of those types exist, or the return type
422 # does not exist, then the macro is not defined and no tests
423 # of it can be run.
424 if ret == 'float':
425 narrowing = True
426 narrowing_std = True
427 narrow_cond = '1'
428 narrow_args = [Type.double_type, Type.long_double_type]
429 elif ret == 'double':
430 narrowing = True
431 narrowing_std = True
432 narrow_cond = '1'
433 narrow_args = [Type.long_double_type]
434 elif ret.startswith('_Float'):
435 narrowing = True
436 narrow_args_1 = []
437 narrow_args_2 = []
438 nret_type = None
439 for order, real_type in sorted(Type.real_types_order.items()):
440 if real_type.name == ret:
441 nret_type = real_type
442 elif nret_type and real_type.name.startswith('_Float'):
443 if ret.endswith('x') == real_type.name.endswith('x'):
444 narrow_args_1.append(real_type)
445 else:
446 narrow_args_2.append(real_type)
447 narrow_args = narrow_args_1 + narrow_args_2
448 if narrow_args:
449 narrow_cond = ('(%s && (%s))'
450 % (nret_type.condition,
451 ' || '.join(t.condition
452 for t in narrow_args)))
453 else:
454 # No possible argument types, even conditionally.
455 narrow_cond = '0'
456 types = [ret] + args
457 for t in types:
458 if t != 'c' and t != 'g' and t != 'r' and t != 's':
459 self.add_type_var(t, '1')
460 for t in Type.argument_types_list:
461 if t.integer:
462 continue
463 if t.complex and not have_complex:
464 continue
465 if func == None and not t.complex:
466 continue
467 if ret == 's' and t.name.startswith('_Float'):
468 continue
469 if narrowing and t not in narrow_args:
470 continue
471 if ret == 'c':
472 ret_name = t.complex_type.name
473 elif ret == 'g':
474 ret_name = t.name
475 elif ret == 'r' or ret == 's':
476 ret_name = t.real_type.name
477 else:
478 ret_name = ret
479 dummy_func_name = complex_func if t.complex else func
480 arg_list = []
481 arg_num = 0
482 for a in args:
483 if a == 'c':
484 arg_name = t.complex_type.name
485 elif a == 'g':
486 arg_name = t.name
487 elif a == 'r' or a == 's':
488 arg_name = t.real_type.name
489 else:
490 arg_name = a
491 arg_list.append('%s arg%d __attribute__ ((unused))'
492 % (arg_name, arg_num))
493 arg_num += 1
494 dummy_func = ('%s\n'
495 '(%s%s) (%s)\n'
496 '{\n'
497 ' called_mant_dig = %s;\n'
498 ' called_func_name = "%s";\n'
499 ' return 0;\n'
500 '}\n' % (ret_name, dummy_func_name,
501 t.real_type.suffix, ', '.join(arg_list),
502 t.real_type.mant_dig, dummy_func_name))
503 if narrowing:
504 dummy_cond = [narrow_cond, t.condition]
505 else:
506 dummy_cond = [t.condition]
507 dummy_func = if_cond_text(dummy_cond, dummy_func)
508 self.test_text_list.append(dummy_func)
509 arg_types = []
510 for t in args:
511 if t == 'g' or t == 'c':
512 arg_types.append(Type.argument_types_list)
513 elif t == 'r':
514 arg_types.append(Type.real_argument_types_list)
515 elif t == 's':
516 arg_types.append(Type.standard_real_argument_types_list)
517 arg_types_product = list_product(arg_types)
518 test_num = 0
519 for this_args in arg_types_product:
520 comb_type = Type.combine_types(this_args)
521 if narrowing:
522 # As long as there are no integer arguments, and as
523 # long as the chosen argument type is as wide as all
524 # the floating-point arguments passed, the semantics
525 # of the macro call do not depend on the exact
526 # function chosen. In particular, for f32x functions
527 # when _Float64x exists, the chosen type should differ
528 # for double / _Float32x and _Float64 arguments, but
529 # it is not always possible to distinguish those types
530 # before GCC 7 (resulting in some cases - only real
531 # arguments - where a wider argument type is used,
532 # which is semantically OK, and others - integer
533 # arguments present - where it may not be OK, but is
534 # unavoidable).
535 narrow_mant_dig = comb_type.real_type.mant_dig
536 for arg_type in this_args:
537 if arg_type.integer:
538 narrow_mant_dig = 0
539 else:
540 narrow_mant_dig = 0
541 can_comb = Type.can_combine_types(this_args)
542 all_conds = [t.condition for t in this_args]
543 narrow_args_cond = '(%s)' % ' && '.join(sorted(set(all_conds)))
544 all_conds.append(can_comb)
545 if narrowing:
546 all_conds.append(narrow_cond)
547 any_complex = func == None
548 for t in this_args:
549 if t.complex:
550 any_complex = True
551 func_name = complex_func if any_complex else func
552 test_name = '%s (%s)' % (macro,
553 ', '.join([t.name for t in this_args]))
554 test_func_name = 'test_%s_%d' % (macro, test_num)
555 test_num += 1
556 mant_dig = comb_type.real_type.mant_dig
557 test_mant_dig_comp = ''
558 if (narrowing
559 and comb_type not in narrow_args):
560 # The expected argument type is the first in
561 # narrow_args that can represent all the values of
562 # comb_type (which, for the supported cases, means the
563 # first with mant_dig at least as large as that for
564 # comb_type, provided this isn't the case of an IBM
565 # long double argument with binary128 type from
566 # narrow_args).
567 narrow_extra_conds = []
568 test_mant_dig_list = ['#undef NARROW_MANT_DIG\n#if 0\n']
569 for t in narrow_args:
570 t_cond = '(%s && %s && %s <= %s && %s)' % (
571 narrow_args_cond, t.condition, mant_dig, t.mant_dig,
572 Type.can_combine_types(this_args + [t]))
573 narrow_extra_conds.append(t_cond)
574 test_mant_dig_list.append('#elif %s\n'
575 '#define NARROW_MANT_DIG %s\n'
576 % (t_cond, t.mant_dig))
577 test_mant_dig_list.append('#endif\n')
578 test_mant_dig_comp = ''.join(test_mant_dig_list)
579 all_conds.append('(%s)' % ' || '.join(narrow_extra_conds))
580 # A special case where this logic isn't correct is
581 # where comb_type is the internal long_double_Float64
582 # or long_double_Float64x, which will be detected as
583 # not in narrow_args even if the actual type chosen in
584 # a particular configuration would have been in
585 # narrow_args, so check for that case and handle it
586 # appropriately. In particular, if long double has
587 # the same format as double and there are long double
588 # and _Float64 arguments, and the macro returns
589 # _Float32x, the function called should be one for
590 # _Float64 arguments, not one for _Float64x arguments
591 # that would arise from this logic.
592 if comb_type.real_type.name == 'long_double_Float64':
593 comb_type_1 = Type.long_double_type
594 comb_type_2 = Type.float64_type
595 comb_type_is_2_cond = 'LDBL_MANT_DIG <= FLT64_MANT_DIG'
596 elif comb_type.real_type.name == 'long_double_Float64x':
597 comb_type_1 = Type.long_double_type
598 comb_type_2 = Type.float64x_type
599 comb_type_is_2_cond = 'LDBL_MANT_DIG < FLT64X_MANT_DIG'
600 else:
601 comb_type_1 = None
602 comb_type_2 = None
603 if comb_type_1 is None:
604 mant_dig = 'NARROW_MANT_DIG'
605 else:
606 mant_dig = ''
607 if comb_type_1 in narrow_args:
608 mant_dig += '!(%s) ? %s : ' % (comb_type_is_2_cond,
609 comb_type_1.mant_dig)
610 if comb_type_2 in narrow_args:
611 mant_dig += '%s ? %s : ' % (comb_type_is_2_cond,
612 comb_type_2.mant_dig)
613 mant_dig += 'NARROW_MANT_DIG'
614 if narrow_mant_dig != 0:
615 narrow_mant_dig = mant_dig
616 test_text = '%s, "%s", "%s", %s, %s' % (test_func_name, func_name,
617 test_name, mant_dig,
618 narrow_mant_dig)
619 test_text = '%s { %s },\n' % (test_mant_dig_comp, test_text)
620 test_text = if_cond_text(all_conds, test_text)
621 self.test_array_list.append(test_text)
622 call_args = []
623 call_arg_pos = 0
624 for t in args:
625 if t == 'g' or t == 'c' or t == 'r' or t == 's':
626 type = this_args[call_arg_pos].name
627 call_arg_pos += 1
628 else:
629 type = t
630 call_args.append(vol_var_for_type(type))
631 call_args_text = ', '.join(call_args)
632 if ret == 'g':
633 ret_type = comb_type.name
634 elif ret == 'r' or ret == 's':
635 ret_type = comb_type.real_type.name
636 elif ret == 'c':
637 ret_type = comb_type.complex_type.name
638 else:
639 ret_type = ret
640 call_text = '%s (%s)' % (macro, call_args_text)
641 test_func_text = ('static void\n'
642 '%s (void)\n'
643 '{\n'
644 ' extern typeof (%s) %s '
645 '__attribute__ ((unused));\n'
646 ' %s = %s;\n'
647 '}\n' % (test_func_name, call_text,
648 var_for_type(ret_type),
649 vol_var_for_type(ret_type), call_text))
650 test_func_text = if_cond_text(all_conds, test_func_text)
651 self.test_text_list.append(test_func_text)
653 def add_all_tests(self, macro):
654 """Add tests for the given tgmath.h macro, if any, and generate the
655 list of all supported macros."""
656 self.macro = macro
657 # C99/C11 real-only functions.
658 self.add_tests('atan2', 'r', ['r', 'r'])
659 self.add_tests('cbrt', 'r', ['r'])
660 self.add_tests('ceil', 'r', ['r'])
661 self.add_tests('copysign', 'r', ['r', 'r'])
662 self.add_tests('erf', 'r', ['r'])
663 self.add_tests('erfc', 'r', ['r'])
664 self.add_tests('exp2', 'r', ['r'])
665 self.add_tests('expm1', 'r', ['r'])
666 self.add_tests('fdim', 'r', ['r', 'r'])
667 self.add_tests('floor', 'r', ['r'])
668 self.add_tests('fma', 'r', ['r', 'r', 'r'])
669 self.add_tests('fmax', 'r', ['r', 'r'])
670 self.add_tests('fmin', 'r', ['r', 'r'])
671 self.add_tests('fmod', 'r', ['r', 'r'])
672 self.add_tests('frexp', 'r', ['r', 'int *'])
673 self.add_tests('hypot', 'r', ['r', 'r'])
674 self.add_tests('ilogb', 'int', ['r'])
675 self.add_tests('ldexp', 'r', ['r', 'int'])
676 self.add_tests('lgamma', 'r', ['r'])
677 self.add_tests('llrint', 'long long int', ['r'])
678 self.add_tests('llround', 'long long int', ['r'])
679 # log10 is real-only in ISO C, but supports complex arguments
680 # as a GNU extension.
681 self.add_tests('log10', 'g', ['g'])
682 self.add_tests('log1p', 'r', ['r'])
683 self.add_tests('log2', 'r', ['r'])
684 self.add_tests('logb', 'r', ['r'])
685 self.add_tests('lrint', 'long int', ['r'])
686 self.add_tests('lround', 'long int', ['r'])
687 self.add_tests('nearbyint', 'r', ['r'])
688 self.add_tests('nextafter', 'r', ['r', 'r'])
689 self.add_tests('nexttoward', 's', ['s', 'long double'])
690 self.add_tests('remainder', 'r', ['r', 'r'])
691 self.add_tests('remquo', 'r', ['r', 'r', 'int *'])
692 self.add_tests('rint', 'r', ['r'])
693 self.add_tests('round', 'r', ['r'])
694 self.add_tests('scalbn', 'r', ['r', 'int'])
695 self.add_tests('scalbln', 'r', ['r', 'long int'])
696 self.add_tests('tgamma', 'r', ['r'])
697 self.add_tests('trunc', 'r', ['r'])
698 # C99/C11 real-and-complex functions.
699 self.add_tests('acos', 'g', ['g'])
700 self.add_tests('asin', 'g', ['g'])
701 self.add_tests('atan', 'g', ['g'])
702 self.add_tests('acosh', 'g', ['g'])
703 self.add_tests('asinh', 'g', ['g'])
704 self.add_tests('atanh', 'g', ['g'])
705 self.add_tests('cos', 'g', ['g'])
706 self.add_tests('sin', 'g', ['g'])
707 self.add_tests('tan', 'g', ['g'])
708 self.add_tests('cosh', 'g', ['g'])
709 self.add_tests('sinh', 'g', ['g'])
710 self.add_tests('tanh', 'g', ['g'])
711 self.add_tests('exp', 'g', ['g'])
712 self.add_tests('log', 'g', ['g'])
713 self.add_tests('pow', 'g', ['g', 'g'])
714 self.add_tests('sqrt', 'g', ['g'])
715 self.add_tests('fabs', 'r', ['g'], 'cabs')
716 # C99/C11 complex-only functions.
717 self.add_tests('carg', 'r', ['c'])
718 self.add_tests('cimag', 'r', ['c'])
719 self.add_tests('conj', 'c', ['c'])
720 self.add_tests('cproj', 'c', ['c'])
721 self.add_tests('creal', 'r', ['c'])
722 # TS 18661-1 functions.
723 self.add_tests('roundeven', 'r', ['r'])
724 self.add_tests('nextup', 'r', ['r'])
725 self.add_tests('nextdown', 'r', ['r'])
726 self.add_tests('fminmag', 'r', ['r', 'r'])
727 self.add_tests('fmaxmag', 'r', ['r', 'r'])
728 self.add_tests('llogb', 'long int', ['r'])
729 self.add_tests('fromfp', 'intmax_t', ['r', 'int', 'unsigned int'])
730 self.add_tests('fromfpx', 'intmax_t', ['r', 'int', 'unsigned int'])
731 self.add_tests('ufromfp', 'uintmax_t', ['r', 'int', 'unsigned int'])
732 self.add_tests('ufromfpx', 'uintmax_t', ['r', 'int', 'unsigned int'])
733 for fn, args in (('add', 2), ('div', 2), ('fma', 3), ('mul', 2),
734 ('sqrt', 1), ('sub', 2)):
735 for ret, prefix in (('float', 'f'),
736 ('double', 'd'),
737 ('_Float16', 'f16'),
738 ('_Float32', 'f32'),
739 ('_Float64', 'f64'),
740 ('_Float128', 'f128'),
741 ('_Float32x', 'f32x'),
742 ('_Float64x', 'f64x')):
743 self.add_tests(prefix + fn, ret, ['r'] * args)
744 # TS 18661-4 functions.
745 self.add_tests('exp10', 'r', ['r'])
746 # C2X functions.
747 self.add_tests('fmaximum', 'r', ['r', 'r'])
748 self.add_tests('fmaximum_mag', 'r', ['r', 'r'])
749 self.add_tests('fmaximum_num', 'r', ['r', 'r'])
750 self.add_tests('fmaximum_mag_num', 'r', ['r', 'r'])
751 self.add_tests('fminimum', 'r', ['r', 'r'])
752 self.add_tests('fminimum_mag', 'r', ['r', 'r'])
753 self.add_tests('fminimum_num', 'r', ['r', 'r'])
754 self.add_tests('fminimum_mag_num', 'r', ['r', 'r'])
755 # Miscellaneous functions.
756 self.add_tests('scalb', 's', ['s', 's'])
758 def tests_text(self):
759 """Return the text of the generated testcase."""
760 test_list = [''.join(self.test_text_list),
761 'static const struct test tests[] =\n'
762 ' {\n',
763 ''.join(self.test_array_list),
764 ' };\n']
765 footer_list = ['static int\n'
766 'do_test (void)\n'
767 '{\n'
768 ' for (size_t i = 0;\n'
769 ' i < sizeof (tests) / sizeof (tests[0]);\n'
770 ' i++)\n'
771 ' {\n'
772 ' called_mant_dig = 0;\n'
773 ' called_func_name = "";\n'
774 ' tests[i].func ();\n'
775 ' if (called_mant_dig == tests[i].mant_dig\n'
776 ' && strcmp (called_func_name,\n'
777 ' tests[i].func_name) == 0)\n'
778 ' num_pass++;\n'
779 '#if !__GNUC_PREREQ (7, 0)\n'
780 ' else if (tests[i].narrow_mant_dig > 0\n'
781 ' && (called_mant_dig\n'
782 ' >= tests[i].narrow_mant_dig)\n'
783 ' && strcmp (called_func_name,\n'
784 ' tests[i].func_name) == 0)\n'
785 ' {\n'
786 ' num_pass++;\n'
787 ' printf ("Test %zu (%s):\\n"\n'
788 ' " Expected: %s precision %d\\n"\n'
789 ' " Actual: %s precision %d\\n"\n'
790 ' " (OK with old GCC)\\n\\n",\n'
791 ' i, tests[i].test_name,\n'
792 ' tests[i].func_name,\n'
793 ' tests[i].mant_dig,\n'
794 ' called_func_name, called_mant_dig);\n'
795 ' }\n'
796 ' else if (tests[i].narrow_mant_dig == 0\n'
797 ' && strcmp (called_func_name,\n'
798 ' tests[i].func_name) == 0)\n'
799 ' {\n'
800 ' num_pass++;\n'
801 ' printf ("Test %zu (%s):\\n"\n'
802 ' " Expected: %s precision %d\\n"\n'
803 ' " Actual: %s precision %d\\n"\n'
804 ' " (unavoidable with old GCC)'
805 '\\n\\n",\n'
806 ' i, tests[i].test_name,\n'
807 ' tests[i].func_name,\n'
808 ' tests[i].mant_dig,\n'
809 ' called_func_name, called_mant_dig);\n'
810 ' }\n'
811 '#endif\n'
812 ' else\n'
813 ' {\n'
814 ' num_fail++;\n'
815 ' printf ("Test %zu (%s):\\n"\n'
816 ' " Expected: %s precision %d\\n"\n'
817 ' " Actual: %s precision %d\\n\\n",\n'
818 ' i, tests[i].test_name,\n'
819 ' tests[i].func_name,\n'
820 ' tests[i].mant_dig,\n'
821 ' called_func_name, called_mant_dig);\n'
822 ' }\n'
823 ' }\n'
824 ' printf ("%d pass, %d fail\\n", num_pass, num_fail);\n'
825 ' return num_fail != 0;\n'
826 '}\n'
827 '\n'
828 '#include <support/test-driver.c>']
829 return ''.join(self.header_list + test_list + footer_list)
831 def check_macro_list(self, macro_list):
832 """Check the list of macros that can be tested."""
833 if self.macros_seen != set(macro_list):
834 print('error: macro list mismatch')
835 sys.exit(1)
837 def main():
838 """The main entry point."""
839 Type.init_types()
840 t = Tests()
841 if sys.argv[1] == 'check-list':
842 macro = None
843 macro_list = sys.argv[2:]
844 else:
845 macro = sys.argv[1]
846 macro_list = []
847 t.add_all_tests(macro)
848 if macro:
849 print(t.tests_text())
850 else:
851 t.check_macro_list(macro_list)
853 if __name__ == '__main__':
854 main()