about summary refs log tree commit diff
path: root/math/tgmath.h
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2019-08-21 12:06:44 +0000
committerJoseph Myers <joseph@codesourcery.com>2019-08-21 12:06:44 +0000
commitf9fabc1b02d252d5d9b2e0df406bb394b8a7b46a (patch)
tree94dc8834a10f10cf0b464e7b0c49b2abffadda84 /math/tgmath.h
parentb72971845ae1be24724f8f94e70d5e7f1c5e15fc (diff)
downloadglibc-f9fabc1b02d252d5d9b2e0df406bb394b8a7b46a.tar.gz
glibc-f9fabc1b02d252d5d9b2e0df406bb394b8a7b46a.tar.xz
glibc-f9fabc1b02d252d5d9b2e0df406bb394b8a7b46a.zip
Add tgmath.h macros for narrowing functions.
When adding some of the TS 18661 narrowing functions for glibc 2.28, I
deferred adding corresponding <tgmath.h> support because of unresolved
questions about the specification for those type-generic macros,
especially in relation to _FloatN and _FloatNx types.

Those issues are now clarified in the response to Clarification
Request 13 to TS 18661-3, and this patch adds the deferred tgmath.h
support.  As with other tgmath.h macros, there are fairly
straightforward implementations based on __builtin_tgmath for GCC 8
and later, which result in exactly the right function being called in
each case, and more complicated implementations for GCC 7 and earlier,
which generally result in a function being called whose arguments have
the right format (i.e. an alias for the right function), but which
might not be exactly the function name specified by TS 18661.

In one case with older compilers (f32x* macros, where the type
_Float64x exists and all the arguments have type _Float32 or
_Float32x), there is a further relaxation and the function called may
have arguments narrower than the one specified by the TS, but still
wide enough to represent the arguments exactly, so the result of the
call is unchanged (as this does not affect any case where rounding of
integer arguments might be involved).  With GCC 6 or before this is
inherently unavoidable (but still harmless and not detectable by how
the compiled program behaves, unless it redefines the functions in
question like the testcases do) because _Float32x and _Float64 are
both typedefs for double in that case but the specified semantics
result in different functions, with different argument formats, being
called for those two argument types.

Tests for the new macros are handled through gen-tgmath-tests.py,
which deals with the special-case handling for older GCC.

Tested as follows: with the full glibc testsuite on x86_64 and x86
(with GCC 6, 7 and 8); with the math/ tests on aarch64 and arm (with
GCC 6, 7 and 8); with build-many-glibcs.py (with GCC 6, 7 and 9).

	* math/tgmath.h [__HAVE_FLOAT128X]: Give error.
	[(__HAVE_FLOAT64X && !__HAVE_FLOAT128)
	|| (__HAVE_FLOAT128 && !__HAVE_FLOAT64X)]: Likewise.
	(__TGMATH_2_NARROW_F): Likewise.
	(__TGMATH_2_NARROW_D): New macro.
	(__TGMATH_2_NARROW_F16): Likewise.
	(__TGMATH_2_NARROW_F32): Likewise.
	(__TGMATH_2_NARROW_F64): Likewise.
	(__TGMATH_2_NARROW_F32X): Likewise.
	(__TGMATH_2_NARROW_F64X): Likewise.
	[__HAVE_BUILTIN_TGMATH] (__TGMATH_NARROW_FUNCS_F): Likewise.
	[__HAVE_BUILTIN_TGMATH] (__TGMATH_NARROW_FUNCS_F16): Likewise.
	[__HAVE_BUILTIN_TGMATH] (__TGMATH_NARROW_FUNCS_F32): Likewise.
	[__HAVE_BUILTIN_TGMATH] (__TGMATH_NARROW_FUNCS_F64): Likewise.
	[__HAVE_BUILTIN_TGMATH] (__TGMATH_NARROW_FUNCS_F32X): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (fadd): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (dadd): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (fdiv): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (ddiv): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (fmul): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (dmul): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (fsub): Likewise.
	[__GLIBC_USE (IEC_60559_BFP_EXT_C2X)] (dsub): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT16] (f16add):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT16] (f16div):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT16] (f16mul):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT16] (f16sub):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32] (f32add):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32] (f32div):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32] (f32mul):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32] (f32sub):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64
	&& (__HAVE_FLOAT64X || __HAVE_FLOAT128)] (f64add): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64
	&& (__HAVE_FLOAT64X || __HAVE_FLOAT128)] (f64div): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64
	&& (__HAVE_FLOAT64X || __HAVE_FLOAT128)] (f64mul): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64
	&& (__HAVE_FLOAT64X || __HAVE_FLOAT128)] (f64sub): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32X] (f32xadd):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32X] (f32xdiv):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32X] (f32xmul):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT32X] (f32xsub):
	Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64X
	&& (__HAVE_FLOAT128X || __HAVE_FLOAT128)] (f64xadd): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64X
	&& (__HAVE_FLOAT128X || __HAVE_FLOAT128)] (f64xdiv): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64X
	&& (__HAVE_FLOAT128X || __HAVE_FLOAT128)] (f64xmul): Likewise.
	[__GLIBC_USE (IEC_60559_TYPES_EXT) && __HAVE_FLOAT64X
	&& (__HAVE_FLOAT128X || __HAVE_FLOAT128)] (f64xsub): Likewise.
	* math/gen-tgmath-tests.py (Type): Add members
	non_standard_real_argument_types_list, long_double_type,
	complex_float64_type and float32x_ext_type.
	(Type.__init__): Set the new members.
	(Type.floating_type): Add new argument floatn.
	(Type.real_floating_type): Likewise.
	(Type.can_combine_types): Likewise.
	(Type.combine_types): Likewise.
	(Type.init_types): Create internal Float32x_ext type.
	(Tests.__init__): Define Float32x_ext in generated C code.
	(Tests.add_tests): Handle narrowing functions.
	(Tests.add_all_tests): Likewise.
	(Tests.tests_text): Allow variation in mant_dig for narrowing
	functions with compilers before GCC 8.
	* math/Makefile (tgmath3-narrow-types): New variable.
	(tgmath3-narrow-macros): Likewise.
	(tgmath3-macros): Add $(tgmath3-narrow-macros).
Diffstat (limited to 'math/tgmath.h')
-rw-r--r--math/tgmath.h167
1 files changed, 167 insertions, 0 deletions
diff --git a/math/tgmath.h b/math/tgmath.h
index d9dfca459b..0c58cc9326 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 */