Blame math/gen-tgmath-tests.py

Packit 6c4009
#!/usr/bin/python
Packit 6c4009
# Generate tests for <tgmath.h> macros.
Packit 6c4009
# Copyright (C) 2017-2018 Free Software Foundation, Inc.
Packit 6c4009
# This file is part of the GNU C Library.
Packit 6c4009
#
Packit 6c4009
# The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
# modify it under the terms of the GNU Lesser General Public
Packit 6c4009
# License as published by the Free Software Foundation; either
Packit 6c4009
# version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
#
Packit 6c4009
# The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
# Lesser General Public License for more details.
Packit 6c4009
#
Packit 6c4009
# You should have received a copy of the GNU Lesser General Public
Packit 6c4009
# License along with the GNU C Library; if not, see
Packit 6c4009
# <http://www.gnu.org/licenses/>.
Packit 6c4009
Packit 6c4009
# As glibc does not support decimal floating point, the types to
Packit 6c4009
# consider for generic parameters are standard and binary
Packit 6c4009
# floating-point types, and integer types which are treated as double.
Packit 6c4009
# The corresponding complex types may also be used (including complex
Packit 6c4009
# integer types, which are a GNU extension, but are currently disabled
Packit 6c4009
# here because they do not work properly with tgmath.h).
Packit 6c4009
Packit 6c4009
# The proposed resolution to TS 18661-1 DR#9
Packit 6c4009
# <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2149.htm#dr_9>
Packit 6c4009
# makes the <tgmath.h> rules for selecting a function to call
Packit 6c4009
# correspond to the usual arithmetic conversions (applied successively
Packit 6c4009
# to the arguments for generic parameters in order), which choose the
Packit 6c4009
# type whose set of values contains that of the other type (undefined
Packit 6c4009
# behavior if neither type's set of values is a superset of the
Packit 6c4009
# other), with interchange types being preferred to standard types
Packit 6c4009
# (long double, double, float), being preferred to extended types
Packit 6c4009
# (_Float128x, _Float64x, _Float32x).
Packit 6c4009
Packit 6c4009
# For the standard and binary floating-point types supported by GCC 7
Packit 6c4009
# on any platform, this means the resulting type is the last of the
Packit 6c4009
# given types in one of the following orders, or undefined behavior if
Packit 6c4009
# types with both ibm128 and binary128 representation are specified.
Packit 6c4009
Packit 6c4009
# If double = long double: _Float16, float, _Float32, _Float32x,
Packit 6c4009
# double, long double, _Float64, _Float64x, _Float128.
Packit 6c4009
Packit 6c4009
# Otherwise: _Float16, float, _Float32, _Float32x, double, _Float64,
Packit 6c4009
# _Float64x, long double, _Float128.
Packit 6c4009
Packit 6c4009
# We generate tests to verify the return type is exactly as expected.
Packit 6c4009
# We also verify that the function called is real or complex as
Packit 6c4009
# expected, and that it is called for the right floating-point format
Packit 6c4009
# (but it is OK to call a double function instead of a long double one
Packit 6c4009
# if they have the same format, for example).  For all the formats
Packit 6c4009
# supported on any given configuration of glibc, the MANT_DIG value
Packit 6c4009
# uniquely determines the format.
Packit 6c4009
Packit 6c4009
import string
Packit 6c4009
import sys
Packit 6c4009
Packit 6c4009
class Type(object):
Packit 6c4009
    """A type that may be used as an argument for generic parameters."""
Packit 6c4009
Packit 6c4009
    # All possible argument or result types.
Packit 6c4009
    all_types_list = []
Packit 6c4009
    # All argument types.
Packit 6c4009
    argument_types_list = []
Packit 6c4009
    # All real argument types.
Packit 6c4009
    real_argument_types_list = []
Packit 6c4009
    # Real argument types that correspond to a standard floating type
Packit 6c4009
    # (float, double or long double; not _FloatN or _FloatNx).
Packit 6c4009
    standard_real_argument_types_list = []
Packit 6c4009
    # The real floating types by their order properties (which are
Packit 6c4009
    # tuples giving the positions in both the possible orders above).
Packit 6c4009
    real_types_order = {}
Packit 6c4009
    # The type double.
Packit 6c4009
    double_type = None
Packit 6c4009
    # The type _Complex double.
Packit 6c4009
    complex_double_type = None
Packit 6c4009
    # The type _Float64.
Packit 6c4009
    float64_type = None
Packit 6c4009
    # The type _Float64x.
Packit 6c4009
    float64x_type = None
Packit 6c4009
Packit 6c4009
    def __init__(self, name, suffix=None, mant_dig=None, condition='1',
Packit 6c4009
                 order=None, integer=False, complex=False, real_type=None):
Packit 6c4009
        """Initialize a Type object, creating any corresponding complex type
Packit 6c4009
        in the process."""
Packit 6c4009
        self.name = name
Packit 6c4009
        self.suffix = suffix
