C2x semantics for <tgmath.h>
[platform/upstream/glibc.git] / math / gen-tgmath-tests.py
1 #!/usr/bin/python3
2 # Generate tests for <tgmath.h> macros.
3 # Copyright (C) 2017-2022 Free Software Foundation, Inc.
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
18 # <https://www.gnu.org/licenses/>.
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
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).
27
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).
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
56 import string
57 import sys
58
59 class 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
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
90
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
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
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
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,
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)
161
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
175
176     def real_floating_type(self, integer_float32x):
177         """Return the corresponding real floating type."""
178         return self.real_type.floating_type(integer_float32x)
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',
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)
239
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'
259
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
277
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:])
286
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)
291
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)
299
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)
303
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)))
314
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)
325
326 class Tests(object):
327     """The state associated with testcase generation."""
328
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()
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):
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)
652
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'])
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'
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)
830
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
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)
852
853 if __name__ == '__main__':
854     main()