You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
938 lines
44 KiB
938 lines
44 KiB
commit 8a78f833d670f86302f2d0c32eb1e4357d9166ff |
|
Author: Joseph Myers <joseph@codesourcery.com> |
|
Date: Fri Jan 6 19:33:29 2023 +0000 |
|
|
|
C2x semantics for <tgmath.h> |
|
|
|
<tgmath.h> implements semantics for integer generic arguments that |
|
handle cases involving _FloatN / _FloatNx types as specified in TS |
|
18661-3 plus some defect fixes. |
|
|
|
C2x has further changes to the semantics for <tgmath.h> macros with |
|
such types, which should also be considered defect fixes (although |
|
handled through the integration of TS 18661-3 in C2x rather than |
|
through an issue tracking process). Specifically, the rules were |
|
changed because of problems raised with using the macros with the |
|
evaluation format types such as float_t and _Float32_t: the older |
|
version of the rules didn't allow passing _FloatN / _FloatNx types to |
|
the narrowing macros returning float or double, or passing float / |
|
double / long double to the narrowing macros returning _FloatN / |
|
_FloatNx, which was a problem with the evaluation format types which |
|
could be either kind of type depending on the value of |
|
FLT_EVAL_METHOD. |
|
|
|
Thus the new rules allow cases of mixing types which were not allowed |
|
before, and, as part of the changes, the handling of integer arguments |
|
was also changed: if there is any _FloatNx generic argument, integer |
|
generic arguments are treated as _Float32x (not double), while the |
|
rule about treating integer arguments to narrowing macros returning |
|
_FloatN or _FloatNx as _Float64 not double was removed (no longer |
|
needed now double is a valid argument to such macros). |
|
|
|
I've implemented the changes in GCC's __builtin_tgmath, which thus |
|
requires updates to glibc's test expectations so that the tests |
|
continue to build with GCC 13 (the test is also updated to test the |
|
argument types that weren't allowed before but are now valid under C2x |
|
rules). |
|
|
|
Given those test changes, it's then also necessary to fix the |
|
implementations in <tgmath.h> to have appropriate semantics with older |
|
GCC so that the tests pass with GCC versions before GCC 13 as well. |
|
For some cases (non-narrowing macros with two or three generic |
|
arguments; narrowing macros returning _Float32x), the older version of |
|
__builtin_tgmath doesn't correspond sufficiently well to C2x |
|
semantics, so in those cases <tgmath.h> is adjusted to use the older |
|
macro implementation instead of __builtin_tgmath. The older macro |
|
implementation is itself adjusted to give the desired semantics, with |
|
GCC 7 and later. (It's not possible to get the right semantics in all |
|
cases for the narrowing macros with GCC 6 and before when the _FloatN |
|
/ _FloatNx names are typedefs rather than distinct types.) |
|
|
|
Tested as follows: with the full glibc testsuite for x86_64, GCC 6, 7, |
|
11, 13; with execution of the math/tests for aarch64, arm, powerpc and |
|
powerpc64le, GCC 6, 7, 12 and 13 (powerpc64le only with GCC 12 and |
|
13); with build-many-glibcs.py with GCC 6, 7, 12 and 13. |
|
|
|
Conflicts: |
|
math/tgmath.h |
|
(missing support for narrowing fma/sqrt downstream |
|
means that the definitions for __TGMATH_1_NARROW_* |
|
and __TGMATH_3_NARROW_* are not needed) |
|
|
|
diff --git a/math/gen-tgmath-tests.py b/math/gen-tgmath-tests.py |
|
index 364963da6525e08d..be5e8cd9a07ef071 100755 |
|
--- a/math/gen-tgmath-tests.py |
|
+++ b/math/gen-tgmath-tests.py |
|
@@ -19,14 +19,13 @@ |
|
|
|
# As glibc does not support decimal floating point, the types to |
|
# consider for generic parameters are standard and binary |
|
-# floating-point types, and integer types which are treated as double. |
|
-# The corresponding complex types may also be used (including complex |
|
-# integer types, which are a GNU extension, but are currently disabled |
|
-# here because they do not work properly with tgmath.h). |
|
- |
|
-# The proposed resolution to TS 18661-1 DR#9 |
|
-# <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2149.htm#dr_9> |
|
-# makes the <tgmath.h> rules for selecting a function to call |
|
+# floating-point types, and integer types which are treated as |
|
+# _Float32x if any argument has a _FloatNx type and otherwise as |
|
+# double. The corresponding complex types may also be used (including |
|
+# complex integer types, which are a GNU extension, but are currently |
|
+# disabled here because they do not work properly with tgmath.h). |
|
+ |
|
+# C2x makes the <tgmath.h> rules for selecting a function to call |
|
# correspond to the usual arithmetic conversions (applied successively |
|
# to the arguments for generic parameters in order), which choose the |
|
# type whose set of values contains that of the other type (undefined |
|
@@ -69,10 +68,6 @@ class Type(object): |
|
# Real argument types that correspond to a standard floating type |
|
# (float, double or long double; not _FloatN or _FloatNx). |
|
standard_real_argument_types_list = [] |
|
- # Real argument types other than float, double and long double |
|
- # (i.e., those that are valid as arguments to narrowing macros |
|
- # returning _FloatN or _FloatNx). |
|
- non_standard_real_argument_types_list = [] |
|
# The real floating types by their order properties (which are |
|
# tuples giving the positions in both the possible orders above). |
|
real_types_order = {} |
|
@@ -86,13 +81,16 @@ class Type(object): |
|
float64_type = None |
|
# The type _Complex _Float64. |
|
complex_float64_type = None |
|
+ # The type _Float32x. |
|
+ float32x_type = None |
|
+ # The type _Complex _Float32x. |
|
+ complex_float32x_type = None |
|
# The type _Float64x. |
|
float64x_type = None |
|
- # The type _Float64x if available, otherwise _Float64. |
|
- float32x_ext_type = None |
|
|
|
def __init__(self, name, suffix=None, mant_dig=None, condition='1', |
|
- order=None, integer=False, complex=False, real_type=None): |
|
+ order=None, integer=False, complex=False, real_type=None, |
|
+ floatnx=False): |
|
"""Initialize a Type object, creating any corresponding complex type |
|
in the process.""" |
|
self.name = name |
|
@@ -102,6 +100,7 @@ class Type(object): |
|
self.order = order |
|
self.integer = integer |
|
self.complex = complex |
|
+ self.floatnx = floatnx |
|
if complex: |
|
self.complex_type = self |
|
self.real_type = real_type |
|
@@ -119,8 +118,6 @@ class Type(object): |
|
Type.real_argument_types_list.append(self) |
|
if not self.name.startswith('_Float'): |
|
Type.standard_real_argument_types_list.append(self) |
|
- if self.name not in ('float', 'double', 'long double'): |
|
- Type.non_standard_real_argument_types_list.append(self) |
|
if self.order is not None: |
|
Type.real_types_order[self.order] = self |
|
if self.name == 'double': |
|
@@ -133,26 +130,28 @@ class Type(object): |
|
Type.float64_type = self |
|
if self.name == '_Complex _Float64': |
|
Type.complex_float64_type = self |
|
+ if self.name == '_Float32x': |
|
+ Type.float32x_type = self |
|
+ if self.name == '_Complex _Float32x': |
|
+ Type.complex_float32x_type = self |
|
if self.name == '_Float64x': |
|
Type.float64x_type = self |
|
- if self.name == 'Float32x_ext': |
|
- Type.float32x_ext_type = self |
|
|
|
@staticmethod |
|
def create_type(name, suffix=None, mant_dig=None, condition='1', order=None, |
|
integer=False, complex_name=None, complex_ok=True, |
|
- internal=False): |
|
+ floatnx=False, internal=False): |
|
"""Create and register a Type object for a real type, creating any |
|
corresponding complex type in the process.""" |
|
real_type = Type(name, suffix=suffix, mant_dig=mant_dig, |
|
condition=condition, order=order, integer=integer, |
|
- complex=False) |
|
+ complex=False, floatnx=floatnx) |
|
if complex_ok: |
|
if complex_name is None: |
|
complex_name = '_Complex %s' % name |
|
complex_type = Type(complex_name, condition=condition, |
|
integer=integer, complex=True, |
|
- real_type=real_type) |
|
+ real_type=real_type, floatnx=floatnx) |
|
else: |
|
complex_type = None |
|
real_type.complex_type = complex_type |
|
@@ -160,13 +159,13 @@ class Type(object): |
|
if complex_type is not None: |
|
complex_type.register_type(internal) |
|
|
|
- def floating_type(self, floatn): |
|
+ def floating_type(self, integer_float32x): |
|
"""Return the corresponding floating type.""" |
|
if self.integer: |
|
- if floatn: |
|
- return (Type.complex_float64_type |
|
+ if integer_float32x: |
|
+ return (Type.complex_float32x_type |
|
if self.complex |
|
- else Type.float64_type) |
|
+ else Type.float32x_type) |
|
else: |
|
return (Type.complex_double_type |
|
if self.complex |
|
@@ -174,9 +173,9 @@ class Type(object): |
|
else: |
|
return self |
|
|
|
- def real_floating_type(self, floatn): |
|
+ def real_floating_type(self, integer_float32x): |
|
"""Return the corresponding real floating type.""" |
|
- return self.real_type.floating_type(floatn) |
|
+ return self.real_type.floating_type(integer_float32x) |
|
|
|
def __str__(self): |
|
"""Return string representation of a type.""" |
|
@@ -194,7 +193,8 @@ class Type(object): |
|
condition='defined HUGE_VAL_F32', order=(2, 2)) |
|
Type.create_type('_Float32x', 'f32x', 'FLT32X_MANT_DIG', |
|
complex_name='__CFLOAT32X', |
|
- condition='defined HUGE_VAL_F32X', order=(3, 3)) |
|
+ condition='defined HUGE_VAL_F32X', order=(3, 3), |
|
+ floatnx=True) |
|
Type.create_type('double', '', 'DBL_MANT_DIG', order=(4, 4)) |
|
Type.create_type('long double', 'l', 'LDBL_MANT_DIG', order=(5, 7)) |
|
Type.create_type('_Float64', 'f64', 'FLT64_MANT_DIG', |
|
@@ -202,7 +202,8 @@ class Type(object): |
|
condition='defined HUGE_VAL_F64', order=(6, 5)) |
|
Type.create_type('_Float64x', 'f64x', 'FLT64X_MANT_DIG', |
|
complex_name='__CFLOAT64X', |
|
- condition='defined HUGE_VAL_F64X', order=(7, 6)) |
|
+ condition='defined HUGE_VAL_F64X', order=(7, 6), |
|
+ floatnx=True) |
|
Type.create_type('_Float128', 'f128', 'FLT128_MANT_DIG', |
|
complex_name='__CFLOAT128', |
|
condition='defined HUGE_VAL_F128', order=(8, 8)) |
|
@@ -235,21 +236,16 @@ class Type(object): |
|
complex_name='complex_long_double_Float64x', |
|
condition='defined HUGE_VAL_F64X', order=(7, 7), |
|
internal=True) |
|
- # An internal type for the argument type used by f32x* |
|
- # narrowing macros (_Float64x if available, otherwise |
|
- # _Float64). |
|
- Type.create_type('Float32x_ext', None, 'FLT32X_EXT_MANT_DIG', |
|
- complex_name='complex_Float32x_ext', |
|
- condition='1', internal=True) |
|
|
|
@staticmethod |
|
- def can_combine_types(types, floatn): |
|
+ def can_combine_types(types): |
|
"""Return a C preprocessor conditional for whether the given list of |
|
types can be used together as type-generic macro arguments.""" |
|
have_long_double = False |
|
have_float128 = False |
|
+ integer_float32x = any(t.floatnx for t in types) |
|
for t in types: |
|
- t = t.real_floating_type(floatn) |
|
+ t = t.real_floating_type(integer_float32x) |
|
if t.name == 'long double': |
|
have_long_double = True |
|
if t.name == '_Float128' or t.name == '_Float64x': |
|
@@ -262,14 +258,15 @@ class Type(object): |
|
return '1' |
|
|
|
@staticmethod |
|
- def combine_types(types, floatn): |
|
+ def combine_types(types): |
|
"""Return the result of combining a set of types.""" |
|
have_complex = False |
|
combined = None |
|
+ integer_float32x = any(t.floatnx for t in types) |
|
for t in types: |
|
if t.complex: |
|
have_complex = True |
|
- t = t.real_floating_type(floatn) |
|
+ t = t.real_floating_type(integer_float32x) |
|
if combined is None: |
|
combined = t |
|
else: |
|
@@ -375,18 +372,8 @@ class Tests(object): |
|
'# endif\n') |
|
float64x_text = if_cond_text([Type.float64x_type.condition], |
|
float64x_text) |
|
- float32x_ext_text = ('#ifdef HUGE_VAL_F64X\n' |
|
- 'typedef _Float64x Float32x_ext;\n' |
|
- 'typedef __CFLOAT64X complex_Float32x_ext;\n' |
|
- '# define FLT32X_EXT_MANT_DIG FLT64X_MANT_DIG\n' |
|
- '#else\n' |
|
- 'typedef _Float64 Float32x_ext;\n' |
|
- 'typedef __CFLOAT64 complex_Float32x_ext;\n' |
|
- '# define FLT32X_EXT_MANT_DIG FLT64_MANT_DIG\n' |
|
- '#endif\n') |
|
self.header_list.append(float64_text) |
|
self.header_list.append(float64x_text) |
|
- self.header_list.append(float32x_ext_text) |
|
self.types_seen = set() |
|
for t in Type.all_types_list: |
|
self.add_type_var(t.name, t.condition) |
|
@@ -439,39 +426,33 @@ class Tests(object): |
|
narrowing_std = True |
|
narrow_cond = '1' |
|
narrow_args = [Type.double_type, Type.long_double_type] |
|
- narrow_fallback = Type.double_type |
|
elif ret == 'double': |
|
narrowing = True |
|
narrowing_std = True |
|
narrow_cond = '1' |
|
narrow_args = [Type.long_double_type] |
|
- narrow_fallback = Type.long_double_type |
|
elif ret.startswith('_Float'): |
|
narrowing = True |
|
- narrow_args = [] |
|
+ narrow_args_1 = [] |
|
+ narrow_args_2 = [] |
|
nret_type = None |
|
- narrow_fallback = None |
|
for order, real_type in sorted(Type.real_types_order.items()): |
|
if real_type.name == ret: |
|
nret_type = real_type |
|
elif nret_type and real_type.name.startswith('_Float'): |
|
- narrow_args.append(real_type) |
|
- if (narrow_fallback is None |
|
- and ret.endswith('x') == real_type.name.endswith('x')): |
|
- narrow_fallback = real_type |
|
+ if ret.endswith('x') == real_type.name.endswith('x'): |
|
+ narrow_args_1.append(real_type) |
|
+ else: |
|
+ narrow_args_2.append(real_type) |
|
+ narrow_args = narrow_args_1 + narrow_args_2 |
|
if narrow_args: |
|
narrow_cond = ('(%s && (%s))' |
|
% (nret_type.condition, |
|
' || '.join(t.condition |
|
for t in narrow_args))) |
|
- if narrow_fallback is None: |
|
- narrow_fallback = narrow_args[0] |
|
- if ret == '_Float32x': |
|
- narrow_fallback = Type.float32x_ext_type |
|
else: |
|
# No possible argument types, even conditionally. |
|
narrow_cond = '0' |
|
- narrowing_nonstd = narrowing and not narrowing_std |
|
types = [ret] + args |
|
for t in types: |
|
if t != 'c' and t != 'g' and t != 'r' and t != 's': |
|
@@ -530,19 +511,13 @@ class Tests(object): |
|
if t == 'g' or t == 'c': |
|
arg_types.append(Type.argument_types_list) |
|
elif t == 'r': |
|
- if narrowing_std: |
|
- arg_types.append(Type.standard_real_argument_types_list) |
|
- elif narrowing: |
|
- arg_types.append( |
|
- Type.non_standard_real_argument_types_list) |
|
- else: |
|
- arg_types.append(Type.real_argument_types_list) |
|
+ arg_types.append(Type.real_argument_types_list) |
|
elif t == 's': |
|
arg_types.append(Type.standard_real_argument_types_list) |
|
arg_types_product = list_product(arg_types) |
|
test_num = 0 |
|
for this_args in arg_types_product: |
|
- comb_type = Type.combine_types(this_args, narrowing_nonstd) |
|
+ comb_type = Type.combine_types(this_args) |
|
if narrowing: |
|
# As long as there are no integer arguments, and as |
|
# long as the chosen argument type is as wide as all |
|
@@ -550,22 +525,22 @@ class Tests(object): |
|
# of the macro call do not depend on the exact |
|
# function chosen. In particular, for f32x functions |
|
# when _Float64x exists, the chosen type should differ |
|
- # for _Float32x and _Float64 arguments, but it is not |
|
- # always possible to distinguish those types before |
|
- # GCC 7 and the implementation does not attempt to do |
|
- # so before GCC 8. |
|
+ # for double / _Float32x and _Float64 arguments, but |
|
+ # it is not always possible to distinguish those types |
|
+ # before GCC 7 (resulting in some cases - only real |
|
+ # arguments - where a wider argument type is used, |
|
+ # which is semantically OK, and others - integer |
|
+ # arguments present - where it may not be OK, but is |
|
+ # unavoidable). |
|
narrow_mant_dig = comb_type.real_type.mant_dig |
|
for arg_type in this_args: |
|
if arg_type.integer: |
|
narrow_mant_dig = 0 |
|
else: |
|
narrow_mant_dig = 0 |
|
- if (narrowing |
|
- and comb_type not in narrow_args |
|
- and narrow_fallback is not None): |
|
- comb_type = narrow_fallback |
|
- can_comb = Type.can_combine_types(this_args, narrowing_nonstd) |
|
+ can_comb = Type.can_combine_types(this_args) |
|
all_conds = [t.condition for t in this_args] |
|
+ narrow_args_cond = '(%s)' % ' && '.join(sorted(set(all_conds))) |
|
all_conds.append(can_comb) |
|
if narrowing: |
|
all_conds.append(narrow_cond) |
|
@@ -579,10 +554,69 @@ class Tests(object): |
|
test_func_name = 'test_%s_%d' % (macro, test_num) |
|
test_num += 1 |
|
mant_dig = comb_type.real_type.mant_dig |
|
+ test_mant_dig_comp = '' |
|
+ if (narrowing |
|
+ and comb_type not in narrow_args): |
|
+ # The expected argument type is the first in |
|
+ # narrow_args that can represent all the values of |
|
+ # comb_type (which, for the supported cases, means the |
|
+ # first with mant_dig at least as large as that for |
|
+ # comb_type, provided this isn't the case of an IBM |
|
+ # long double argument with binary128 type from |
|
+ # narrow_args). |
|
+ narrow_extra_conds = [] |
|
+ test_mant_dig_list = ['#undef NARROW_MANT_DIG\n#if 0\n'] |
|
+ for t in narrow_args: |
|
+ t_cond = '(%s && %s && %s <= %s && %s)' % ( |
|
+ narrow_args_cond, t.condition, mant_dig, t.mant_dig, |
|
+ Type.can_combine_types(this_args + [t])) |
|
+ narrow_extra_conds.append(t_cond) |
|
+ test_mant_dig_list.append('#elif %s\n' |
|
+ '#define NARROW_MANT_DIG %s\n' |
|
+ % (t_cond, t.mant_dig)) |
|
+ test_mant_dig_list.append('#endif\n') |
|
+ test_mant_dig_comp = ''.join(test_mant_dig_list) |
|
+ all_conds.append('(%s)' % ' || '.join(narrow_extra_conds)) |
|
+ # A special case where this logic isn't correct is |
|
+ # where comb_type is the internal long_double_Float64 |
|
+ # or long_double_Float64x, which will be detected as |
|
+ # not in narrow_args even if the actual type chosen in |
|
+ # a particular configuration would have been in |
|
+ # narrow_args, so check for that case and handle it |
|
+ # appropriately. In particular, if long double has |
|
+ # the same format as double and there are long double |
|
+ # and _Float64 arguments, and the macro returns |
|
+ # _Float32x, the function called should be one for |
|
+ # _Float64 arguments, not one for _Float64x arguments |
|
+ # that would arise from this logic. |
|
+ if comb_type.real_type.name == 'long_double_Float64': |
|
+ comb_type_1 = Type.long_double_type |
|
+ comb_type_2 = Type.float64_type |
|
+ comb_type_is_2_cond = 'LDBL_MANT_DIG <= FLT64_MANT_DIG' |
|
+ elif comb_type.real_type.name == 'long_double_Float64x': |
|
+ comb_type_1 = Type.long_double_type |
|
+ comb_type_2 = Type.float64x_type |
|
+ comb_type_is_2_cond = 'LDBL_MANT_DIG < FLT64X_MANT_DIG' |
|
+ else: |
|
+ comb_type_1 = None |
|
+ comb_type_2 = None |
|
+ if comb_type_1 is None: |
|
+ mant_dig = 'NARROW_MANT_DIG' |
|
+ else: |
|
+ mant_dig = '' |
|
+ if comb_type_1 in narrow_args: |
|
+ mant_dig += '!(%s) ? %s : ' % (comb_type_is_2_cond, |
|
+ comb_type_1.mant_dig) |
|
+ if comb_type_2 in narrow_args: |
|
+ mant_dig += '%s ? %s : ' % (comb_type_is_2_cond, |
|
+ comb_type_2.mant_dig) |
|
+ mant_dig += 'NARROW_MANT_DIG' |
|
+ if narrow_mant_dig != 0: |
|
+ narrow_mant_dig = mant_dig |
|
test_text = '%s, "%s", "%s", %s, %s' % (test_func_name, func_name, |
|
test_name, mant_dig, |
|
narrow_mant_dig) |
|
- test_text = ' { %s },\n' % test_text |
|
+ test_text = '%s { %s },\n' % (test_mant_dig_comp, test_text) |
|
test_text = if_cond_text(all_conds, test_text) |
|
self.test_array_list.append(test_text) |
|
call_args = [] |
|
@@ -730,7 +764,7 @@ class Tests(object): |
|
' && strcmp (called_func_name,\n' |
|
' tests[i].func_name) == 0)\n' |
|
' num_pass++;\n' |
|
- '#if !__GNUC_PREREQ (8, 0)\n' |
|
+ '#if !__GNUC_PREREQ (7, 0)\n' |
|
' else if (tests[i].narrow_mant_dig > 0\n' |
|
' && (called_mant_dig\n' |
|
' >= tests[i].narrow_mant_dig)\n' |
|
@@ -747,6 +781,21 @@ class Tests(object): |
|
' tests[i].mant_dig,\n' |
|
' called_func_name, called_mant_dig);\n' |
|
' }\n' |
|
+ ' else if (tests[i].narrow_mant_dig == 0\n' |
|
+ ' && strcmp (called_func_name,\n' |
|
+ ' tests[i].func_name) == 0)\n' |
|
+ ' {\n' |
|
+ ' num_pass++;\n' |
|
+ ' printf ("Test %zu (%s):\\n"\n' |
|
+ ' " Expected: %s precision %d\\n"\n' |
|
+ ' " Actual: %s precision %d\\n"\n' |
|
+ ' " (unavoidable with old GCC)' |
|
+ '\\n\\n",\n' |
|
+ ' i, tests[i].test_name,\n' |
|
+ ' tests[i].func_name,\n' |
|
+ ' tests[i].mant_dig,\n' |
|
+ ' called_func_name, called_mant_dig);\n' |
|
+ ' }\n' |
|
'#endif\n' |
|
' else\n' |
|
' {\n' |
|
diff --git a/math/tgmath.h b/math/tgmath.h |
|
index b55cb39c93575ddc..dbd165dd1882dcc4 100644 |
|
--- a/math/tgmath.h |
|
+++ b/math/tgmath.h |
|
@@ -37,9 +37,17 @@ |
|
for older GCC, using other compiler extensions but with macros |
|
expanding their arguments many times (so resulting in exponential |
|
blowup of the size of expansions when calls to such macros are |
|
- nested inside arguments to such macros). */ |
|
+ nested inside arguments to such macros). Because of a long series |
|
+ of defect fixes made after the initial release of TS 18661-1, GCC |
|
+ versions before GCC 13 have __builtin_tgmath semantics that, when |
|
+ integer arguments are passed to narrowing macros returning |
|
+ _Float32x, or non-narrowing macros with at least two generic |
|
+ arguments, do not always correspond to the C2X semantics, so more |
|
+ complicated macro definitions are also used in some cases for |
|
+ versions from GCC 8 to GCC 12. */ |
|
|
|
#define __HAVE_BUILTIN_TGMATH __GNUC_PREREQ (8, 0) |
|
+#define __HAVE_BUILTIN_TGMATH_C2X __GNUC_PREREQ (13, 0) |
|
|
|
#if __GNUC_PREREQ (2, 7) |
|
|
|
@@ -135,13 +143,14 @@ |
|
__builtin_tgmath (__TGMATH_NARROW_FUNCS_F32 (F) (X), (Y)) |
|
# define __TGMATH_2_NARROW_F64(F, X, Y) \ |
|
__builtin_tgmath (__TGMATH_NARROW_FUNCS_F64 (F) (X), (Y)) |
|
-# if __HAVE_FLOAT128 |
|
+# if __HAVE_FLOAT128 && __HAVE_BUILTIN_TGMATH_C2X |
|
# define __TGMATH_2_NARROW_F32X(F, X, Y) \ |
|
__builtin_tgmath (__TGMATH_NARROW_FUNCS_F32X (F) (X), (Y)) |
|
# endif |
|
|
|
-# else /* !__HAVE_BUILTIN_TGMATH. */ |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH_C2X |
|
# ifdef __NO_LONG_DOUBLE_MATH |
|
# define __tgml(fct) fct |
|
# else |
|
@@ -181,13 +190,17 @@ |
|
/* Whether an expression (of arithmetic type) has a real type. */ |
|
# define __expr_is_real(E) (__builtin_classify_type (E) != 9) |
|
|
|
+/* Type T1 if E is 1, type T2 is E is 0. */ |
|
+# define __tgmath_type_if(T1, T2, E) \ |
|
+ __typeof__ (*(0 ? (__typeof__ (0 ? (T2 *) 0 : (void *) (E))) 0 \ |
|
+ : (__typeof__ (0 ? (T1 *) 0 : (void *) (!(E)))) 0)) |
|
+ |
|
/* The tgmath real type for T, where E is 0 if T is an integer type |
|
and 1 for a floating type. If T has a complex type, it is |
|
unspecified whether the return type is real or complex (but it has |
|
the correct corresponding real type). */ |
|
# define __tgmath_real_type_sub(T, E) \ |
|
- __typeof__ (*(0 ? (__typeof__ (0 ? (double *) 0 : (void *) (E))) 0 \ |
|
- : (__typeof__ (0 ? (T *) 0 : (void *) (!(E)))) 0)) |
|
+ __tgmath_type_if (T, double, E) |
|
|
|
/* The tgmath real type of EXPR. */ |
|
# define __tgmath_real_type(expr) \ |
|
@@ -215,6 +228,56 @@ |
|
__real_integer_type (__typeof__ (+(expr))), \ |
|
__complex_integer_type (__typeof__ (+(expr)))) |
|
|
|
+/* The tgmath real type of EXPR1 combined with EXPR2, without handling |
|
+ the C2X rule of interpreting integer arguments as _Float32x if any |
|
+ argument is _FloatNx. */ |
|
+# define __tgmath_real_type2_base(expr1, expr2) \ |
|
+ __typeof ((__tgmath_real_type (expr1)) 0 + (__tgmath_real_type (expr2)) 0) |
|
+ |
|
+/* The tgmath complex type of EXPR1 combined with EXPR2, without |
|
+ handling the C2X rule of interpreting integer arguments as |
|
+ _Float32x if any argument is _FloatNx. */ |
|
+# define __tgmath_complex_type2_base(expr1, expr2) \ |
|
+ __typeof ((__tgmath_complex_type (expr1)) 0 \ |
|
+ + (__tgmath_complex_type (expr2)) 0) |
|
+ |
|
+/* The tgmath real type of EXPR1 combined with EXPR2 and EXPR3, |
|
+ without handling the C2X rule of interpreting integer arguments as |
|
+ _Float32x if any argument is _FloatNx. */ |
|
+# define __tgmath_real_type3_base(expr1, expr2, expr3) \ |
|
+ __typeof ((__tgmath_real_type (expr1)) 0 \ |
|
+ + (__tgmath_real_type (expr2)) 0 \ |
|
+ + (__tgmath_real_type (expr3)) 0) |
|
+ |
|
+/* The tgmath real or complex type of EXPR1 combined with EXPR2 (and |
|
+ EXPR3 if applicable). */ |
|
+# if __HAVE_FLOATN_NOT_TYPEDEF |
|
+# define __tgmath_real_type2(expr1, expr2) \ |
|
+ __tgmath_type_if (_Float32x, __tgmath_real_type2_base (expr1, expr2), \ |
|
+ _Generic ((expr1) + (expr2), _Float32x: 1, default: 0)) |
|
+# define __tgmath_complex_type2(expr1, expr2) \ |
|
+ __tgmath_type_if (_Float32x, \ |
|
+ __tgmath_type_if (_Complex _Float32x, \ |
|
+ __tgmath_complex_type2_base (expr1, \ |
|
+ expr2), \ |
|
+ _Generic ((expr1) + (expr2), \ |
|
+ _Complex _Float32x: 1, \ |
|
+ default: 0)), \ |
|
+ _Generic ((expr1) + (expr2), _Float32x: 1, default: 0)) |
|
+# define __tgmath_real_type3(expr1, expr2, expr3) \ |
|
+ __tgmath_type_if (_Float32x, \ |
|
+ __tgmath_real_type3_base (expr1, expr2, expr3), \ |
|
+ _Generic ((expr1) + (expr2) + (expr3), \ |
|
+ _Float32x: 1, default: 0)) |
|
+# else |
|
+# define __tgmath_real_type2(expr1, expr2) \ |
|
+ __tgmath_real_type2_base (expr1, expr2) |
|
+# define __tgmath_complex_type2(expr1, expr2) \ |
|
+ __tgmath_complex_type2_base (expr1, expr2) |
|
+# define __tgmath_real_type3(expr1, expr2, expr3) \ |
|
+ __tgmath_real_type3_base (expr1, expr2, expr3) |
|
+# endif |
|
+ |
|
# if (__HAVE_DISTINCT_FLOAT16 \ |
|
|| __HAVE_DISTINCT_FLOAT32 \ |
|
|| __HAVE_DISTINCT_FLOAT64 \ |
|
@@ -226,7 +289,10 @@ |
|
|
|
/* Expand to text that checks if ARG_COMB has type _Float128, and if |
|
so calls the appropriately suffixed FCT (which may include a cast), |
|
- or FCT and CFCT for complex functions, with arguments ARG_CALL. */ |
|
+ or FCT and CFCT for complex functions, with arguments ARG_CALL. |
|
+ __TGMATH_F128LD (only used in the __HAVE_FLOAT64X_LONG_DOUBLE case, |
|
+ for narrowing macros) handles long double the same as |
|
+ _Float128. */ |
|
# if __HAVE_DISTINCT_FLOAT128 && __GLIBC_USE (IEC_60559_TYPES_EXT) |
|
# if (!__HAVE_FLOAT64X \ |
|
|| __HAVE_FLOAT64X_LONG_DOUBLE \ |
|
@@ -234,6 +300,10 @@ |
|
# define __TGMATH_F128(arg_comb, fct, arg_call) \ |
|
__builtin_types_compatible_p (__typeof (+(arg_comb)), _Float128) \ |
|
? fct ## f128 arg_call : |
|
+# define __TGMATH_F128LD(arg_comb, fct, arg_call) \ |
|
+ (__builtin_types_compatible_p (__typeof (+(arg_comb)), _Float128) \ |
|
+ || __builtin_types_compatible_p (__typeof (+(arg_comb)), long double)) \ |
|
+ ? fct ## f128 arg_call : |
|
# define __TGMATH_CF128(arg_comb, fct, cfct, arg_call) \ |
|
__builtin_types_compatible_p (__typeof (+__real__ (arg_comb)), _Float128) \ |
|
? (__expr_is_real (arg_comb) \ |
|
@@ -259,7 +329,7 @@ |
|
# define __TGMATH_CF128(arg_comb, fct, cfct, arg_call) /* Nothing. */ |
|
# endif |
|
|
|
-# endif /* !__HAVE_BUILTIN_TGMATH. */ |
|
+# endif /* !__HAVE_BUILTIN_TGMATH_C2X. */ |
|
|
|
/* We have two kinds of generic macros: to support functions which are |
|
only defined on real valued parameters and those which are defined |
|
@@ -272,14 +342,18 @@ |
|
__TGMATH_2 (Fct, (Val1), (Val2)) |
|
# define __TGMATH_BINARY_FIRST_REAL_STD_ONLY(Val1, Val2, Fct) \ |
|
__TGMATH_2STD (Fct, (Val1), (Val2)) |
|
-# define __TGMATH_BINARY_REAL_ONLY(Val1, Val2, Fct) \ |
|
+# if __HAVE_BUILTIN_TGMATH_C2X |
|
+# define __TGMATH_BINARY_REAL_ONLY(Val1, Val2, Fct) \ |
|
__TGMATH_2 (Fct, (Val1), (Val2)) |
|
+# endif |
|
# define __TGMATH_BINARY_REAL_STD_ONLY(Val1, Val2, Fct) \ |
|
__TGMATH_2STD (Fct, (Val1), (Val2)) |
|
-# define __TGMATH_TERNARY_FIRST_SECOND_REAL_ONLY(Val1, Val2, Val3, Fct) \ |
|
+# if __HAVE_BUILTIN_TGMATH_C2X |
|
+# define __TGMATH_TERNARY_FIRST_SECOND_REAL_ONLY(Val1, Val2, Val3, Fct) \ |
|
__TGMATH_3 (Fct, (Val1), (Val2), (Val3)) |
|
-# define __TGMATH_TERNARY_REAL_ONLY(Val1, Val2, Val3, Fct) \ |
|
+# define __TGMATH_TERNARY_REAL_ONLY(Val1, Val2, Val3, Fct) \ |
|
__TGMATH_3 (Fct, (Val1), (Val2), (Val3)) |
|
+# endif |
|
# define __TGMATH_TERNARY_FIRST_REAL_RET_ONLY(Val1, Val2, Val3, Fct) \ |
|
__TGMATH_3 (Fct, (Val1), (Val2), (Val3)) |
|
# define __TGMATH_UNARY_REAL_IMAG(Val, Fct, Cfct) \ |
|
@@ -289,11 +363,14 @@ |
|
__TGMATH_1C (Fct, Cfct, (Val)) |
|
# define __TGMATH_UNARY_REAL_IMAG_RET_REAL_SAME(Val, Cfct) \ |
|
__TGMATH_1 (Cfct, (Val)) |
|
-# define __TGMATH_BINARY_REAL_IMAG(Val1, Val2, Fct, Cfct) \ |
|
+# if __HAVE_BUILTIN_TGMATH_C2X |
|
+# define __TGMATH_BINARY_REAL_IMAG(Val1, Val2, Fct, Cfct) \ |
|
__TGMATH_2C (Fct, Cfct, (Val1), (Val2)) |
|
+# endif |
|
|
|
-# else /* !__HAVE_BUILTIN_TGMATH. */ |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH |
|
# define __TGMATH_UNARY_REAL_ONLY(Val, Fct) \ |
|
(__extension__ ((sizeof (+(Val)) == sizeof (double) \ |
|
|| __builtin_classify_type (Val) != 8) \ |
|
@@ -330,29 +407,28 @@ |
|
: (sizeof (+(Val1)) == sizeof (float)) \ |
|
? (__tgmath_real_type (Val1)) Fct##f (Val1, Val2) \ |
|
: (__tgmath_real_type (Val1)) __tgml(Fct) (Val1, Val2))) |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH_C2X |
|
# define __TGMATH_BINARY_REAL_ONLY(Val1, Val2, Fct) \ |
|
(__extension__ ((sizeof ((Val1) + (Val2)) > sizeof (double) \ |
|
&& __builtin_classify_type ((Val1) + (Val2)) == 8) \ |
|
? __TGMATH_F128 ((Val1) + (Val2), \ |
|
- (__typeof \ |
|
- ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) Fct, \ |
|
+ (__tgmath_real_type2 (Val1, Val2)) Fct, \ |
|
(Val1, Val2)) \ |
|
- (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) \ |
|
+ (__tgmath_real_type2 (Val1, Val2)) \ |
|
__tgml(Fct) (Val1, Val2) \ |
|
: (sizeof (+(Val1)) == sizeof (double) \ |
|
|| sizeof (+(Val2)) == sizeof (double) \ |
|
|| __builtin_classify_type (Val1) != 8 \ |
|
|| __builtin_classify_type (Val2) != 8) \ |
|
- ? (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) \ |
|
+ ? (__tgmath_real_type2 (Val1, Val2)) \ |
|
Fct (Val1, Val2) \ |
|
- : (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) \ |
|
+ : (__tgmath_real_type2 (Val1, Val2)) \ |
|
Fct##f (Val1, Val2))) |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH |
|
# define __TGMATH_BINARY_REAL_STD_ONLY(Val1, Val2, Fct) \ |
|
(__extension__ ((sizeof ((Val1) + (Val2)) > sizeof (double) \ |
|
&& __builtin_classify_type ((Val1) + (Val2)) == 8) \ |
|
@@ -369,27 +445,24 @@ |
|
: (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
+ (__tgmath_real_type (Val2)) 0)) \ |
|
Fct##f (Val1, Val2))) |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH_C2X |
|
# define __TGMATH_TERNARY_FIRST_SECOND_REAL_ONLY(Val1, Val2, Val3, Fct) \ |
|
(__extension__ ((sizeof ((Val1) + (Val2)) > sizeof (double) \ |
|
&& __builtin_classify_type ((Val1) + (Val2)) == 8) \ |
|
? __TGMATH_F128 ((Val1) + (Val2), \ |
|
- (__typeof \ |
|
- ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) Fct, \ |
|
+ (__tgmath_real_type2 (Val1, Val2)) Fct, \ |
|
(Val1, Val2, Val3)) \ |
|
- (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) \ |
|
+ (__tgmath_real_type2 (Val1, Val2)) \ |
|
__tgml(Fct) (Val1, Val2, Val3) \ |
|
: (sizeof (+(Val1)) == sizeof (double) \ |
|
|| sizeof (+(Val2)) == sizeof (double) \ |
|
|| __builtin_classify_type (Val1) != 8 \ |
|
|| __builtin_classify_type (Val2) != 8) \ |
|
- ? (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) \ |
|
+ ? (__tgmath_real_type2 (Val1, Val2)) \ |
|
Fct (Val1, Val2, Val3) \ |
|
- : (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0)) \ |
|
+ : (__tgmath_real_type2 (Val1, Val2)) \ |
|
Fct##f (Val1, Val2, Val3))) |
|
|
|
# define __TGMATH_TERNARY_REAL_ONLY(Val1, Val2, Val3, Fct) \ |
|
@@ -397,14 +470,10 @@ |
|
&& __builtin_classify_type ((Val1) + (Val2) + (Val3)) \ |
|
== 8) \ |
|
? __TGMATH_F128 ((Val1) + (Val2) + (Val3), \ |
|
- (__typeof \ |
|
- ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0 \ |
|
- + (__tgmath_real_type (Val3)) 0)) Fct, \ |
|
+ (__tgmath_real_type3 (Val1, Val2, \ |
|
+ Val3)) Fct, \ |
|
(Val1, Val2, Val3)) \ |
|
- (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0 \ |
|
- + (__tgmath_real_type (Val3)) 0)) \ |
|
+ (__tgmath_real_type3 (Val1, Val2, Val3)) \ |
|
__tgml(Fct) (Val1, Val2, Val3) \ |
|
: (sizeof (+(Val1)) == sizeof (double) \ |
|
|| sizeof (+(Val2)) == sizeof (double) \ |
|
@@ -412,15 +481,13 @@ |
|
|| __builtin_classify_type (Val1) != 8 \ |
|
|| __builtin_classify_type (Val2) != 8 \ |
|
|| __builtin_classify_type (Val3) != 8) \ |
|
- ? (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0 \ |
|
- + (__tgmath_real_type (Val3)) 0)) \ |
|
+ ? (__tgmath_real_type3 (Val1, Val2, Val3)) \ |
|
Fct (Val1, Val2, Val3) \ |
|
- : (__typeof ((__tgmath_real_type (Val1)) 0 \ |
|
- + (__tgmath_real_type (Val2)) 0 \ |
|
- + (__tgmath_real_type (Val3)) 0)) \ |
|
+ : (__tgmath_real_type3 (Val1, Val2, Val3)) \ |
|
Fct##f (Val1, Val2, Val3))) |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH |
|
# define __TGMATH_TERNARY_FIRST_REAL_RET_ONLY(Val1, Val2, Val3, Fct) \ |
|
(__extension__ ((sizeof (+(Val1)) == sizeof (double) \ |
|
|| __builtin_classify_type (Val1) != 8) \ |
|
@@ -496,7 +563,9 @@ |
|
__tgml(Cfct) (Val)))) |
|
# define __TGMATH_UNARY_REAL_IMAG_RET_REAL_SAME(Val, Cfct) \ |
|
__TGMATH_UNARY_REAL_IMAG_RET_REAL ((Val), Cfct, Cfct) |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH_C2X |
|
/* XXX This definition has to be changed as soon as the compiler understands |
|
the imaginary keyword. */ |
|
# define __TGMATH_BINARY_REAL_IMAG(Val1, Val2, Fct, Cfct) \ |
|
@@ -505,46 +574,39 @@ |
|
&& __builtin_classify_type (__real__ (Val1) \ |
|
+ __real__ (Val2)) == 8) \ |
|
? __TGMATH_CF128 ((Val1) + (Val2), \ |
|
- (__typeof \ |
|
- ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ (__tgmath_complex_type2 (Val1, Val2)) \ |
|
Fct, \ |
|
- (__typeof \ |
|
- ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ (__tgmath_complex_type2 (Val1, Val2)) \ |
|
Cfct, \ |
|
(Val1, Val2)) \ |
|
(__expr_is_real ((Val1) + (Val2)) \ |
|
- ? (__typeof ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ ? (__tgmath_complex_type2 (Val1, Val2)) \ |
|
__tgml(Fct) (Val1, Val2) \ |
|
- : (__typeof ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ : (__tgmath_complex_type2 (Val1, Val2)) \ |
|
__tgml(Cfct) (Val1, Val2)) \ |
|
: (sizeof (+__real__ (Val1)) == sizeof (double) \ |
|
|| sizeof (+__real__ (Val2)) == sizeof (double) \ |
|
|| __builtin_classify_type (__real__ (Val1)) != 8 \ |
|
|| __builtin_classify_type (__real__ (Val2)) != 8) \ |
|
? (__expr_is_real ((Val1) + (Val2)) \ |
|
- ? (__typeof ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ ? (__tgmath_complex_type2 (Val1, Val2)) \ |
|
Fct (Val1, Val2) \ |
|
- : (__typeof ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ : (__tgmath_complex_type2 (Val1, Val2)) \ |
|
Cfct (Val1, Val2)) \ |
|
: (__expr_is_real ((Val1) + (Val2)) \ |
|
- ? (__typeof ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ ? (__tgmath_complex_type2 (Val1, Val2)) \ |
|
Fct##f (Val1, Val2) \ |
|
- : (__typeof ((__tgmath_complex_type (Val1)) 0 \ |
|
- + (__tgmath_complex_type (Val2)) 0)) \ |
|
+ : (__tgmath_complex_type2 (Val1, Val2)) \ |
|
Cfct##f (Val1, Val2)))) |
|
+# endif |
|
|
|
+# if !__HAVE_BUILTIN_TGMATH |
|
# define __TGMATH_2_NARROW_F(F, X, Y) \ |
|
(__extension__ (sizeof ((__tgmath_real_type (X)) 0 \ |
|
+ (__tgmath_real_type (Y)) 0) > sizeof (double) \ |
|
? F ## l (X, Y) \ |
|
: F (X, Y))) |
|
+# endif |
|
/* In most cases, these narrowing macro definitions based on sizeof |
|
ensure that the function called has the right argument format, as |
|
for other <tgmath.h> macros for compilers before GCC 8, but may not |
|
@@ -553,35 +615,50 @@ |
|
|
|
In the case of macros for _Float32x return type, when _Float64x |
|
exists, _Float64 arguments should result in the *f64 function being |
|
- called while _Float32x arguments should result in the *f64x |
|
- function being called. These cases cannot be distinguished using |
|
- sizeof (or at all if the types are typedefs rather than different |
|
- types). However, for these functions it is OK (does not affect the |
|
- final result) to call a function with any argument format at least |
|
- as wide as all the floating-point arguments, unless that affects |
|
- rounding of integer arguments. Integer arguments are considered to |
|
- have type _Float64, so the *f64 functions are preferred for f32x* |
|
- macros when no argument has a wider floating-point type. */ |
|
-# if __HAVE_FLOAT64X_LONG_DOUBLE && __HAVE_DISTINCT_FLOAT128 |
|
+ called while _Float32x, float and double arguments should result in |
|
+ the *f64x function being called (and integer arguments are |
|
+ considered to have type _Float32x if any argument has type |
|
+ _FloatNx, or double otherwise). These cases cannot be |
|
+ distinguished using sizeof (or at all if the types are typedefs |
|
+ rather than different types, in which case we err on the side of |
|
+ using the wider type if unsure). */ |
|
+# if !__HAVE_BUILTIN_TGMATH_C2X |
|
+# if __HAVE_FLOATN_NOT_TYPEDEF |
|
+# define __TGMATH_NARROW_F32X_USE_F64X(X) \ |
|
+ !__builtin_types_compatible_p (__typeof (+(X)), _Float64) |
|
+# else |
|
+# define __TGMATH_NARROW_F32X_USE_F64X(X) \ |
|
+ (__builtin_types_compatible_p (__typeof (+(X)), double) \ |
|
+ || __builtin_types_compatible_p (__typeof (+(X)), float) \ |
|
+ || !__floating_type (__typeof (+(X)))) |
|
+# endif |
|
+# endif |
|
+# if __HAVE_FLOAT64X_LONG_DOUBLE && __HAVE_DISTINCT_FLOAT128 |
|
+# if !__HAVE_BUILTIN_TGMATH |
|
# define __TGMATH_2_NARROW_F32(F, X, Y) \ |
|
(__extension__ (sizeof ((__tgmath_real_type (X)) 0 \ |
|
+ (__tgmath_real_type (Y)) 0) > sizeof (_Float64) \ |
|
- ? __TGMATH_F128 ((X) + (Y), F, (X, Y)) \ |
|
+ ? __TGMATH_F128LD ((X) + (Y), F, (X, Y)) \ |
|
F ## f64x (X, Y) \ |
|
: F ## f64 (X, Y))) |
|
# define __TGMATH_2_NARROW_F64(F, X, Y) \ |
|
(__extension__ (sizeof ((__tgmath_real_type (X)) 0 \ |
|
+ (__tgmath_real_type (Y)) 0) > sizeof (_Float64) \ |
|
- ? __TGMATH_F128 ((X) + (Y), F, (X, Y)) \ |
|
+ ? __TGMATH_F128LD ((X) + (Y), F, (X, Y)) \ |
|
F ## f64x (X, Y) \ |
|
: F ## f128 (X, Y))) |
|
+# endif |
|
+# if !__HAVE_BUILTIN_TGMATH_C2X |
|
# define __TGMATH_2_NARROW_F32X(F, X, Y) \ |
|
(__extension__ (sizeof ((__tgmath_real_type (X)) 0 \ |
|
+ (__tgmath_real_type (Y)) 0) > sizeof (_Float64) \ |
|
+ || __TGMATH_NARROW_F32X_USE_F64X ((X) + (Y)) \ |
|
? __TGMATH_F128 ((X) + (Y), F, (X, Y)) \ |
|
F ## f64x (X, Y) \ |
|
: F ## f64 (X, Y))) |
|
-# elif __HAVE_FLOAT128 |
|
+# endif |
|
+# elif __HAVE_FLOAT128 |
|
+# if !__HAVE_BUILTIN_TGMATH |
|
# define __TGMATH_2_NARROW_F32(F, X, Y) \ |
|
(__extension__ (sizeof ((__tgmath_real_type (X)) 0 \ |
|
+ (__tgmath_real_type (Y)) 0) > sizeof (_Float64) \ |
|
@@ -589,16 +666,21 @@ |
|
: F ## f64 (X, Y))) |
|
# define __TGMATH_2_NARROW_F64(F, X, Y) \ |
|
(F ## f128 (X, Y)) |
|
+# endif |
|
+# if !__HAVE_BUILTIN_TGMATH_C2X |
|
# define __TGMATH_2_NARROW_F32X(F, X, Y) \ |
|
(__extension__ (sizeof ((__tgmath_real_type (X)) 0 \ |
|
+ (__tgmath_real_type (Y)) 0) > sizeof (_Float32x) \ |
|
+ || __TGMATH_NARROW_F32X_USE_F64X ((X) + (Y)) \ |
|
? F ## f64x (X, Y) \ |
|
: F ## f64 (X, Y))) |
|
-# else |
|
+# endif |
|
+# else |
|
+# if !__HAVE_BUILTIN_TGMATH |
|
# define __TGMATH_2_NARROW_F32(F, X, Y) \ |
|
(F ## f64 (X, Y)) |
|
# endif |
|
-# endif /* !__HAVE_BUILTIN_TGMATH. */ |
|
+# endif |
|
#else |
|
# error "Unsupported compiler; you cannot use <tgmath.h>" |
|
#endif
|
|
|