Packit 6c4009
        self.mant_dig = mant_dig
Packit 6c4009
        self.condition = condition
Packit 6c4009
        self.order = order
Packit 6c4009
        self.integer = integer
Packit 6c4009
        self.complex = complex
Packit 6c4009
        if complex:
Packit 6c4009
            self.complex_type = self
Packit 6c4009
            self.real_type = real_type
Packit 6c4009
        else:
Packit 6c4009
            # complex_type filled in by the caller once created.
Packit 6c4009
            self.complex_type = None
Packit 6c4009
            self.real_type = self
Packit 6c4009
Packit 6c4009
    def register_type(self, internal):
Packit 6c4009
        """Record a type in the lists of all types."""
Packit 6c4009
        Type.all_types_list.append(self)
Packit 6c4009
        if not internal:
Packit 6c4009
            Type.argument_types_list.append(self)
Packit 6c4009
            if not self.complex:
Packit 6c4009
                Type.real_argument_types_list.append(self)
Packit 6c4009
                if not self.name.startswith('_Float'):
Packit 6c4009
                    Type.standard_real_argument_types_list.append(self)
Packit 6c4009
        if self.order is not None:
Packit 6c4009
            Type.real_types_order[self.order] = self
Packit 6c4009
        if self.name == 'double':
Packit 6c4009
            Type.double_type = self
Packit 6c4009
        if self.name == '_Complex double':
Packit 6c4009
            Type.complex_double_type = self
Packit 6c4009
        if self.name == '_Float64':
Packit 6c4009
            Type.float64_type = self
Packit 6c4009
        if self.name == '_Float64x':
Packit 6c4009
            Type.float64x_type = self
Packit 6c4009
Packit 6c4009
    @staticmethod
Packit 6c4009
    def create_type(name, suffix=None, mant_dig=None, condition='1', order=None,
Packit 6c4009
                    integer=False, complex_name=None, complex_ok=True,
Packit 6c4009
                    internal=False):
Packit 6c4009
        """Create and register a Type object for a real type, creating any
Packit 6c4009
        corresponding complex type in the process."""
Packit 6c4009
        real_type = Type(name, suffix=suffix, mant_dig=mant_dig,
Packit 6c4009
                         condition=condition, order=order, integer=integer,
Packit 6c4009
                         complex=False)
Packit 6c4009
        if complex_ok:
Packit 6c4009
            if complex_name is None:
Packit 6c4009
                complex_name = '_Complex %s' % name
Packit 6c4009
            complex_type = Type(complex_name, condition=condition,
Packit 6c4009
                                integer=integer, complex=True,
Packit 6c4009
                                real_type=real_type)
Packit 6c4009
        else:
Packit 6c4009
            complex_type = None
Packit 6c4009
        real_type.complex_type = complex_type
Packit 6c4009
        real_type.register_type(internal)
Packit 6c4009
        if complex_type is not None:
Packit 6c4009
            complex_type.register_type(internal)
Packit 6c4009
Packit 6c4009
    def floating_type(self):
Packit 6c4009
        """Return the corresponding floating type."""
Packit 6c4009
        if self.integer:
Packit 6c4009
            return (Type.complex_double_type
Packit 6c4009
                    if self.complex
Packit 6c4009
                    else Type.double_type)
Packit 6c4009
        else:
Packit 6c4009
            return self
Packit 6c4009
Packit 6c4009
    def real_floating_type(self):
Packit 6c4009
        """Return the corresponding real floating type."""
Packit 6c4009
        return self.real_type.floating_type()
Packit 6c4009
Packit 6c4009
    def __str__(self):
Packit 6c4009
        """Return string representation of a type."""
Packit 6c4009
        return self.name
Packit 6c4009
Packit 6c4009
    @staticmethod
Packit 6c4009
    def init_types():
Packit 6c4009
        """Initialize all the known types."""
Packit 6c4009
        Type.create_type('_Float16', 'f16', 'FLT16_MANT_DIG',
Packit 6c4009
                         complex_name='__CFLOAT16',
Packit 6c4009
                         condition='defined HUGE_VAL_F16', order=(0, 0))
Packit 6c4009
        Type.create_type('float', 'f', 'FLT_MANT_DIG', order=(1, 1))
Packit 6c4009
        Type.create_type('_Float32', 'f32', 'FLT32_MANT_DIG',
Packit 6c4009
                         complex_name='__CFLOAT32',
Packit 6c4009
                         condition='defined HUGE_VAL_F32', order=(2, 2))
Packit 6c4009
        Type.create_type('_Float32x', 'f32x', 'FLT32X_MANT_DIG',
Packit 6c4009
                         complex_name='__CFLOAT32X',
Packit 6c4009
                         condition='defined HUGE_VAL_F32X', order=(3, 3))
Packit 6c4009
        Type.create_type('double', '', 'DBL_MANT_DIG', order=(4, 4))
