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