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 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
58import sys
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 = []
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 = []
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
81    # The type long double.
82    long_double_type = None
83    # The type _Complex double.
84    complex_double_type = None
85    # The type _Float64.
86    float64_type = None
87    # The type _Complex _Float64.
88    complex_float64_type = None
89    # The type _Float64x.
90    float64x_type = None
91    # The type _Float64x if available, otherwise _Float64.
92    float32x_ext_type = None
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)
122                if self.name not in ('float', 'double', 'long double'):
123                    Type.non_standard_real_argument_types_list.append(self)
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
128        if self.name == 'long double':
129            Type.long_double_type = self
130        if self.name == '_Complex double':
131            Type.complex_double_type = self
132        if self.name == '_Float64':
133            Type.float64_type = self
134        if self.name == '_Complex _Float64':
135            Type.complex_float64_type = self
136        if self.name == '_Float64x':
137            Type.float64x_type = self
138        if self.name == 'Float32x_ext':
139            Type.float32x_ext_type = self
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)
150        if complex_ok:
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
163    def floating_type(self, floatn):
164        """Return the corresponding floating type."""
165        if self.integer:
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)
174        else:
175            return self
176
177    def real_floating_type(self, floatn):
178        """Return the corresponding real floating type."""
179        return self.real_type.floating_type(floatn)
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',
190                         condition='defined HUGE_VAL_F16', order=(0, 0))
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',
194                         condition='defined HUGE_VAL_F32', order=(2, 2))
195        Type.create_type('_Float32x', 'f32x', 'FLT32X_MANT_DIG',
196                         complex_name='__CFLOAT32X',
197                         condition='defined HUGE_VAL_F32X', order=(3, 3))
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        Type.create_type('_Float128', 'f128', 'FLT128_MANT_DIG',
207                         complex_name='__CFLOAT128',
208                         condition='defined HUGE_VAL_F128', order=(8, 8))
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)
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__')
224        Type.create_type('enum e', integer=True, complex_ok=False)
225        Type.create_type('_Bool', integer=True, complex_ok=False)
226        Type.create_type('bit_field', integer=True, complex_ok=False)
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.
230        Type.create_type('long_double_Float64', None, 'LDBL_MANT_DIG',
231                         complex_name='complex_long_double_Float64',
232                         condition='defined HUGE_VAL_F64', order=(6, 7),
233                         internal=True)
234        Type.create_type('long_double_Float64x', None, 'FLT64X_MANT_DIG',
235                         complex_name='complex_long_double_Float64x',
236                         condition='defined HUGE_VAL_F64X', order=(7, 7),
237                         internal=True)
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)
244
245    @staticmethod
246    def can_combine_types(types, floatn):
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:
252            t = t.real_floating_type(floatn)
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
265    def combine_types(types, floatn):
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
272            t = t.real_floating_type(floatn)
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)."""
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'))
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."""
334        self.header_list = ['#define __STDC_WANT_IEC_60559_TYPES_EXT__\n'
335                            '#include <float.h>\n'
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'
348                            '    int narrow_mant_dig;\n'
349                            '  };\n'
350                            'int num_pass, num_fail;\n'
351                            'volatile int called_mant_dig;\n'
352                            'const char *volatile called_func_name;\n'
353                            'enum e { E, F };\n'
354                            'struct s\n'
355                            '  {\n'
356                            '    int bf:2;\n'
357                            '  };\n']
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)
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')
387        self.header_list.append(float64_text)
388        self.header_list.append(float64x_text)
389        self.header_list.append(float32x_ext_text)
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 = []
395        self.macros_seen = set()
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):
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."""
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.
415        self.macros_seen.add(macro)
416        if macro != self.macro:
417            return
418        have_complex = False
419        func = macro
420        narrowing = False
421        narrowing_std = False
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
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
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
488            if narrowing and t not in narrow_args:
489                continue
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))
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)
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':
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)
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:
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)
568            all_conds = [t.condition for t in this_args]
569            all_conds.append(can_comb)
570            if narrowing:
571                all_conds.append(narrow_cond)
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
582            test_text = '%s, "%s", "%s", %s, %s' % (test_func_name, func_name,
583                                                    test_name, mant_dig,
584                                                    narrow_mant_dig)
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
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
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'])
645        # log10 is real-only in ISO C, but supports complex arguments
646        # as a GNU extension.
647        self.add_tests('log10', 'g', ['g'])
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'])
699        for fn, args in (('add', 2), ('div', 2), ('fma', 3), ('mul', 2),
700                         ('sqrt', 1), ('sub', 2)):
701            for ret, prefix in (('float', 'f'),
702                                ('double', 'd'),
703                                ('_Float16', 'f16'),
704                                ('_Float32', 'f32'),
705                                ('_Float64', 'f64'),
706                                ('_Float128', 'f128'),
707                                ('_Float32x', 'f32x'),
708                                ('_Float64x', 'f64x')):
709                self.add_tests(prefix + fn, ret, ['r'] * args)
710        # TS 18661-4 functions.
711        self.add_tests('exp10', 'r', ['r'])
712        # C2X functions.
713        self.add_tests('fmaximum', 'r', ['r', 'r'])
714        self.add_tests('fmaximum_mag', 'r', ['r', 'r'])
715        self.add_tests('fmaximum_num', 'r', ['r', 'r'])
716        self.add_tests('fmaximum_mag_num', 'r', ['r', 'r'])
717        self.add_tests('fminimum', 'r', ['r', 'r'])
718        self.add_tests('fminimum_mag', 'r', ['r', 'r'])
719        self.add_tests('fminimum_num', 'r', ['r', 'r'])
720        self.add_tests('fminimum_mag_num', 'r', ['r', 'r'])
721        # Miscellaneous functions.
722        self.add_tests('scalb', 's', ['s', 's'])
723
724    def tests_text(self):
725        """Return the text of the generated testcase."""
726        test_list = [''.join(self.test_text_list),
727                     'static const struct test tests[] =\n'
728                     '  {\n',
729                     ''.join(self.test_array_list),
730                     '  };\n']
731        footer_list = ['static int\n'
732                       'do_test (void)\n'
733                       '{\n'
734                       '  for (size_t i = 0;\n'
735                       '       i < sizeof (tests) / sizeof (tests[0]);\n'
736                       '       i++)\n'
737                       '    {\n'
738                       '      called_mant_dig = 0;\n'
739                       '      called_func_name = "";\n'
740                       '      tests[i].func ();\n'
741                       '      if (called_mant_dig == tests[i].mant_dig\n'
742                       '          && strcmp (called_func_name,\n'
743                       '                     tests[i].func_name) == 0)\n'
744                       '        num_pass++;\n'
745                       '#if !__GNUC_PREREQ (8, 0)\n'
746                       '      else if (tests[i].narrow_mant_dig > 0\n'
747                       '               && (called_mant_dig\n'
748                       '                   >= tests[i].narrow_mant_dig)\n'
749                       '               && strcmp (called_func_name,\n'
750                       '                          tests[i].func_name) == 0)\n'
751                       '        {\n'
752                       '          num_pass++;\n'
753                       '          printf ("Test %zu (%s):\\n"\n'
754                       '                  "  Expected: %s precision %d\\n"\n'
755                       '                  "  Actual: %s precision %d\\n"\n'
756                       '                  "  (OK with old GCC)\\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                       '#endif\n'
763                       '      else\n'
764                       '        {\n'
765                       '          num_fail++;\n'
766                       '          printf ("Test %zu (%s):\\n"\n'
767                       '                  "  Expected: %s precision %d\\n"\n'
768                       '                  "  Actual: %s precision %d\\n\\n",\n'
769                       '                  i, tests[i].test_name,\n'
770                       '                  tests[i].func_name,\n'
771                       '                  tests[i].mant_dig,\n'
772                       '                  called_func_name, called_mant_dig);\n'
773                       '        }\n'
774                       '    }\n'
775                       '  printf ("%d pass, %d fail\\n", num_pass, num_fail);\n'
776                       '  return num_fail != 0;\n'
777                       '}\n'
778                       '\n'
779                       '#include <support/test-driver.c>']
780        return ''.join(self.header_list + test_list + footer_list)
781
782    def check_macro_list(self, macro_list):
783        """Check the list of macros that can be tested."""
784        if self.macros_seen != set(macro_list):
785            print('error: macro list mismatch')
786            sys.exit(1)
787
788def main():
789    """The main entry point."""
790    Type.init_types()
791    t = Tests()
792    if sys.argv[1] == 'check-list':
793        macro = None
794        macro_list = sys.argv[2:]
795    else:
796        macro = sys.argv[1]
797        macro_list = []
798    t.add_all_tests(macro)
799    if macro:
800        print(t.tests_text())
801    else:
802        t.check_macro_list(macro_list)
803
804if __name__ == '__main__':
805    main()
806