Packit 6c4009
        Type.create_type('long double', 'l', 'LDBL_MANT_DIG', order=(5, 7))
Packit 6c4009
        Type.create_type('_Float64', 'f64', 'FLT64_MANT_DIG',
Packit 6c4009
                         complex_name='__CFLOAT64',
Packit 6c4009
                         condition='defined HUGE_VAL_F64', order=(6, 5))
Packit 6c4009
        Type.create_type('_Float64x', 'f64x', 'FLT64X_MANT_DIG',
Packit 6c4009
                         complex_name='__CFLOAT64X',
Packit 6c4009
                         condition='defined HUGE_VAL_F64X', order=(7, 6))
Packit 6c4009
        Type.create_type('_Float128', 'f128', 'FLT128_MANT_DIG',
Packit 6c4009
                         complex_name='__CFLOAT128',
Packit 6c4009
                         condition='defined HUGE_VAL_F128', order=(8, 8))
Packit 6c4009
        Type.create_type('char', integer=True)
Packit 6c4009
        Type.create_type('signed char', integer=True)
Packit 6c4009
        Type.create_type('unsigned char', integer=True)
Packit 6c4009
        Type.create_type('short int', integer=True)
Packit 6c4009
        Type.create_type('unsigned short int', integer=True)
Packit 6c4009
        Type.create_type('int', integer=True)
Packit 6c4009
        Type.create_type('unsigned int', integer=True)
Packit 6c4009
        Type.create_type('long int', integer=True)
Packit 6c4009
        Type.create_type('unsigned long int', integer=True)
Packit 6c4009
        Type.create_type('long long int', integer=True)
Packit 6c4009
        Type.create_type('unsigned long long int', integer=True)
Packit 6c4009
        Type.create_type('__int128', integer=True,
Packit 6c4009
                         condition='defined __SIZEOF_INT128__')
Packit 6c4009
        Type.create_type('unsigned __int128', integer=True,
Packit 6c4009
                         condition='defined __SIZEOF_INT128__')
Packit 6c4009
        Type.create_type('enum e', integer=True, complex_ok=False)
Packit 6c4009
        Type.create_type('_Bool', integer=True, complex_ok=False)
Packit 6c4009
        Type.create_type('bit_field', integer=True, complex_ok=False)
Packit 6c4009
        # Internal types represent the combination of long double with
Packit 6c4009
        # _Float64 or _Float64x, for which the ordering depends on
Packit 6c4009
        # whether long double has the same format as double.
Packit 6c4009
        Type.create_type('long_double_Float64', None, 'LDBL_MANT_DIG',
Packit 6c4009
                         complex_name='complex_long_double_Float64',
Packit 6c4009
                         condition='defined HUGE_VAL_F64', order=(6, 7),
Packit 6c4009
                         internal=True)
Packit 6c4009
        Type.create_type('long_double_Float64x', None, 'FLT64X_MANT_DIG',
Packit 6c4009
                         complex_name='complex_long_double_Float64x',
Packit 6c4009
                         condition='defined HUGE_VAL_F64X', order=(7, 7),
Packit 6c4009
                         internal=True)
Packit 6c4009
Packit 6c4009
    @staticmethod
Packit 6c4009
    def can_combine_types(types):
Packit 6c4009
        """Return a C preprocessor conditional for whether the given list of
Packit 6c4009
        types can be used together as type-generic macro arguments."""
Packit 6c4009
        have_long_double = False
Packit 6c4009
        have_float128 = False
Packit 6c4009
        for t in types:
Packit 6c4009
            t = t.real_floating_type()
Packit 6c4009
            if t.name == 'long double':
Packit 6c4009
                have_long_double = True
Packit 6c4009
            if t.name == '_Float128' or t.name == '_Float64x':
Packit 6c4009
                have_float128 = True
Packit 6c4009
        if have_long_double and have_float128:
Packit 6c4009
            # If ibm128 format is in use for long double, both
Packit 6c4009
            # _Float64x and _Float128 are binary128 and the types
Packit 6c4009
            # cannot be combined.
Packit 6c4009
            return '(LDBL_MANT_DIG != 106)'
Packit 6c4009
        return '1'
Packit 6c4009
Packit 6c4009
    @staticmethod
Packit 6c4009
    def combine_types(types):
Packit 6c4009
        """Return the result of combining a set of types."""
Packit 6c4009
        have_complex = False
Packit 6c4009
        combined = None
Packit 6c4009
        for t in types:
Packit 6c4009
            if t.complex:
Packit 6c4009
                have_complex = True
Packit 6c4009
            t = t.real_floating_type()
Packit 6c4009
            if combined is None:
Packit 6c4009
                combined = t
Packit 6c4009
            else:
Packit 6c4009
                order = (max(combined.order[0], t.order[0]),
Packit 6c4009
                         max(combined.order[1], t.order[1]))
Packit 6c4009
                combined = Type.real_types_order[order]
Packit 6c4009
        return combined.complex_type if have_complex else combined
