]> git.ipfire.org Git - thirdparty/glibc.git/blame - math/gen-tgmath-tests.py
treewide: python-scripts: use `is None` for none-equality
[thirdparty/glibc.git] / math / gen-tgmath-tests.py
CommitLineData
4f88b380 1#!/usr/bin/python3
2dd0aec5 2# Generate tests for <tgmath.h> macros.
dff8da6b 3# Copyright (C) 2017-2024 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
8a78f833
JM
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).
2dd0aec5 27
42cc619d 28# C23 makes the <tgmath.h> rules for selecting a function to call
2dd0aec5
JM
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).
36
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.
41
42# If double = long double: _Float16, float, _Float32, _Float32x,
43# double, long double, _Float64, _Float64x, _Float128.
44
45# Otherwise: _Float16, float, _Float32, _Float32x, double, _Float64,
46# _Float64x, long double, _Float128.
47
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.
55
56import string
7c67e6e8 57import sys
2dd0aec5
JM
58
59class Type(object):
60 """A type that may be used as an argument for generic parameters."""
61
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
f9fabc1b
JM
76 # The type long double.
77 long_double_type = None
2dd0aec5
JM
78 # The type _Complex double.
79 complex_double_type = None
80 # The type _Float64.
81 float64_type = None
f9fabc1b
JM
82 # The type _Complex _Float64.
83 complex_float64_type = None
8a78f833
JM
84 # The type _Float32x.
85 float32x_type = None
86 # The type _Complex _Float32x.
87 complex_float32x_type = None
2dd0aec5
JM
88 # The type _Float64x.
89 float64x_type = None
90
91 def __init__(self, name, suffix=None, mant_dig=None, condition='1',
8a78f833
JM
92 order=None, integer=False, complex=False, real_type=None,
93 floatnx=False):
2dd0aec5
JM
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
8a78f833 103 self.floatnx = floatnx
2dd0aec5
JM
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
111
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
f9fabc1b
JM
125 if self.name == 'long double':
126 Type.long_double_type = self
2dd0aec5
JM
127 if self.name == '_Complex double':
128 Type.complex_double_type = self
129 if self.name == '_Float64':
130 Type.float64_type = self
f9fabc1b
JM
131 if self.name == '_Complex _Float64':
132 Type.complex_float64_type = self
8a78f833
JM
133 if self.name == '_Float32x':
134 Type.float32x_type = self
135 if self.name == '_Complex _Float32x':
136 Type.complex_float32x_type = self
2dd0aec5
JM
137 if self.name == '_Float64x':
138 Type.float64x_type = self
139
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,
8a78f833 143 floatnx=False, internal=False):
2dd0aec5
JM
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,
8a78f833 148 complex=False, floatnx=floatnx)
d9bef9c0 149 if complex_ok:
2dd0aec5
JM
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,
8a78f833 154 real_type=real_type, floatnx=floatnx)
2dd0aec5
JM
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)
161
8a78f833 162 def floating_type(self, integer_float32x):
2dd0aec5
JM
163 """Return the corresponding floating type."""
164 if self.integer:
8a78f833
JM
165 if integer_float32x:
166 return (Type.complex_float32x_type
f9fabc1b 167 if self.complex
8a78f833 168 else Type.float32x_type)
f9fabc1b
JM
169 else:
170 return (Type.complex_double_type
171 if self.complex
172 else Type.double_type)
2dd0aec5
JM
173 else:
174 return self
175
8a78f833 176 def real_floating_type(self, integer_float32x):
2dd0aec5 177 """Return the corresponding real floating type."""
8a78f833 178 return self.real_type.floating_type(integer_float32x)
2dd0aec5
JM
179
180 def __str__(self):
181 """Return string representation of a type."""
182 return self.name
183
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',
614d15f9 189 condition='defined HUGE_VAL_F16', order=(0, 0))
2dd0aec5
JM
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',
614d15f9 193 condition='defined HUGE_VAL_F32', order=(2, 2))
2dd0aec5
JM
194 Type.create_type('_Float32x', 'f32x', 'FLT32X_MANT_DIG',
195 complex_name='__CFLOAT32X',
8a78f833
JM
196 condition='defined HUGE_VAL_F32X', order=(3, 3),
197 floatnx=True)
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',
8a78f833
JM
205 condition='defined HUGE_VAL_F64X', order=(7, 6),
206 floatnx=True)
2dd0aec5
JM
207 Type.create_type('_Float128', 'f128', 'FLT128_MANT_DIG',
208 complex_name='__CFLOAT128',
614d15f9 209 condition='defined HUGE_VAL_F128', order=(8, 8))
2dd0aec5
JM
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)
42df8d59
JM
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__')
2dd0aec5
JM
225 Type.create_type('enum e', integer=True, complex_ok=False)
226 Type.create_type('_Bool', integer=True, complex_ok=False)
2fee621d 227 Type.create_type('bit_field', integer=True, complex_ok=False)
2dd0aec5
JM
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.
01e659e7 231 Type.create_type('long_double_Float64', None, 'LDBL_MANT_DIG',
2dd0aec5 232 complex_name='complex_long_double_Float64',
614d15f9
JM
233 condition='defined HUGE_VAL_F64', order=(6, 7),
234 internal=True)
01e659e7 235 Type.create_type('long_double_Float64x', None, 'FLT64X_MANT_DIG',
2dd0aec5 236 complex_name='complex_long_double_Float64x',
614d15f9
JM
237 condition='defined HUGE_VAL_F64X', order=(7, 7),
238 internal=True)
2dd0aec5
JM
239
240 @staticmethod
8a78f833 241 def can_combine_types(types):
2dd0aec5
JM
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
8a78f833 246 integer_float32x = any(t.floatnx for t in types)
2dd0aec5 247 for t in types:
8a78f833 248 t = t.real_floating_type(integer_float32x)
2dd0aec5
JM
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'
259
260 @staticmethod
8a78f833 261 def combine_types(types):
2dd0aec5
JM
262 """Return the result of combining a set of types."""
263 have_complex = False
264 combined = None
8a78f833 265 integer_float32x = any(t.floatnx for t in types)
2dd0aec5
JM
266 for t in types:
267 if t.complex:
268 have_complex = True
8a78f833 269 t = t.real_floating_type(integer_float32x)
2dd0aec5
JM
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
277
278def 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:])
286
287def 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)
291
292try:
293 trans_id = str.maketrans(' *', '_p')
294except AttributeError:
295 trans_id = string.maketrans(' *', '_p')
296def var_for_type(name):
297 """Return the name of a variable with a given type (name)."""
298 return 'var_%s' % name.translate(trans_id)
299
300def 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)
303
304def define_vars_for_type(name):
305 """Return the definitions of variables with a given type (name)."""
2fee621d
JM
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'))
2dd0aec5
JM
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)))
314
315def 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)
325
326class Tests(object):
327 """The state associated with testcase generation."""
328
329 def __init__(self):
330 """Initialize a Tests object."""
fa562680
JM
331 self.header_list = ['#define __STDC_WANT_IEC_60559_TYPES_EXT__\n'
332 '#include <float.h>\n'
2dd0aec5
JM
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'
f9fabc1b 345 ' int narrow_mant_dig;\n'
2dd0aec5
JM
346 ' };\n'
347 'int num_pass, num_fail;\n'
348 'volatile int called_mant_dig;\n'
349 'const char *volatile called_func_name;\n'
2fee621d
JM
350 'enum e { E, F };\n'
351 'struct s\n'
352 ' {\n'
353 ' int bf:2;\n'
354 ' };\n']
2dd0aec5
JM
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 = []
7c67e6e8 382 self.macros_seen = set()
2dd0aec5
JM
383
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)
391
392 def add_tests(self, macro, ret, args, complex_func=None):
7c67e6e8
JM
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."""
2dd0aec5
JM
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.
7c67e6e8
JM
402 self.macros_seen.add(macro)
403 if macro != self.macro:
404 return
2dd0aec5
JM
405 have_complex = False
406 func = macro
f9fabc1b
JM
407 narrowing = False
408 narrowing_std = False
2dd0aec5
JM
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
fe00366b 417 if complex_func is None:
2dd0aec5 418 complex_func = 'c%s' % func
f9fabc1b
JM
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]
f9fabc1b
JM
429 elif ret == 'double':
430 narrowing = True
431 narrowing_std = True
432 narrow_cond = '1'
433 narrow_args = [Type.long_double_type]
f9fabc1b
JM
434 elif ret.startswith('_Float'):
435 narrowing = True
8a78f833
JM
436 narrow_args_1 = []
437 narrow_args_2 = []
f9fabc1b 438 nret_type = None
f9fabc1b
JM
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'):
8a78f833
JM
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
f9fabc1b
JM
448 if narrow_args:
449 narrow_cond = ('(%s && (%s))'
450 % (nret_type.condition,
451 ' || '.join(t.condition
452 for t in narrow_args)))
f9fabc1b
JM
453 else:
454 # No possible argument types, even conditionally.
455 narrow_cond = '0'
2dd0aec5
JM
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
fe00366b 465 if func is None and not t.complex:
2dd0aec5
JM
466 continue
467 if ret == 's' and t.name.startswith('_Float'):
468 continue
f9fabc1b
JM
469 if narrowing and t not in narrow_args:
470 continue
2dd0aec5
JM
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))
f9fabc1b
JM
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)
2dd0aec5
JM
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':
8a78f833 514 arg_types.append(Type.real_argument_types_list)
2dd0aec5
JM
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:
8a78f833 520 comb_type = Type.combine_types(this_args)
f9fabc1b
JM
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
8a78f833
JM
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).
f9fabc1b
JM
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
8a78f833 541 can_comb = Type.can_combine_types(this_args)
2dd0aec5 542 all_conds = [t.condition for t in this_args]
8a78f833 543 narrow_args_cond = '(%s)' % ' && '.join(sorted(set(all_conds)))
2dd0aec5 544 all_conds.append(can_comb)
f9fabc1b
JM
545 if narrowing:
546 all_conds.append(narrow_cond)
fe00366b 547 any_complex = func is None
2dd0aec5
JM
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
8a78f833
JM
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
f9fabc1b
JM
616 test_text = '%s, "%s", "%s", %s, %s' % (test_func_name, func_name,
617 test_name, mant_dig,
618 narrow_mant_dig)
8a78f833 619 test_text = '%s { %s },\n' % (test_mant_dig_comp, test_text)
2dd0aec5
JM
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)
652
7c67e6e8
JM
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
2dd0aec5
JM
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'])
0908a38a
JM
679 # log10 is real-only in ISO C, but supports complex arguments
680 # as a GNU extension.
681 self.add_tests('log10', 'g', ['g'])
2dd0aec5
JM
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'])
b3f27d81
JM
733 for fn, args in (('add', 2), ('div', 2), ('fma', 3), ('mul', 2),
734 ('sqrt', 1), ('sub', 2)):
f9fabc1b
JM
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')):
abd38358 743 self.add_tests(prefix + fn, ret, ['r'] * args)
52c057e3
JM
744 # TS 18661-4 functions.
745 self.add_tests('exp10', 'r', ['r'])
42cc619d 746 # C23 functions.
90f0ac10
JM
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'])
2dd0aec5
JM
755 # Miscellaneous functions.
756 self.add_tests('scalb', 's', ['s', 's'])
757
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'
8a78f833 779 '#if !__GNUC_PREREQ (7, 0)\n'
f9fabc1b
JM
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'
8a78f833
JM
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'
f9fabc1b 811 '#endif\n'
2dd0aec5
JM
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)
830
7c67e6e8
JM
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)
836
2dd0aec5
JM
837def main():
838 """The main entry point."""
839 Type.init_types()
840 t = Tests()
7c67e6e8
JM
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)
2dd0aec5
JM
852
853if __name__ == '__main__':
854 main()