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