Packit 6c4009
Packit 6c4009
def list_product_initial(initial, lists):
Packit 6c4009
    """Return a list of lists, with an initial sequence from the first
Packit 6c4009
    argument (a list of lists) followed by each sequence of one
Packit 6c4009
    element from each successive element of the second argument."""
Packit 6c4009
    if not lists:
Packit 6c4009
        return initial
Packit 6c4009
    return list_product_initial([a + [b] for a in initial for b in lists[0]],
Packit 6c4009
                                lists[1:])
Packit 6c4009
Packit 6c4009
def list_product(lists):
Packit 6c4009
    """Return a list of lists, with each sequence of one element from each
Packit 6c4009
    successive element of the argument."""
Packit 6c4009
    return list_product_initial([[]], lists)
Packit 6c4009
Packit 6c4009
try:
Packit 6c4009
    trans_id = str.maketrans(' *', '_p')
Packit 6c4009
except AttributeError:
Packit 6c4009
    trans_id = string.maketrans(' *', '_p')
Packit 6c4009
def var_for_type(name):
Packit 6c4009
    """Return the name of a variable with a given type (name)."""
Packit 6c4009
    return 'var_%s' % name.translate(trans_id)
Packit 6c4009
Packit 6c4009
def vol_var_for_type(name):
Packit 6c4009
    """Return the name of a variable with a given volatile type (name)."""
Packit 6c4009
    return 'vol_var_%s' % name.translate(trans_id)
Packit 6c4009
Packit 6c4009
def define_vars_for_type(name):
Packit 6c4009
    """Return the definitions of variables with a given type (name)."""
Packit 6c4009
    if name == 'bit_field':
Packit 6c4009
        struct_vars = define_vars_for_type('struct s');
Packit 6c4009
        return '%s#define %s %s.bf\n' % (struct_vars,
Packit 6c4009
                                         vol_var_for_type(name),
Packit 6c4009
                                         vol_var_for_type('struct s'))
Packit 6c4009
    return ('%s %s __attribute__ ((unused));\n'
Packit 6c4009
            '%s volatile %s __attribute__ ((unused));\n'
Packit 6c4009
            % (name, var_for_type(name), name, vol_var_for_type(name)))
Packit 6c4009
Packit 6c4009
def if_cond_text(conds, text):
Packit 6c4009
    """Return the result of making some text conditional under #if.  The
Packit 6c4009
    text ends with a newline, as does the return value if not empty."""
Packit 6c4009
    if '0' in conds:
Packit 6c4009
        return ''
Packit 6c4009
    conds = [c for c in conds if c != '1']
Packit 6c4009
    conds = sorted(set(conds))
Packit 6c4009
    if not conds:
Packit 6c4009
        return text
Packit 6c4009
    return '#if %s\n%s#endif\n' % (' && '.join(conds), text)
Packit 6c4009
Packit 6c4009
class Tests(object):
Packit 6c4009
    """The state associated with testcase generation."""
Packit 6c4009
Packit 6c4009
    def __init__(self):
Packit 6c4009
        """Initialize a Tests object."""
Packit 6c4009
        self.header_list = ['#define __STDC_WANT_IEC_60559_TYPES_EXT__\n'
Packit 6c4009
                            '#include <float.h>\n'
Packit 6c4009
                            '#include <stdbool.h>\n'
Packit 6c4009
                            '#include <stdint.h>\n'
Packit 6c4009
                            '#include <stdio.h>\n'
Packit 6c4009
                            '#include <string.h>\n'
Packit 6c4009
                            '#include <tgmath.h>\n'
Packit 6c4009
                            '\n'
Packit 6c4009
                            'struct test\n'
Packit 6c4009
                            '  {\n'
Packit 6c4009
                            '    void (*func) (void);\n'
Packit 6c4009
                            '    const char *func_name;\n'
Packit 6c4009
                            '    const char *test_name;\n'
Packit 6c4009
                            '    int mant_dig;\n'
Packit 6c4009
                            '  };\n'
Packit 6c4009
                            'int num_pass, num_fail;\n'
Packit 6c4009
                            'volatile int called_mant_dig;\n'
Packit 6c4009
                            'const char *volatile called_func_name;\n'
Packit 6c4009
                            'enum e { E, F };\n'
Packit 6c4009
                            'struct s\n'
Packit 6c4009
                            '  {\n'
Packit 6c4009
                            '    int bf:2;\n'
Packit 6c4009
                            '  };\n']
Packit 6c4009
        float64_text = ('# if LDBL_MANT_DIG == DBL_MANT_DIG\n'
Packit 6c4009
                        'typedef _Float64 long_double_Float64;\n'
Packit 6c4009
                        'typedef __CFLOAT64 complex_long_double_Float64;\n'
Packit 6c4009
                        '# else\n'
Packit 6c4009
                        'typedef long double long_double_Float64;\n'
Packit 6c4009
                        'typedef _Complex long double '
Packit 6c4009
                        'complex_long_double_Float64;\n'
Packit 6c4009
                        '# endif\n')
