]>
Commit | Line | Data |
---|---|---|
2dd0aec5 JM |
1 | #!/usr/bin/python |
2 | # Generate tests for <tgmath.h> macros. | |
688903eb | 3 | # Copyright (C) 2017-2018 Free Software Foundation, Inc. |
2dd0aec5 JM |
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 | # <http://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 | ||
57 | import string | |
7c67e6e8 | 58 | import sys |
2dd0aec5 JM |
59 | |
60 | class 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 | # The real floating types by their order properties (which are | |
73 | # tuples giving the positions in both the possible orders above). | |
74 | real_types_order = {} | |
75 | # The type double. | |
76 | double_type = None | |
77 | # The type _Complex double. | |
78 | complex_double_type = None | |
79 | # The type _Float64. | |
80 | float64_type = None | |
81 | # The type _Float64x. | |
82 | float64x_type = None | |
83 | ||
84 | def __init__(self, name, suffix=None, mant_dig=None, condition='1', | |
85 | order=None, integer=False, complex=False, real_type=None): | |
86 | """Initialize a Type object, creating any corresponding complex type | |
87 | in the process.""" | |
88 | self.name = name | |
89 | self.suffix = suffix | |
90 | self.mant_dig = mant_dig | |
91 | self.condition = condition | |
92 | self.order = order | |
93 | self.integer = integer | |
94 | self.complex = complex | |
95 | if complex: | |
96 | self.complex_type = self | |
97 | self.real_type = real_type | |
98 | else: | |
99 | # complex_type filled in by the caller once created. | |
100 | self.complex_type = None | |
101 | self.real_type = self | |
102 | ||
103 | def register_type(self, internal): | |
104 | """Record a type in the lists of all types.""" | |
105 | Type.all_types_list.append(self) | |
106 | if not internal: | |
107 | Type.argument_types_list.append(self) | |
108 | if not self.complex: | |
109 | Type.real_argument_types_list.append(self) | |
110 | if not self.name.startswith('_Float'): | |
111 | Type.standard_real_argument_types_list.append(self) | |
112 | if self.order is not None: | |
113 | Type.real_types_order[self.order] = self | |
114 | if self.name == 'double': | |
115 | Type.double_type = self | |
116 | if self.name == '_Complex double': | |
117 | Type.complex_double_type = self | |
118 | if self.name == '_Float64': | |
119 | Type.float64_type = self | |
120 | if self.name == '_Float64x': | |
121 | Type.float64x_type = self | |
122 | ||
123 | @staticmethod | |
124 | def create_type(name, suffix=None, mant_dig=None, condition='1', order=None, | |
125 | integer=False, complex_name=None, complex_ok=True, | |
126 | internal=False): | |
127 | """Create and register a Type object for a real type, creating any | |
128 | corresponding complex type in the process.""" | |
129 | real_type = Type(name, suffix=suffix, mant_dig=mant_dig, | |
130 | condition=condition, order=order, integer=integer, | |
131 | complex=False) | |
d9bef9c0 | 132 | if complex_ok: |
2dd0aec5 JM |
133 | if complex_name is None: |
134 | complex_name = '_Complex %s' % name | |
135 | complex_type = Type(complex_name, condition=condition, | |
136 | integer=integer, complex=True, | |
137 | real_type=real_type) | |
138 | else: | |
139 | complex_type = None | |
140 | real_type.complex_type = complex_type | |
141 | real_type.register_type(internal) | |
142 | if complex_type is not None: | |
143 | complex_type.register_type(internal) | |
144 | ||
145 | def floating_type(self): | |
146 | """Return the corresponding floating type.""" | |
147 | if self.integer: | |
148 | return (Type.complex_double_type | |
149 | if self.complex | |
150 | else Type.double_type) | |
151 | else: | |
152 | return self | |
153 | ||
154 | def real_floating_type(self): | |
155 | """Return the corresponding real floating type.""" | |
156 | return self.real_type.floating_type() | |
157 | ||
158 | def __str__(self): | |
159 | """Return string representation of a type.""" | |
160 | return self.name | |
161 | ||
162 | @staticmethod | |
163 | def init_types(): | |
164 | """Initialize all the known types.""" | |
165 | Type.create_type('_Float16', 'f16', 'FLT16_MANT_DIG', | |
166 | complex_name='__CFLOAT16', | |
614d15f9 | 167 | condition='defined HUGE_VAL_F16', order=(0, 0)) |
2dd0aec5 JM |
168 | Type.create_type('float', 'f', 'FLT_MANT_DIG', order=(1, 1)) |
169 | Type.create_type('_Float32', 'f32', 'FLT32_MANT_DIG', | |
170 | complex_name='__CFLOAT32', | |
614d15f9 | 171 | condition='defined HUGE_VAL_F32', order=(2, 2)) |
2dd0aec5 JM |
172 | Type.create_type('_Float32x', 'f32x', 'FLT32X_MANT_DIG', |
173 | complex_name='__CFLOAT32X', | |
614d15f9 | 174 | condition='defined HUGE_VAL_F32X', order=(3, 3)) |
2dd0aec5 JM |
175 | Type.create_type('double', '', 'DBL_MANT_DIG', order=(4, 4)) |
176 | Type.create_type('long double', 'l', 'LDBL_MANT_DIG', order=(5, 7)) | |
177 | Type.create_type('_Float64', 'f64', 'FLT64_MANT_DIG', | |
178 | complex_name='__CFLOAT64', | |
614d15f9 | 179 | condition='defined HUGE_VAL_F64', order=(6, 5)) |
2dd0aec5 JM |
180 | Type.create_type('_Float64x', 'f64x', 'FLT64X_MANT_DIG', |
181 | complex_name='__CFLOAT64X', | |
614d15f9 | 182 | condition='defined HUGE_VAL_F64X', order=(7, 6)) |
2dd0aec5 JM |
183 | Type.create_type('_Float128', 'f128', 'FLT128_MANT_DIG', |
184 | complex_name='__CFLOAT128', | |
614d15f9 | 185 | condition='defined HUGE_VAL_F128', order=(8, 8)) |
2dd0aec5 JM |
186 | Type.create_type('char', integer=True) |
187 | Type.create_type('signed char', integer=True) | |
188 | Type.create_type('unsigned char', integer=True) | |
189 | Type.create_type('short int', integer=True) | |
190 | Type.create_type('unsigned short int', integer=True) | |
191 | Type.create_type('int', integer=True) | |
192 | Type.create_type('unsigned int', integer=True) | |
193 | Type.create_type('long int', integer=True) | |
194 | Type.create_type('unsigned long int', integer=True) | |
195 | Type.create_type('long long int', integer=True) | |
196 | Type.create_type('unsigned long long int', integer=True) | |
42df8d59 JM |
197 | Type.create_type('__int128', integer=True, |
198 | condition='defined __SIZEOF_INT128__') | |
199 | Type.create_type('unsigned __int128', integer=True, | |
200 | condition='defined __SIZEOF_INT128__') | |
2dd0aec5 JM |
201 | Type.create_type('enum e', integer=True, complex_ok=False) |
202 | Type.create_type('_Bool', integer=True, complex_ok=False) | |
2fee621d | 203 | Type.create_type('bit_field', integer=True, complex_ok=False) |
2dd0aec5 JM |
204 | # Internal types represent the combination of long double with |
205 | # _Float64 or _Float64x, for which the ordering depends on | |
206 | # whether long double has the same format as double. | |
01e659e7 | 207 | Type.create_type('long_double_Float64', None, 'LDBL_MANT_DIG', |
2dd0aec5 | 208 | complex_name='complex_long_double_Float64', |
614d15f9 JM |
209 | condition='defined HUGE_VAL_F64', order=(6, 7), |
210 | internal=True) | |
01e659e7 | 211 | Type.create_type('long_double_Float64x', None, 'FLT64X_MANT_DIG', |
2dd0aec5 | 212 | complex_name='complex_long_double_Float64x', |
614d15f9 JM |
213 | condition='defined HUGE_VAL_F64X', order=(7, 7), |
214 | internal=True) | |
2dd0aec5 JM |
215 | |
216 | @staticmethod | |
217 | def can_combine_types(types): | |
218 | """Return a C preprocessor conditional for whether the given list of | |
219 | types can be used together as type-generic macro arguments.""" | |
220 | have_long_double = False | |
221 | have_float128 = False | |
222 | for t in types: | |
223 | t = t.real_floating_type() | |
224 | if t.name == 'long double': | |
225 | have_long_double = True | |
226 | if t.name == '_Float128' or t.name == '_Float64x': | |
227 | have_float128 = True | |
228 | if have_long_double and have_float128: | |
229 | # If ibm128 format is in use for long double, both | |
230 | # _Float64x and _Float128 are binary128 and the types | |
231 | # cannot be combined. | |
232 | return '(LDBL_MANT_DIG != 106)' | |
233 | return '1' | |
234 | ||
235 | @staticmethod | |
236 | def combine_types(types): | |
237 | """Return the result of combining a set of types.""" | |
238 | have_complex = False | |
239 | combined = None | |
240 | for t in types: | |
241 | if t.complex: | |
242 | have_complex = True | |
243 | t = t.real_floating_type() | |
244 | if combined is None: | |
245 | combined = t | |
246 | else: | |
247 | order = (max(combined.order[0], t.order[0]), | |
248 | max(combined.order[1], t.order[1])) | |
249 | combined = Type.real_types_order[order] | |
250 | return combined.complex_type if have_complex else combined | |
251 | ||
252 | def list_product_initial(initial, lists): | |
253 | """Return a list of lists, with an initial sequence from the first | |
254 | argument (a list of lists) followed by each sequence of one | |
255 | element from each successive element of the second argument.""" | |
256 | if not lists: | |
257 | return initial | |
258 | return list_product_initial([a + [b] for a in initial for b in lists[0]], | |
259 | lists[1:]) | |
260 | ||
261 | def list_product(lists): | |
262 | """Return a list of lists, with each sequence of one element from each | |
263 | successive element of the argument.""" | |
264 | return list_product_initial([[]], lists) | |
265 | ||
266 | try: | |
267 | trans_id = str.maketrans(' *', '_p') | |
268 | except AttributeError: | |
269 | trans_id = string.maketrans(' *', '_p') | |
270 | def var_for_type(name): | |
271 | """Return the name of a variable with a given type (name).""" | |
272 | return 'var_%s' % name.translate(trans_id) | |
273 | ||
274 | def vol_var_for_type(name): | |
275 | """Return the name of a variable with a given volatile type (name).""" | |
276 | return 'vol_var_%s' % name.translate(trans_id) | |
277 | ||
278 | def define_vars_for_type(name): | |
279 | """Return the definitions of variables with a given type (name).""" | |
2fee621d JM |
280 | if name == 'bit_field': |
281 | struct_vars = define_vars_for_type('struct s'); | |
282 | return '%s#define %s %s.bf\n' % (struct_vars, | |
283 | vol_var_for_type(name), | |
284 | vol_var_for_type('struct s')) | |
2dd0aec5 JM |
285 | return ('%s %s __attribute__ ((unused));\n' |
286 | '%s volatile %s __attribute__ ((unused));\n' | |
287 | % (name, var_for_type(name), name, vol_var_for_type(name))) | |
288 | ||
289 | def if_cond_text(conds, text): | |
290 | """Return the result of making some text conditional under #if. The | |
291 | text ends with a newline, as does the return value if not empty.""" | |
292 | if '0' in conds: | |
293 | return '' | |
294 | conds = [c for c in conds if c != '1'] | |
295 | conds = sorted(set(conds)) | |
296 | if not conds: | |
297 | return text | |
298 | return '#if %s\n%s#endif\n' % (' && '.join(conds), text) | |
299 | ||
300 | class Tests(object): | |
301 | """The state associated with testcase generation.""" | |
302 | ||
303 | def __init__(self): | |
304 | """Initialize a Tests object.""" | |
fa562680 JM |
305 | self.header_list = ['#define __STDC_WANT_IEC_60559_TYPES_EXT__\n' |
306 | '#include <float.h>\n' | |
2dd0aec5 JM |
307 | '#include <stdbool.h>\n' |
308 | '#include <stdint.h>\n' | |
309 | '#include <stdio.h>\n' | |
310 | '#include <string.h>\n' | |
311 | '#include <tgmath.h>\n' | |
312 | '\n' | |
313 | 'struct test\n' | |
314 | ' {\n' | |
315 | ' void (*func) (void);\n' | |
316 | ' const char *func_name;\n' | |
317 | ' const char *test_name;\n' | |
318 | ' int mant_dig;\n' | |
319 | ' };\n' | |
320 | 'int num_pass, num_fail;\n' | |
321 | 'volatile int called_mant_dig;\n' | |
322 | 'const char *volatile called_func_name;\n' | |
2fee621d JM |
323 | 'enum e { E, F };\n' |
324 | 'struct s\n' | |
325 | ' {\n' | |
326 | ' int bf:2;\n' | |
327 | ' };\n'] | |
2dd0aec5 JM |
328 | float64_text = ('# if LDBL_MANT_DIG == DBL_MANT_DIG\n' |
329 | 'typedef _Float64 long_double_Float64;\n' | |
330 | 'typedef __CFLOAT64 complex_long_double_Float64;\n' | |
331 | '# else\n' | |
332 | 'typedef long double long_double_Float64;\n' | |
333 | 'typedef _Complex long double ' | |
334 | 'complex_long_double_Float64;\n' | |
335 | '# endif\n') | |
336 | float64_text = if_cond_text([Type.float64_type.condition], | |
337 | float64_text) | |
338 | float64x_text = ('# if LDBL_MANT_DIG == DBL_MANT_DIG\n' | |
339 | 'typedef _Float64x long_double_Float64x;\n' | |
340 | 'typedef __CFLOAT64X complex_long_double_Float64x;\n' | |
341 | '# else\n' | |
342 | 'typedef long double long_double_Float64x;\n' | |
343 | 'typedef _Complex long double ' | |
344 | 'complex_long_double_Float64x;\n' | |
345 | '# endif\n') | |
346 | float64x_text = if_cond_text([Type.float64x_type.condition], | |
347 | float64x_text) | |
348 | self.header_list.append(float64_text) | |
349 | self.header_list.append(float64x_text) | |
350 | self.types_seen = set() | |
351 | for t in Type.all_types_list: | |
352 | self.add_type_var(t.name, t.condition) | |
353 | self.test_text_list = [] | |
354 | self.test_array_list = [] | |
7c67e6e8 | 355 | self.macros_seen = set() |
2dd0aec5 JM |
356 | |
357 | def add_type_var(self, name, cond): | |
358 | """Add declarations of variables for a type.""" | |
359 | if name in self.types_seen: | |
360 | return | |
361 | t_vars = define_vars_for_type(name) | |
362 | self.header_list.append(if_cond_text([cond], t_vars)) | |
363 | self.types_seen.add(name) | |
364 | ||
365 | def add_tests(self, macro, ret, args, complex_func=None): | |
7c67e6e8 JM |
366 | """Add tests for a given tgmath.h macro, if that is the macro for |
367 | which tests are to be generated; otherwise just add it to the | |
368 | list of macros for which test generation is supported.""" | |
2dd0aec5 JM |
369 | # 'c' means the function argument or return type is |
370 | # type-generic and complex only (a complex function argument | |
371 | # may still have a real macro argument). 'g' means it is | |
372 | # type-generic and may be real or complex; 'r' means it is | |
373 | # type-generic and may only be real; 's' means the same as | |
374 | # 'r', but restricted to float, double and long double. | |
7c67e6e8 JM |
375 | self.macros_seen.add(macro) |
376 | if macro != self.macro: | |
377 | return | |
2dd0aec5 JM |
378 | have_complex = False |
379 | func = macro | |
380 | if ret == 'c' or 'c' in args: | |
381 | # Complex-only. | |
382 | have_complex = True | |
383 | complex_func = func | |
384 | func = None | |
385 | elif ret == 'g' or 'g' in args: | |
386 | # Real and complex. | |
387 | have_complex = True | |
388 | if complex_func == None: | |
389 | complex_func = 'c%s' % func | |
390 | types = [ret] + args | |
391 | for t in types: | |
392 | if t != 'c' and t != 'g' and t != 'r' and t != 's': | |
393 | self.add_type_var(t, '1') | |
394 | for t in Type.argument_types_list: | |
395 | if t.integer: | |
396 | continue | |
397 | if t.complex and not have_complex: | |
398 | continue | |
399 | if func == None and not t.complex: | |
400 | continue | |
401 | if ret == 's' and t.name.startswith('_Float'): | |
402 | continue | |
403 | if ret == 'c': | |
404 | ret_name = t.complex_type.name | |
405 | elif ret == 'g': | |
406 | ret_name = t.name | |
407 | elif ret == 'r' or ret == 's': | |
408 | ret_name = t.real_type.name | |
409 | else: | |
410 | ret_name = ret | |
411 | dummy_func_name = complex_func if t.complex else func | |
412 | arg_list = [] | |
413 | arg_num = 0 | |
414 | for a in args: | |
415 | if a == 'c': | |
416 | arg_name = t.complex_type.name | |
417 | elif a == 'g': | |
418 | arg_name = t.name | |
419 | elif a == 'r' or a == 's': | |
420 | arg_name = t.real_type.name | |
421 | else: | |
422 | arg_name = a | |
423 | arg_list.append('%s arg%d __attribute__ ((unused))' | |
424 | % (arg_name, arg_num)) | |
425 | arg_num += 1 | |
426 | dummy_func = ('%s\n' | |
427 | '(%s%s) (%s)\n' | |
428 | '{\n' | |
429 | ' called_mant_dig = %s;\n' | |
430 | ' called_func_name = "%s";\n' | |
431 | ' return 0;\n' | |
432 | '}\n' % (ret_name, dummy_func_name, | |
433 | t.real_type.suffix, ', '.join(arg_list), | |
434 | t.real_type.mant_dig, dummy_func_name)) | |
435 | dummy_func = if_cond_text([t.condition], dummy_func) | |
436 | self.test_text_list.append(dummy_func) | |
437 | arg_types = [] | |
438 | for t in args: | |
439 | if t == 'g' or t == 'c': | |
440 | arg_types.append(Type.argument_types_list) | |
441 | elif t == 'r': | |
442 | arg_types.append(Type.real_argument_types_list) | |
443 | elif t == 's': | |
444 | arg_types.append(Type.standard_real_argument_types_list) | |
445 | arg_types_product = list_product(arg_types) | |
446 | test_num = 0 | |
447 | for this_args in arg_types_product: | |
448 | comb_type = Type.combine_types(this_args) | |
449 | can_comb = Type.can_combine_types(this_args) | |
450 | all_conds = [t.condition for t in this_args] | |
451 | all_conds.append(can_comb) | |
452 | any_complex = func == None | |
453 | for t in this_args: | |
454 | if t.complex: | |
455 | any_complex = True | |
456 | func_name = complex_func if any_complex else func | |
457 | test_name = '%s (%s)' % (macro, | |
458 | ', '.join([t.name for t in this_args])) | |
459 | test_func_name = 'test_%s_%d' % (macro, test_num) | |
460 | test_num += 1 | |
461 | mant_dig = comb_type.real_type.mant_dig | |
462 | test_text = '%s, "%s", "%s", %s' % (test_func_name, func_name, | |
463 | test_name, mant_dig) | |
464 | test_text = ' { %s },\n' % test_text | |
465 | test_text = if_cond_text(all_conds, test_text) | |
466 | self.test_array_list.append(test_text) | |
467 | call_args = [] | |
468 | call_arg_pos = 0 | |
469 | for t in args: | |
470 | if t == 'g' or t == 'c' or t == 'r' or t == 's': | |
471 | type = this_args[call_arg_pos].name | |
472 | call_arg_pos += 1 | |
473 | else: | |
474 | type = t | |
475 | call_args.append(vol_var_for_type(type)) | |
476 | call_args_text = ', '.join(call_args) | |
477 | if ret == 'g': | |
478 | ret_type = comb_type.name | |
479 | elif ret == 'r' or ret == 's': | |
480 | ret_type = comb_type.real_type.name | |
481 | elif ret == 'c': | |
482 | ret_type = comb_type.complex_type.name | |
483 | else: | |
484 | ret_type = ret | |
485 | call_text = '%s (%s)' % (macro, call_args_text) | |
486 | test_func_text = ('static void\n' | |
487 | '%s (void)\n' | |
488 | '{\n' | |
489 | ' extern typeof (%s) %s ' | |
490 | '__attribute__ ((unused));\n' | |
491 | ' %s = %s;\n' | |
492 | '}\n' % (test_func_name, call_text, | |
493 | var_for_type(ret_type), | |
494 | vol_var_for_type(ret_type), call_text)) | |
495 | test_func_text = if_cond_text(all_conds, test_func_text) | |
496 | self.test_text_list.append(test_func_text) | |
497 | ||
7c67e6e8 JM |
498 | def add_all_tests(self, macro): |
499 | """Add tests for the given tgmath.h macro, if any, and generate the | |
500 | list of all supported macros.""" | |
501 | self.macro = macro | |
2dd0aec5 JM |
502 | # C99/C11 real-only functions. |
503 | self.add_tests('atan2', 'r', ['r', 'r']) | |
504 | self.add_tests('cbrt', 'r', ['r']) | |
505 | self.add_tests('ceil', 'r', ['r']) | |
506 | self.add_tests('copysign', 'r', ['r', 'r']) | |
507 | self.add_tests('erf', 'r', ['r']) | |
508 | self.add_tests('erfc', 'r', ['r']) | |
509 | self.add_tests('exp2', 'r', ['r']) | |
510 | self.add_tests('expm1', 'r', ['r']) | |
511 | self.add_tests('fdim', 'r', ['r', 'r']) | |
512 | self.add_tests('floor', 'r', ['r']) | |
513 | self.add_tests('fma', 'r', ['r', 'r', 'r']) | |
514 | self.add_tests('fmax', 'r', ['r', 'r']) | |
515 | self.add_tests('fmin', 'r', ['r', 'r']) | |
516 | self.add_tests('fmod', 'r', ['r', 'r']) | |
517 | self.add_tests('frexp', 'r', ['r', 'int *']) | |
518 | self.add_tests('hypot', 'r', ['r', 'r']) | |
519 | self.add_tests('ilogb', 'int', ['r']) | |
520 | self.add_tests('ldexp', 'r', ['r', 'int']) | |
521 | self.add_tests('lgamma', 'r', ['r']) | |
522 | self.add_tests('llrint', 'long long int', ['r']) | |
523 | self.add_tests('llround', 'long long int', ['r']) | |
0908a38a JM |
524 | # log10 is real-only in ISO C, but supports complex arguments |
525 | # as a GNU extension. | |
526 | self.add_tests('log10', 'g', ['g']) | |
2dd0aec5 JM |
527 | self.add_tests('log1p', 'r', ['r']) |
528 | self.add_tests('log2', 'r', ['r']) | |
529 | self.add_tests('logb', 'r', ['r']) | |
530 | self.add_tests('lrint', 'long int', ['r']) | |
531 | self.add_tests('lround', 'long int', ['r']) | |
532 | self.add_tests('nearbyint', 'r', ['r']) | |
533 | self.add_tests('nextafter', 'r', ['r', 'r']) | |
534 | self.add_tests('nexttoward', 's', ['s', 'long double']) | |
535 | self.add_tests('remainder', 'r', ['r', 'r']) | |
536 | self.add_tests('remquo', 'r', ['r', 'r', 'int *']) | |
537 | self.add_tests('rint', 'r', ['r']) | |
538 | self.add_tests('round', 'r', ['r']) | |
539 | self.add_tests('scalbn', 'r', ['r', 'int']) | |
540 | self.add_tests('scalbln', 'r', ['r', 'long int']) | |
541 | self.add_tests('tgamma', 'r', ['r']) | |
542 | self.add_tests('trunc', 'r', ['r']) | |
543 | # C99/C11 real-and-complex functions. | |
544 | self.add_tests('acos', 'g', ['g']) | |
545 | self.add_tests('asin', 'g', ['g']) | |
546 | self.add_tests('atan', 'g', ['g']) | |
547 | self.add_tests('acosh', 'g', ['g']) | |
548 | self.add_tests('asinh', 'g', ['g']) | |
549 | self.add_tests('atanh', 'g', ['g']) | |
550 | self.add_tests('cos', 'g', ['g']) | |
551 | self.add_tests('sin', 'g', ['g']) | |
552 | self.add_tests('tan', 'g', ['g']) | |
553 | self.add_tests('cosh', 'g', ['g']) | |
554 | self.add_tests('sinh', 'g', ['g']) | |
555 | self.add_tests('tanh', 'g', ['g']) | |
556 | self.add_tests('exp', 'g', ['g']) | |
557 | self.add_tests('log', 'g', ['g']) | |
558 | self.add_tests('pow', 'g', ['g', 'g']) | |
559 | self.add_tests('sqrt', 'g', ['g']) | |
560 | self.add_tests('fabs', 'r', ['g'], 'cabs') | |
561 | # C99/C11 complex-only functions. | |
562 | self.add_tests('carg', 'r', ['c']) | |
563 | self.add_tests('cimag', 'r', ['c']) | |
564 | self.add_tests('conj', 'c', ['c']) | |
565 | self.add_tests('cproj', 'c', ['c']) | |
566 | self.add_tests('creal', 'r', ['c']) | |
567 | # TS 18661-1 functions. | |
568 | self.add_tests('roundeven', 'r', ['r']) | |
569 | self.add_tests('nextup', 'r', ['r']) | |
570 | self.add_tests('nextdown', 'r', ['r']) | |
571 | self.add_tests('fminmag', 'r', ['r', 'r']) | |
572 | self.add_tests('fmaxmag', 'r', ['r', 'r']) | |
573 | self.add_tests('llogb', 'long int', ['r']) | |
574 | self.add_tests('fromfp', 'intmax_t', ['r', 'int', 'unsigned int']) | |
575 | self.add_tests('fromfpx', 'intmax_t', ['r', 'int', 'unsigned int']) | |
576 | self.add_tests('ufromfp', 'uintmax_t', ['r', 'int', 'unsigned int']) | |
577 | self.add_tests('ufromfpx', 'uintmax_t', ['r', 'int', 'unsigned int']) | |
d12a22c5 JM |
578 | self.add_tests('totalorder', 'int', ['r', 'r']) |
579 | self.add_tests('totalordermag', 'int', ['r', 'r']) | |
2dd0aec5 JM |
580 | # The functions that round their result to a narrower type, |
581 | # and the associated type-generic macros, are not yet | |
582 | # supported by this script or by glibc. | |
583 | # Miscellaneous functions. | |
584 | self.add_tests('scalb', 's', ['s', 's']) | |
585 | ||
586 | def tests_text(self): | |
587 | """Return the text of the generated testcase.""" | |
588 | test_list = [''.join(self.test_text_list), | |
589 | 'static const struct test tests[] =\n' | |
590 | ' {\n', | |
591 | ''.join(self.test_array_list), | |
592 | ' };\n'] | |
593 | footer_list = ['static int\n' | |
594 | 'do_test (void)\n' | |
595 | '{\n' | |
596 | ' for (size_t i = 0;\n' | |
597 | ' i < sizeof (tests) / sizeof (tests[0]);\n' | |
598 | ' i++)\n' | |
599 | ' {\n' | |
600 | ' called_mant_dig = 0;\n' | |
601 | ' called_func_name = "";\n' | |
602 | ' tests[i].func ();\n' | |
603 | ' if (called_mant_dig == tests[i].mant_dig\n' | |
604 | ' && strcmp (called_func_name,\n' | |
605 | ' tests[i].func_name) == 0)\n' | |
606 | ' num_pass++;\n' | |
607 | ' else\n' | |
608 | ' {\n' | |
609 | ' num_fail++;\n' | |
610 | ' printf ("Test %zu (%s):\\n"\n' | |
611 | ' " Expected: %s precision %d\\n"\n' | |
612 | ' " Actual: %s precision %d\\n\\n",\n' | |
613 | ' i, tests[i].test_name,\n' | |
614 | ' tests[i].func_name,\n' | |
615 | ' tests[i].mant_dig,\n' | |
616 | ' called_func_name, called_mant_dig);\n' | |
617 | ' }\n' | |
618 | ' }\n' | |
619 | ' printf ("%d pass, %d fail\\n", num_pass, num_fail);\n' | |
620 | ' return num_fail != 0;\n' | |
621 | '}\n' | |
622 | '\n' | |
623 | '#include <support/test-driver.c>'] | |
624 | return ''.join(self.header_list + test_list + footer_list) | |
625 | ||
7c67e6e8 JM |
626 | def check_macro_list(self, macro_list): |
627 | """Check the list of macros that can be tested.""" | |
628 | if self.macros_seen != set(macro_list): | |
629 | print('error: macro list mismatch') | |
630 | sys.exit(1) | |
631 | ||
2dd0aec5 JM |
632 | def main(): |
633 | """The main entry point.""" | |
634 | Type.init_types() | |
635 | t = Tests() | |
7c67e6e8 JM |
636 | if sys.argv[1] == 'check-list': |
637 | macro = None | |
638 | macro_list = sys.argv[2:] | |
639 | else: | |
640 | macro = sys.argv[1] | |
641 | macro_list = [] | |
642 | t.add_all_tests(macro) | |
643 | if macro: | |
644 | print(t.tests_text()) | |
645 | else: | |
646 | t.check_macro_list(macro_list) | |
2dd0aec5 JM |
647 | |
648 | if __name__ == '__main__': | |
649 | main() |