aboutsummaryrefslogtreecommitdiff
path: root/math
diff options
context:
space:
mode:
Diffstat (limited to 'math')
-rw-r--r--math/Makefile6
-rwxr-xr-xmath/gen-tgmath-tests.py184
-rw-r--r--math/tgmath.h167
3 files changed, 337 insertions, 20 deletions
diff --git a/math/Makefile b/math/Makefile
index 15c864c..247e31d 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -368,6 +368,10 @@ $(foreach t,$(libm-tests-base),\
$(foreach t,$(libm-tests-base),\
$(objpfx)$(t)-compat_totalordermag.o): $(objpfx)libm-test-totalordermag.c
+# _Float128x omitted as not supported by gen-tgmath-tests.py.
+tgmath3-narrow-types = f d f16 f32 f64 f128 f32x f64x
+tgmath3-narrow-macros = $(foreach t,$(tgmath3-narrow-types), \
+ $(foreach f,$(libm-narrow-fns),$(t)$(f)))
tgmath3-macros = atan2 cbrt ceil copysign erf erfc exp2 expm1 fdim floor \
fma fmax fmin fmod frexp hypot ilogb ldexp lgamma llrint \
llround log10 log1p log2 logb lrint lround nearbyint \
@@ -375,7 +379,7 @@ tgmath3-macros = atan2 cbrt ceil copysign erf erfc exp2 expm1 fdim floor \
scalbln tgamma trunc acos asin atan acosh asinh atanh cos \
sin tan cosh sinh tanh exp log pow sqrt fabs carg cimag conj \
cproj creal roundeven nextup nextdown fminmag fmaxmag llogb \
- fromfp fromfpx ufromfp ufromfpx scalb
+ fromfp fromfpx ufromfp ufromfpx scalb $(tgmath3-narrow-macros)
tgmath3-macro-tests = $(addprefix test-tgmath3-,$(tgmath3-macros))
tests += $(tgmath3-macro-tests)
generated += $(addsuffix .c,$(tgmath3-macro-tests))
diff --git a/math/gen-tgmath-tests.py b/math/gen-tgmath-tests.py
index 2a7d94e..1c09844 100755
--- a/math/gen-tgmath-tests.py
+++ b/math/gen-tgmath-tests.py
@@ -69,17 +69,27 @@ 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 = {}
# The type double.
double_type = None
+ # The type long double.
+ long_double_type = None
# The type _Complex double.
complex_double_type = None
# The type _Float64.
float64_type = None
+ # The type _Complex _Float64.
+ complex_float64_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):
@@ -109,16 +119,24 @@ 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':
Type.double_type = self
+ if self.name == 'long double':
+ Type.long_double_type = self
if self.name == '_Complex double':
Type.complex_double_type = self
if self.name == '_Float64':
Type.float64_type = self
+ if self.name == '_Complex _Float64':
+ Type.complex_float64_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,
@@ -142,18 +160,23 @@ class Type(object):
if complex_type is not None:
complex_type.register_type(internal)
- def floating_type(self):
+ def floating_type(self, floatn):
"""Return the corresponding floating type."""
if self.integer:
- return (Type.complex_double_type
- if self.complex
- else Type.double_type)
+ if floatn:
+ return (Type.complex_float64_type
+ if self.complex
+ else Type.float64_type)
+ else:
+ return (Type.complex_double_type
+ if self.complex
+ else Type.double_type)
else:
return self
- def real_floating_type(self):
+ def real_floating_type(self, floatn):
"""Return the corresponding real floating type."""
- return self.real_type.floating_type()
+ return self.real_type.floating_type(floatn)
def __str__(self):
"""Return string representation of a type."""
@@ -212,15 +235,21 @@ 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):
+ def can_combine_types(types, floatn):
"""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
for t in types:
- t = t.real_floating_type()
+ t = t.real_floating_type(floatn)
if t.name == 'long double':
have_long_double = True
if t.name == '_Float128' or t.name == '_Float64x':
@@ -233,14 +262,14 @@ class Type(object):
return '1'
@staticmethod
- def combine_types(types):
+ def combine_types(types, floatn):
"""Return the result of combining a set of types."""
have_complex = False
combined = None
for t in types:
if t.complex:
have_complex = True
- t = t.real_floating_type()
+ t = t.real_floating_type(floatn)
if combined is None:
combined = t
else:
@@ -316,6 +345,7 @@ class Tests(object):
' const char *func_name;\n'
' const char *test_name;\n'
' int mant_dig;\n'
+ ' int narrow_mant_dig;\n'
' };\n'
'int num_pass, num_fail;\n'
'volatile int called_mant_dig;\n'
@@ -345,8 +375,18 @@ 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)
@@ -377,6 +417,8 @@ class Tests(object):
return
have_complex = False
func = macro
+ narrowing = False
+ narrowing_std = False
if ret == 'c' or 'c' in args:
# Complex-only.
have_complex = True
@@ -387,6 +429,49 @@ class Tests(object):
have_complex = True
if complex_func == None:
complex_func = 'c%s' % func
+ # For narrowing macros, compute narrow_args, the list of
+ # argument types for which there is an actual corresponding
+ # function. If none of those types exist, or the return type
+ # does not exist, then the macro is not defined and no tests
+ # of it can be run.
+ if ret == 'float':
+ narrowing = True
+ 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 = []
+ 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 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':
@@ -400,6 +485,8 @@ class Tests(object):
continue
if ret == 's' and t.name.startswith('_Float'):
continue
+ if narrowing and t not in narrow_args:
+ continue
if ret == 'c':
ret_name = t.complex_type.name
elif ret == 'g':
@@ -432,23 +519,56 @@ class Tests(object):
'}\n' % (ret_name, dummy_func_name,
t.real_type.suffix, ', '.join(arg_list),
t.real_type.mant_dig, dummy_func_name))
- dummy_func = if_cond_text([t.condition], dummy_func)
+ if narrowing:
+ dummy_cond = [narrow_cond, t.condition]
+ else:
+ dummy_cond = [t.condition]
+ dummy_func = if_cond_text(dummy_cond, dummy_func)
self.test_text_list.append(dummy_func)
arg_types = []
for t in args:
if t == 'g' or t == 'c':
arg_types.append(Type.argument_types_list)
elif t == 'r':
- arg_types.append(Type.real_argument_types_list)
+ 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)
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)
- can_comb = Type.can_combine_types(this_args)
+ comb_type = Type.combine_types(this_args, narrowing_nonstd)
+ if narrowing:
+ # As long as there are no integer arguments, and as
+ # long as the chosen argument type is as wide as all
+ # the floating-point arguments passed, the semantics
+ # 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.
+ 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)
all_conds = [t.condition for t in this_args]
all_conds.append(can_comb)
+ if narrowing:
+ all_conds.append(narrow_cond)
any_complex = func == None
for t in this_args:
if t.complex:
@@ -459,8 +579,9 @@ class Tests(object):
test_func_name = 'test_%s_%d' % (macro, test_num)
test_num += 1
mant_dig = comb_type.real_type.mant_dig
- test_text = '%s, "%s", "%s", %s' % (test_func_name, func_name,
- test_name, 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 = if_cond_text(all_conds, test_text)
self.test_array_list.append(test_text)
@@ -575,9 +696,16 @@ class Tests(object):
self.add_tests('fromfpx', 'intmax_t', ['r', 'int', 'unsigned int'])
self.add_tests('ufromfp', 'uintmax_t', ['r', 'int', 'unsigned int'])
self.add_tests('ufromfpx', 'uintmax_t', ['r', 'int', 'unsigned int'])
- # The functions that round their result to a narrower type,
- # and the associated type-generic macros, are not yet
- # supported by this script or by glibc.
+ for fn in ('add', 'div', 'mul', 'sub'):
+ for ret, prefix in (('float', 'f'),
+ ('double', 'd'),
+ ('_Float16', 'f16'),
+ ('_Float32', 'f32'),
+ ('_Float64', 'f64'),
+ ('_Float128', 'f128'),
+ ('_Float32x', 'f32x'),
+ ('_Float64x', 'f64x')):
+ self.add_tests(prefix + fn, ret, ['r', 'r'])
# Miscellaneous functions.
self.add_tests('scalb', 's', ['s', 's'])
@@ -602,6 +730,24 @@ class Tests(object):
' && strcmp (called_func_name,\n'
' tests[i].func_name) == 0)\n'
' num_pass++;\n'
+ '#if !__GNUC_PREREQ (8, 0)\n'
+ ' else if (tests[i].narrow_mant_dig > 0\n'
+ ' && (called_mant_dig\n'
+ ' >= tests[i].narrow_mant_dig)\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'
+ ' " (OK 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'
' num_fail++;\n'
diff --git a/math/tgmath.h b/math/tgmath.h
index d9dfca4..0c58cc9 100644
--- a/math/tgmath.h
+++ b/math/tgmath.h
@@ -43,6 +43,25 @@
#if __GNUC_PREREQ (2, 7)
+/* Certain cases of narrowing macros only need to call a single
+ function so cannot use __builtin_tgmath and do not need any
+ complicated logic. */
+# if __HAVE_FLOAT128X
+# error "Unsupported _Float128x type for <tgmath.h>."
+# endif
+# if ((__HAVE_FLOAT64X && !__HAVE_FLOAT128) \
+ || (__HAVE_FLOAT128 && !__HAVE_FLOAT64X))
+# error "Unsupported combination of types for <tgmath.h>."
+# endif
+# define __TGMATH_2_NARROW_D(F, X, Y) \
+ (F ## l (X, Y))
+# define __TGMATH_2_NARROW_F64X(F, X, Y) \
+ (F ## f128 (X, Y))
+# if !__HAVE_FLOAT128
+# define __TGMATH_2_NARROW_F32X(F, X, Y) \
+ (F ## f64 (X, Y))
+# endif
+
# if __HAVE_BUILTIN_TGMATH
# if __HAVE_FLOAT16 && __GLIBC_USE (IEC_60559_TYPES_EXT)
@@ -94,6 +113,33 @@
# define __TGMATH_2C(F, C, X, Y) __builtin_tgmath (__TGMATH_RCFUNCS (F, C) \
(X), (Y))
+# define __TGMATH_NARROW_FUNCS_F(X) X, X ## l,
+# define __TGMATH_NARROW_FUNCS_F16(X) \
+ __TG_F32_ARG (X) __TG_F64_ARG (X) __TG_F128_ARG (X) \
+ __TG_F32X_ARG (X) __TG_F64X_ARG (X) __TG_F128X_ARG (X)
+# define __TGMATH_NARROW_FUNCS_F32(X) \
+ __TG_F64_ARG (X) __TG_F128_ARG (X) \
+ __TG_F32X_ARG (X) __TG_F64X_ARG (X) __TG_F128X_ARG (X)
+# define __TGMATH_NARROW_FUNCS_F64(X) \
+ __TG_F128_ARG (X) \
+ __TG_F64X_ARG (X) __TG_F128X_ARG (X)
+# define __TGMATH_NARROW_FUNCS_F32X(X) \
+ __TG_F64X_ARG (X) __TG_F128X_ARG (X) \
+ __TG_F64_ARG (X) __TG_F128_ARG (X)
+
+# define __TGMATH_2_NARROW_F(F, X, Y) \
+ __builtin_tgmath (__TGMATH_NARROW_FUNCS_F (F) (X), (Y))
+# define __TGMATH_2_NARROW_F16(F, X, Y) \
+ __builtin_tgmath (__TGMATH_NARROW_FUNCS_F16 (F) (X), (Y))
+# define __TGMATH_2_NARROW_F32(F, X, Y) \
+ __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
+# define __TGMATH_2_NARROW_F32X(F, X, Y) \
+ __builtin_tgmath (__TGMATH_NARROW_FUNCS_F32X (F) (X), (Y))
+# endif
+
# else /* !__HAVE_BUILTIN_TGMATH. */
# ifdef __NO_LONG_DOUBLE_MATH
@@ -493,6 +539,65 @@
: (__typeof ((__tgmath_complex_type (Val1)) 0 \
+ (__tgmath_complex_type (Val2)) 0)) \
Cfct##f (Val1, Val2))))
+
+# 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)))
+/* 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
+ have exactly the argument type (among the types with that format)
+ specified in the standard logic.
+
+ 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
+# 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)) \
+ 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)) \
+ F ## f64x (X, Y) \
+ : F ## f128 (X, Y)))
+# define __TGMATH_2_NARROW_F32X(F, X, Y) \
+ (__extension__ (sizeof ((__tgmath_real_type (X)) 0 \
+ + (__tgmath_real_type (Y)) 0) > sizeof (_Float64) \
+ ? __TGMATH_F128 ((X) + (Y), F, (X, Y)) \
+ F ## f64x (X, Y) \
+ : F ## f64 (X, Y)))
+# elif __HAVE_FLOAT128
+# define __TGMATH_2_NARROW_F32(F, X, Y) \
+ (__extension__ (sizeof ((__tgmath_real_type (X)) 0 \
+ + (__tgmath_real_type (Y)) 0) > sizeof (_Float64) \
+ ? F ## f128 (X, Y) \
+ : F ## f64 (X, Y)))
+# define __TGMATH_2_NARROW_F64(F, X, Y) \
+ (F ## f128 (X, Y))
+# define __TGMATH_2_NARROW_F32X(F, X, Y) \
+ (__extension__ (sizeof ((__tgmath_real_type (X)) 0 \
+ + (__tgmath_real_type (Y)) 0) > sizeof (_Float32x) \
+ ? F ## f64x (X, Y) \
+ : F ## f64 (X, Y)))
+# else
+# define __TGMATH_2_NARROW_F32(F, X, Y) \
+ (F ## f64 (X, Y))
+# endif
# endif /* !__HAVE_BUILTIN_TGMATH. */
#else
# error "Unsupported compiler; you cannot use <tgmath.h>"
@@ -739,4 +844,66 @@
/* Real part of Z. */
#define creal(Val) __TGMATH_UNARY_REAL_IMAG_RET_REAL_SAME (Val, creal)
+
+/* Narrowing functions. */
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT_C2X)
+
+/* Add. */
+# define fadd(Val1, Val2) __TGMATH_2_NARROW_F (fadd, Val1, Val2)
+# define dadd(Val1, Val2) __TGMATH_2_NARROW_D (dadd, Val1, Val2)
+
+/* Divide. */
+# define fdiv(Val1, Val2) __TGMATH_2_NARROW_F (fdiv, Val1, Val2)
+# define ddiv(Val1, Val2) __TGMATH_2_NARROW_D (ddiv, Val1, Val2)
+
+/* Multiply. */
+# define fmul(Val1, Val2) __TGMATH_2_NARROW_F (fmul, Val1, Val2)
+# define dmul(Val1, Val2) __TGMATH_2_NARROW_D (dmul, Val1, Val2)
+
+/* Subtract. */
+# define fsub(Val1, Val2) __TGMATH_2_NARROW_F (fsub, Val1, Val2)
+# define dsub(Val1, Val2) __TGMATH_2_NARROW_D (dsub, Val1, Val2)
+
+#endif
+
+#if __GLIBC_USE (IEC_60559_TYPES_EXT)
+
+# if __HAVE_FLOAT16
+# define f16add(Val1, Val2) __TGMATH_2_NARROW_F16 (f16add, Val1, Val2)
+# define f16div(Val1, Val2) __TGMATH_2_NARROW_F16 (f16div, Val1, Val2)
+# define f16mul(Val1, Val2) __TGMATH_2_NARROW_F16 (f16mul, Val1, Val2)
+# define f16sub(Val1, Val2) __TGMATH_2_NARROW_F16 (f16sub, Val1, Val2)
+# endif
+
+# if __HAVE_FLOAT32
+# define f32add(Val1, Val2) __TGMATH_2_NARROW_F32 (f32add, Val1, Val2)
+# define f32div(Val1, Val2) __TGMATH_2_NARROW_F32 (f32div, Val1, Val2)
+# define f32mul(Val1, Val2) __TGMATH_2_NARROW_F32 (f32mul, Val1, Val2)
+# define f32sub(Val1, Val2) __TGMATH_2_NARROW_F32 (f32sub, Val1, Val2)
+# endif
+
+# if __HAVE_FLOAT64 && (__HAVE_FLOAT64X || __HAVE_FLOAT128)
+# define f64add(Val1, Val2) __TGMATH_2_NARROW_F64 (f64add, Val1, Val2)
+# define f64div(Val1, Val2) __TGMATH_2_NARROW_F64 (f64div, Val1, Val2)
+# define f64mul(Val1, Val2) __TGMATH_2_NARROW_F64 (f64mul, Val1, Val2)
+# define f64sub(Val1, Val2) __TGMATH_2_NARROW_F64 (f64sub, Val1, Val2)
+# endif
+
+# if __HAVE_FLOAT32X
+# define f32xadd(Val1, Val2) __TGMATH_2_NARROW_F32X (f32xadd, Val1, Val2)
+# define f32xdiv(Val1, Val2) __TGMATH_2_NARROW_F32X (f32xdiv, Val1, Val2)
+# define f32xmul(Val1, Val2) __TGMATH_2_NARROW_F32X (f32xmul, Val1, Val2)
+# define f32xsub(Val1, Val2) __TGMATH_2_NARROW_F32X (f32xsub, Val1, Val2)
+# endif
+
+# if __HAVE_FLOAT64X && (__HAVE_FLOAT128X || __HAVE_FLOAT128)
+# define f64xadd(Val1, Val2) __TGMATH_2_NARROW_F64X (f64xadd, Val1, Val2)
+# define f64xdiv(Val1, Val2) __TGMATH_2_NARROW_F64X (f64xdiv, Val1, Val2)
+# define f64xmul(Val1, Val2) __TGMATH_2_NARROW_F64X (f64xmul, Val1, Val2)
+# define f64xsub(Val1, Val2) __TGMATH_2_NARROW_F64X (f64xsub, Val1, Val2)
+# endif
+
+#endif
+
#endif /* tgmath.h */