Packit 6c4009
        float64_text = if_cond_text([Type.float64_type.condition],
Packit 6c4009
                                    float64_text)
Packit 6c4009
        float64x_text = ('# if LDBL_MANT_DIG == DBL_MANT_DIG\n'
Packit 6c4009
                         'typedef _Float64x long_double_Float64x;\n'
Packit 6c4009
                         'typedef __CFLOAT64X complex_long_double_Float64x;\n'
Packit 6c4009
                         '# else\n'
Packit 6c4009
                         'typedef long double long_double_Float64x;\n'
Packit 6c4009
                         'typedef _Complex long double '
Packit 6c4009
                         'complex_long_double_Float64x;\n'
Packit 6c4009
                         '# endif\n')
Packit 6c4009
        float64x_text = if_cond_text([Type.float64x_type.condition],
Packit 6c4009
                                     float64x_text)
Packit 6c4009
        self.header_list.append(float64_text)
Packit 6c4009
        self.header_list.append(float64x_text)
Packit 6c4009
        self.types_seen = set()
Packit 6c4009
        for t in Type.all_types_list:
Packit 6c4009
            self.add_type_var(t.name, t.condition)
Packit 6c4009
        self.test_text_list = []
Packit 6c4009
        self.test_array_list = []
Packit 6c4009
        self.macros_seen = set()
Packit 6c4009
Packit 6c4009
    def add_type_var(self, name, cond):
Packit 6c4009
        """Add declarations of variables for a type."""
Packit 6c4009
        if name in self.types_seen:
Packit 6c4009
            return
Packit 6c4009
        t_vars = define_vars_for_type(name)
Packit 6c4009
        self.header_list.append(if_cond_text([cond], t_vars))
Packit 6c4009
        self.types_seen.add(name)
Packit 6c4009
Packit 6c4009
    def add_tests(self, macro, ret, args, complex_func=None):
Packit 6c4009
        """Add tests for a given tgmath.h macro, if that is the macro for
Packit 6c4009
        which tests are to be generated; otherwise just add it to the
Packit 6c4009
        list of macros for which test generation is supported."""
Packit 6c4009
        # 'c' means the function argument or return type is
Packit 6c4009
        # type-generic and complex only (a complex function argument
Packit 6c4009
        # may still have a real macro argument).  'g' means it is
Packit 6c4009
        # type-generic and may be real or complex; 'r' means it is
Packit 6c4009
        # type-generic and may only be real; 's' means the same as
Packit 6c4009
        # 'r', but restricted to float, double and long double.
Packit 6c4009
        self.macros_seen.add(macro)
Packit 6c4009
        if macro != self.macro:
Packit 6c4009
            return
Packit 6c4009
        have_complex = False
Packit 6c4009
        func = macro
Packit 6c4009
        if ret == 'c' or 'c' in args:
Packit 6c4009
            # Complex-only.
Packit 6c4009
            have_complex = True
Packit 6c4009
            complex_func = func
Packit 6c4009
            func = None
Packit 6c4009
        elif ret == 'g' or 'g' in args:
Packit 6c4009
            # Real and complex.
Packit 6c4009
            have_complex = True
Packit 6c4009
            if complex_func == None:
Packit 6c4009
                complex_func = 'c%s' % func
Packit 6c4009
        types = [ret] + args
Packit 6c4009
        for t in types:
Packit 6c4009
            if t != 'c' and t != 'g' and t != 'r' and t != 's':
Packit 6c4009
                self.add_type_var(t, '1')
Packit 6c4009
        for t in Type.argument_types_list:
Packit 6c4009
            if t.integer:
Packit 6c4009
                continue
Packit 6c4009
            if t.complex and not have_complex:
Packit 6c4009
                continue
Packit 6c4009
            if func == None and not t.complex:
Packit 6c4009
                continue
Packit 6c4009
            if ret == 's' and t.name.startswith('_Float'):
Packit 6c4009
                continue
Packit 6c4009
            if ret == 'c':
Packit 6c4009
                ret_name = t.complex_type.name
Packit 6c4009
            elif ret == 'g':
Packit 6c4009
                ret_name = t.name
Packit 6c4009
            elif ret == 'r' or ret == 's':
Packit 6c4009
                ret_name = t.real_type.name
Packit 6c4009
            else:
Packit 6c4009
                ret_name = ret
Packit 6c4009
            dummy_func_name = complex_func if t.complex else func
Packit 6c4009
            arg_list = []
Packit 6c4009
            arg_num = 0
Packit 6c4009
            for a in args:
Packit 6c4009
                if a == 'c':
Packit 6c4009
                    arg_name = t.complex_type.name
Packit 6c4009
                elif a == 'g':
Packit 6c4009
                    arg_name = t.name
Packit 6c4009
                elif a == 'r' or a == 's':
