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