Adjust __builtin_tgmath handling of integer arguments to _FloatN narrowing macros

Message ID alpine.DEB.2.20.1803212229370.3411@digraph.polyomino.org.uk
State New
Headers show
Series
  • Adjust __builtin_tgmath handling of integer arguments to _FloatN narrowing macros
Related show

Commit Message

Joseph Myers March 21, 2018, 10:30 p.m.
When adding __builtin_tgmath to support a better tgmath.h
implementation, I noted that further changes might be needed regarding
the TS 18661 functions that round their results to a narrower type,
because of unresolved issues with how the corresponding type-generic
macros are defined in TS 18661.

The resolution of those issues is still in flux, but the latest
version does indeed require something slightly different from
__builtin_tgmath.  It specifies that integer arguments to type-generic
macros such as f32xadd are treated as _Float64 not double - which was
also present in earlier versions of the resolution - but then it also
specifies different handling for _Float64 arguments and double
arguments, which wasn't in earlier versions.  Specifically, in the
latest version
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2213.pdf>, f32xadd
with _Float64 arguments would call f32xaddf64, while f32xadd with
double arguments would call f32xaddf64x.  Since integer arguments are
converted directly to the argument type of the selected function (not
to double / _Float64x unless that ends up as the argument type), this
is a user-visible difference in semantics that means __builtin_tgmath
actually needs to implement treating integer arguments as _Float64 in
this case (the rest of the latest semantics can then be implemented in
the header, with a few inline functions there).

To avoid releasing with the older version of the __builtin_tgmath
semantics that doesn't work with the latest proposed DR#13 resolution,
this patch implements a rule in __builtin_tgmath that maps integer
types to _Float64 (respectively _Complex _Float64 for complex integer
types) where all the specified functions return the same _FloatN or
_FloatNx type.  This does not affect any existing uses of
__builtin_tgmath in glibc's or GCC's tgmath.h since I haven't yet
added any of these type-generic macros to glibc when adding the
corresponding narrowing functions.

Bootstrapped with no regressions on x86_64-pc-linux-gnu.  Applied to 
mainline.

2018-03-21  Joseph Myers  <joseph@codesourcery.com>

	* doc/extend.texi (__builtin_tgmath): Document when complex
	integer types are treated as _Complex _Float64.

gcc/c:
2018-03-21  Joseph Myers  <joseph@codesourcery.com>

	* c-parser.c (c_parser_postfix_expression): For __builtin_tgmath
	where all functions return the same _FloatN or _FloatNx type,
	treat integer types as _Float64 instead of double.

gcc/testsuite:
2018-03-21  Joseph Myers  <joseph@codesourcery.com>

	* gcc.dg/builtin-tgmath-3.c: New test.


-- 
Joseph S. Myers
joseph@codesourcery.com

Patch

Index: gcc/c/c-parser.c
===================================================================
--- gcc/c/c-parser.c	(revision 258722)
+++ gcc/c/c-parser.c	(working copy)
@@ -8530,10 +8530,12 @@  c_parser_postfix_expression (c_parser *parser)
 	       argument is decimal, or if the only alternatives for
 	       type-generic arguments are of decimal types, and are
 	       otherwise treated as double (or _Complex double for
-	       complex integer types).  After that adjustment, types
-	       are combined following the usual arithmetic
-	       conversions.  If the function only accepts complex
-	       arguments, a complex type is produced.  */
+	       complex integer types, or _Float64 or _Complex _Float64
+	       if all the return types are the same _FloatN or
+	       _FloatNx type).  After that adjustment, types are
+	       combined following the usual arithmetic conversions.
+	       If the function only accepts complex arguments, a
+	       complex type is produced.  */
 	    bool arg_complex = all_complex;
 	    bool arg_binary = all_binary;
 	    bool arg_int_decimal = all_decimal;
@@ -8632,6 +8634,19 @@  c_parser_postfix_expression (c_parser *parser)
 		      }
 		  }
 	      }
+	    /* For a macro rounding its result to a narrower type, map
+	       integer types to _Float64 not double if the return type
+	       is a _FloatN or _FloatNx type.  */
+	    bool arg_int_float64 = false;
+	    if (parm_kind[0] == tgmath_fixed
+		&& SCALAR_FLOAT_TYPE_P (parm_first[0])
+		&& float64_type_node != NULL_TREE)
+	      for (unsigned int j = 0; j < NUM_FLOATN_NX_TYPES; j++)
+		if (parm_first[0] == FLOATN_TYPE_NODE (j))
+		  {
+		    arg_int_float64 = true;
+		    break;
+		  }
 	    tree arg_real = NULL_TREE;
 	    for (unsigned int j = 1; j <= nargs; j++)
 	      {
@@ -8644,6 +8659,8 @@  c_parser_postfix_expression (c_parser *parser)
 		if (INTEGRAL_TYPE_P (type))
 		  type = (arg_int_decimal
 			  ? dfloat64_type_node
+			  : arg_int_float64
+			  ? float64_type_node
 			  : double_type_node);
 		if (arg_real == NULL_TREE)
 		  arg_real = type;
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 258722)
+++ gcc/doc/extend.texi	(working copy)
@@ -11848,7 +11848,9 @@  corresponding to @var{t} for each function.
 The standard rules for @code{<tgmath.h>} macros are used to find a
 common type @var{u} from the types of the arguments for parameters
 whose types vary between the functions; complex integer types (a GNU
-extension) are treated like @code{_Complex double} for this purpose.
+extension) are treated like @code{_Complex double} for this purpose
+(or @code{_Complex _Float64} if all the function return types are the
+same @code{_Float@var{n}} or @code{_Float@var{n}x} type).
 If the function return types vary, or are all the same integer type,
 the function called is the one for which @var{t} is @var{u}, and it is
 an error if there is no such function.  If the function return types
Index: gcc/testsuite/gcc.dg/builtin-tgmath-3.c
===================================================================
--- gcc/testsuite/gcc.dg/builtin-tgmath-3.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/builtin-tgmath-3.c	(working copy)
@@ -0,0 +1,50 @@ 
+/* Test __builtin_tgmath: integer arguments mapped to _Float64.  */
+/* { dg-do run } */
+/* { dg-options "" } */
+/* { dg-add-options float32 } */
+/* { dg-add-options float64 } */
+/* { dg-require-effective-target float32_runtime } */
+/* { dg-require-effective-target float64_runtime } */
+
+extern void abort (void);
+extern void exit (int);
+
+#define CHECK_CALL(C, E, V)			\
+  do						\
+    {						\
+      if ((C) != (E))				\
+	abort ();				\
+      extern __typeof (C) V;			\
+    }						\
+  while (0)
+
+extern _Float32 var_f32;
+
+_Float32 t1f (float x) { return x + 1; }
+_Float32 t1d (double x) { return x + 2; }
+_Float32 t1l (long double x) { return x + 3; }
+_Float32 t1f64 (_Float64 x) { return x + 4; }
+
+#define t1v(x) __builtin_tgmath (t1f, t1d, t1l, t1f64, x)
+
+static void
+test_1 (void)
+{
+  float f = 1;
+  double d = 2;
+  long double ld = 3;
+  _Float64 f64 = 4;
+  int i = 5;
+  CHECK_CALL (t1v (f), 2, var_f32);
+  CHECK_CALL (t1v (d), 4, var_f32);
+  CHECK_CALL (t1v (ld), 6, var_f32);
+  CHECK_CALL (t1v (f64), 8, var_f32);
+  CHECK_CALL (t1v (i), 9, var_f32);
+}
+
+int
+main (void)
+{
+  test_1 ();
+  exit (0);
+}