Packit 6c4009
                    arg_name = t.real_type.name
Packit 6c4009
                else:
Packit 6c4009
                    arg_name = a
Packit 6c4009
                arg_list.append('%s arg%d __attribute__ ((unused))'
Packit 6c4009
                                % (arg_name, arg_num))
Packit 6c4009
                arg_num += 1
Packit 6c4009
            dummy_func = ('%s\n'
Packit 6c4009
                          '(%s%s) (%s)\n'
Packit 6c4009
                          '{\n'
Packit 6c4009
                          '  called_mant_dig = %s;\n'
Packit 6c4009
                          '  called_func_name = "%s";\n'
Packit 6c4009
                          '  return 0;\n'
Packit 6c4009
                          '}\n' % (ret_name, dummy_func_name,
Packit 6c4009
                                   t.real_type.suffix, ', '.join(arg_list),
Packit 6c4009
                                   t.real_type.mant_dig, dummy_func_name))
Packit 6c4009
            dummy_func = if_cond_text([t.condition], dummy_func)
Packit 6c4009
            self.test_text_list.append(dummy_func)
Packit 6c4009
        arg_types = []
Packit 6c4009
        for t in args:
Packit 6c4009
            if t == 'g' or t == 'c':
Packit 6c4009
                arg_types.append(Type.argument_types_list)
Packit 6c4009
            elif t == 'r':
Packit 6c4009
                arg_types.append(Type.real_argument_types_list)
Packit 6c4009
            elif t == 's':
Packit 6c4009
                arg_types.append(Type.standard_real_argument_types_list)
Packit 6c4009
        arg_types_product = list_product(arg_types)
Packit 6c4009
        test_num = 0
Packit 6c4009
        for this_args in arg_types_product:
Packit 6c4009
            comb_type = Type.combine_types(this_args)
Packit 6c4009
            can_comb = Type.can_combine_types(this_args)
Packit 6c4009
            all_conds = [t.condition for t in this_args]
Packit 6c4009
            all_conds.append(can_comb)
Packit 6c4009
            any_complex = func == None
Packit 6c4009
            for t in this_args:
Packit 6c4009
                if t.complex:
Packit 6c4009
                    any_complex = True
Packit 6c4009
            func_name = complex_func if any_complex else func
Packit 6c4009
            test_name = '%s (%s)' % (macro,
Packit 6c4009
                                     ', '.join([t.name for t in this_args]))
Packit 6c4009
            test_func_name = 'test_%s_%d' % (macro, test_num)
Packit 6c4009
            test_num += 1
Packit 6c4009
            mant_dig = comb_type.real_type.mant_dig
Packit 6c4009
            test_text = '%s, "%s", "%s", %s' % (test_func_name, func_name,
Packit 6c4009
                                                test_name, mant_dig)
Packit 6c4009
            test_text = '    { %s },\n' % test_text
Packit 6c4009
            test_text = if_cond_text(all_conds, test_text)
Packit 6c4009
            self.test_array_list.append(test_text)
Packit 6c4009
            call_args = []
Packit 6c4009
            call_arg_pos = 0
Packit 6c4009
            for t in args:
Packit 6c4009
                if t == 'g' or t == 'c' or t == 'r' or t == 's':
Packit 6c4009
                    type = this_args[call_arg_pos].name
Packit 6c4009
                    call_arg_pos += 1
Packit 6c4009
                else:
Packit 6c4009
                    type = t
Packit 6c4009
                call_args.append(vol_var_for_type(type))
Packit 6c4009
            call_args_text = ', '.join(call_args)
Packit 6c4009
            if ret == 'g':
Packit 6c4009
                ret_type = comb_type.name
Packit 6c4009
            elif ret == 'r' or ret == 's':
Packit 6c4009
                ret_type = comb_type.real_type.name
Packit 6c4009
            elif ret == 'c':
Packit 6c4009
                ret_type = comb_type.complex_type.name
Packit 6c4009
            else:
Packit 6c4009
                ret_type = ret
Packit 6c4009
            call_text = '%s (%s)' % (macro, call_args_text)
Packit 6c4009
            test_func_text = ('static void\n'
Packit 6c4009
                              '%s (void)\n'
Packit 6c4009
                              '{\n'
Packit 6c4009
                              '  extern typeof (%s) %s '
Packit 6c4009
                              '__attribute__ ((unused));\n'
Packit 6c4009
                              '  %s = %s;\n'
Packit 6c4009
                              '}\n' % (test_func_name, call_text,
Packit 6c4009
                                       var_for_type(ret_type),
Packit 6c4009
                                       vol_var_for_type(ret_type), call_text))
Packit 6c4009
            test_func_text = if_cond_text(all_conds, test_func_text)
Packit 6c4009
            self.test_text_list.append(test_func_text)
Packit 6c4009
Packit 6c4009
    def add_all_tests(self, macro):
Packit 6c4009
        """Add tests for the given tgmath.h macro, if any, and generate the
Packit 6c4009
        list of all supported macros."""
