(root)/
glibc-2.38/
math/
gen-tgmath-tests.py
       1  #!/usr/bin/python3
       2  # Generate tests for <tgmath.h> macros.
       3  # Copyright (C) 2017-2023 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 ESC[4;38;5;81mType(ESC[4;38;5;149mobject):
      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 ESC[4;38;5;81mTests(ESC[4;38;5;149mobject):
     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()