Packit 6c4009
        self.macro = macro
Packit 6c4009
        # C99/C11 real-only functions.
Packit 6c4009
        self.add_tests('atan2', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('cbrt', 'r', ['r'])
Packit 6c4009
        self.add_tests('ceil', 'r', ['r'])
Packit 6c4009
        self.add_tests('copysign', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('erf', 'r', ['r'])
Packit 6c4009
        self.add_tests('erfc', 'r', ['r'])
Packit 6c4009
        self.add_tests('exp2', 'r', ['r'])
Packit 6c4009
        self.add_tests('expm1', 'r', ['r'])
Packit 6c4009
        self.add_tests('fdim', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('floor', 'r', ['r'])
Packit 6c4009
        self.add_tests('fma', 'r', ['r', 'r', 'r'])
Packit 6c4009
        self.add_tests('fmax', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('fmin', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('fmod', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('frexp', 'r', ['r', 'int *'])
Packit 6c4009
        self.add_tests('hypot', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('ilogb', 'int', ['r'])
Packit 6c4009
        self.add_tests('ldexp', 'r', ['r', 'int'])
Packit 6c4009
        self.add_tests('lgamma', 'r', ['r'])
Packit 6c4009
        self.add_tests('llrint', 'long long int', ['r'])
Packit 6c4009
        self.add_tests('llround', 'long long int', ['r'])
Packit 6c4009
        # log10 is real-only in ISO C, but supports complex arguments
Packit 6c4009
        # as a GNU extension.
Packit 6c4009
        self.add_tests('log10', 'g', ['g'])
Packit 6c4009
        self.add_tests('log1p', 'r', ['r'])
Packit 6c4009
        self.add_tests('log2', 'r', ['r'])
Packit 6c4009
        self.add_tests('logb', 'r', ['r'])
Packit 6c4009
        self.add_tests('lrint', 'long int', ['r'])
Packit 6c4009
        self.add_tests('lround', 'long int', ['r'])
Packit 6c4009
        self.add_tests('nearbyint', 'r', ['r'])
Packit 6c4009
        self.add_tests('nextafter', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('nexttoward', 's', ['s', 'long double'])
Packit 6c4009
        self.add_tests('remainder', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('remquo', 'r', ['r', 'r', 'int *'])
Packit 6c4009
        self.add_tests('rint', 'r', ['r'])
Packit 6c4009
        self.add_tests('round', 'r', ['r'])
Packit 6c4009
        self.add_tests('scalbn', 'r', ['r', 'int'])
Packit 6c4009
        self.add_tests('scalbln', 'r', ['r', 'long int'])
Packit 6c4009
        self.add_tests('tgamma', 'r', ['r'])
Packit 6c4009
        self.add_tests('trunc', 'r', ['r'])
Packit 6c4009
        # C99/C11 real-and-complex functions.
Packit 6c4009
        self.add_tests('acos', 'g', ['g'])
Packit 6c4009
        self.add_tests('asin', 'g', ['g'])
Packit 6c4009
        self.add_tests('atan', 'g', ['g'])
Packit 6c4009
        self.add_tests('acosh', 'g', ['g'])
Packit 6c4009
        self.add_tests('asinh', 'g', ['g'])
Packit 6c4009
        self.add_tests('atanh', 'g', ['g'])
Packit 6c4009
        self.add_tests('cos', 'g', ['g'])
Packit 6c4009
        self.add_tests('sin', 'g', ['g'])
Packit 6c4009
        self.add_tests('tan', 'g', ['g'])
Packit 6c4009
        self.add_tests('cosh', 'g', ['g'])
Packit 6c4009
        self.add_tests('sinh', 'g', ['g'])
Packit 6c4009
        self.add_tests('tanh', 'g', ['g'])
Packit 6c4009
        self.add_tests('exp', 'g', ['g'])
Packit 6c4009
        self.add_tests('log', 'g', ['g'])
Packit 6c4009
        self.add_tests('pow', 'g', ['g', 'g'])
Packit 6c4009
        self.add_tests('sqrt', 'g', ['g'])
Packit 6c4009
        self.add_tests('fabs', 'r', ['g'], 'cabs')
Packit 6c4009
        # C99/C11 complex-only functions.
Packit 6c4009
        self.add_tests('carg', 'r', ['c'])
Packit 6c4009
        self.add_tests('cimag', 'r', ['c'])
Packit 6c4009
        self.add_tests('conj', 'c', ['c'])
Packit 6c4009
        self.add_tests('cproj', 'c', ['c'])
Packit 6c4009
        self.add_tests('creal', 'r', ['c'])
Packit 6c4009
        # TS 18661-1 functions.
Packit 6c4009
        self.add_tests('roundeven', 'r', ['r'])
Packit 6c4009
        self.add_tests('nextup', 'r', ['r'])
Packit 6c4009
        self.add_tests('nextdown', 'r', ['r'])
Packit 6c4009
        self.add_tests('fminmag', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('fmaxmag', 'r', ['r', 'r'])
Packit 6c4009
        self.add_tests('llogb', 'long int', ['r'])
Packit 6c4009
        self.add_tests('fromfp', 'intmax_t', ['r', 'int', 'unsigned int'])
Packit 6c4009
        self.add_tests('fromfpx', 'intmax_t', ['r', 'int', 'unsigned int'])
Packit 6c4009
        self.add_tests('ufromfp', 'uintmax_t', ['r', 'int', 'unsigned int'])
Packit 6c4009
        self.add_tests('ufromfpx', 'uintmax_t', ['r', 'int', 'unsigned int'])
Packit 6c4009
        self.add_tests('totalorder', 'int', ['r', 'r'])
Packit 6c4009
        self.add_tests('totalordermag', 'int', ['r', 'r'])
Packit 6c4009
        # The functions that round their result to a narrower type,
Packit 6c4009
        # and the associated type-generic macros, are not yet
Packit 6c4009
        # supported by this script or by glibc.
Packit 6c4009
        # Miscellaneous functions.
Packit 6c4009
        self.add_tests('scalb', 's', ['s', 's'])
Packit 6c4009
Packit 6c4009
    def tests_text(self):
Packit 6c4009
        """Return the text of the generated testcase."""
Packit 6c4009
        test_list = [''.join(self.test_text_list),
Packit 6c4009
                     'static const struct test tests[] =\n'
Packit 6c4009
                     '  {\n',
Packit 6c4009
                     ''.join(self.test_array_list),
Packit 6c4009
                     '  };\n']
Packit 6c4009
        footer_list = ['static int\n'
Packit 6c4009
                       'do_test (void)\n'
Packit 6c4009
                       '{\n'
Packit 6c4009
                       '  for (size_t i = 0;\n'
Packit 6c4009
                       '       i < sizeof (tests) / sizeof (tests[0]);\n'
Packit 6c4009
                       '       i++)\n'
Packit 6c4009
                       '    {\n'
Packit 6c4009
                       '      called_mant_dig = 0;\n'
Packit 6c4009
                       '      called_func_name = "";\n'
Packit 6c4009
                       '      tests[i].func ();\n'
Packit 6c4009
                       '      if (called_mant_dig == tests[i].mant_dig\n'
Packit 6c4009
                       '          && strcmp (called_func_name,\n'
Packit 6c4009
                       '                     tests[i].func_name) == 0)\n'
Packit 6c4009
                       '        num_pass++;\n'
Packit 6c4009
                       '      else\n'
Packit 6c4009
                       '        {\n'
Packit 6c4009
                       '          num_fail++;\n'
Packit 6c4009
                       '          printf ("Test %zu (%s):\\n"\n'
Packit 6c4009
                       '                  "  Expected: %s precision %d\\n"\n'
Packit 6c4009
                       '                  "  Actual: %s precision %d\\n\\n",\n'
Packit 6c4009
                       '                  i, tests[i].test_name,\n'
Packit 6c4009
                       '                  tests[i].func_name,\n'
Packit 6c4009
                       '                  tests[i].mant_dig,\n'
Packit 6c4009
                       '                  called_func_name, called_mant_dig);\n'
Packit 6c4009
                       '        }\n'
Packit 6c4009
                       '    }\n'
Packit 6c4009
                       '  printf ("%d pass, %d fail\\n", num_pass, num_fail);\n'
Packit 6c4009
                       '  return num_fail != 0;\n'
Packit 6c4009
                       '}\n'
Packit 6c4009
                       '\n'
Packit 6c4009
                       '#include <support/test-driver.c>']
Packit 6c4009
        return ''.join(self.header_list + test_list + footer_list)
Packit 6c4009
Packit 6c4009
    def check_macro_list(self, macro_list):
Packit 6c4009
        """Check the list of macros that can be tested."""
Packit 6c4009
        if self.macros_seen != set(macro_list):
Packit 6c4009
            print('error: macro list mismatch')
Packit 6c4009
            sys.exit(1)
Packit 6c4009
Packit 6c4009
def main():
Packit 6c4009
    """The main entry point."""
Packit 6c4009
    Type.init_types()
Packit 6c4009
    t = Tests()
Packit 6c4009
    if sys.argv[1] == 'check-list':
Packit 6c4009
        macro = None
Packit 6c4009
        macro_list = sys.argv[2:]
Packit 6c4009
    else:
Packit 6c4009
        macro = sys.argv[1]
Packit 6c4009
        macro_list = []
Packit 6c4009
    t.add_all_tests(macro)
Packit 6c4009
    if macro:
Packit 6c4009
        print(t.tests_text())
Packit 6c4009
    else:
Packit 6c4009
        t.check_macro_list(macro_list)
Packit 6c4009
Packit 6c4009
if __name__ == '__main__':
Packit 6c4009
    main()