This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Add __builtin_complex to construct complex values (C1X CMPLX* macros)


This patch adds __builtin_complex to support generating values with
arbitrary real and imaginary parts, including in static initializers,
despite the absence of imaginary types.  (Recall that X + I * Y, in
the absence of imaginary types, is really X + Y * (0.0 + 1.0I),
resulting in a real part X + Y * 0.0 which yields incorrect results
when infinities or signed zero are used.)  This is intended to be used
by C library headers to define the C1X macros CMPLX*, with definitions
along the lines of:

#define CMPLX(X, Y) __builtin_complex ((double) (X), (double) (Y))

As requested in PR 48760 comment 12, this is purely a C front-end
built-in (actually, a keyword that looks like a built-in function)
providing syntax for COMPLEX_EXPR, rather than a middle-end built-in
function.  The C++ front end is using a different approach for this
issue, allowing list-initialization of _Complex values.  (Allowing
{ real, imag } initializers was one of the approaches considered for
C1X before the final macro approach was arrived at.  See N1464 for the
approach that was followed and references to previous proposals; the
initializer approach was proposal two in N1431.  Note that if you did
allow such initializers for C, it wouldn't provide *expressions*
usable in static initializers, since to make a braced initializer into
an expression you need a compound literal and compound literals can't
be used in static initializers.)

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

2011-08-19  Joseph Myers  <joseph@codesourcery.com>

	* c-parser.c (c_parser_postfix_expression): Handle
	RID_BUILTIN_COMPLEX.
	* doc/extend.texi (__builtin_complex): Document.

c-family:
2011-08-19  Joseph Myers  <joseph@codesourcery.com>

	* c-common.c (c_common_reswords): Add __builtin_complex.
	* c-common.h (RID_BUILTIN_COMPLEX): New.

testsuite:
2011-08-19  Joseph Myers  <joseph@codesourcery.com>

	* gcc.dg/builtin-complex-err-1.c, gcc.dg/builtin-complex-err-2.c,
	gcc.dg/dfp/builtin-complex.c, gcc.dg/torture/builtin-complex-1.c:
	New tests.

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 177894)
+++ gcc/doc/extend.texi	(working copy)
@@ -7511,6 +7511,18 @@ future revisions.
 
 @end deftypefn
 
+@deftypefn {Built-in Function} @var{type} __builtin_complex (@var{real}, @var{imag})
+
+The built-in function @code{__builtin_complex} is provided for use in
+implementing the ISO C1X macros @code{CMPLXF}, @code{CMPLX} and
+@code{CMPLXL}.  @var{real} and @var{imag} must have the same type, a
+real binary floating-point type, and the result has the corresponding
+complex type with real and imaginary parts @var{real} and @var{imag}.
+Unlike @samp{@var{real} + I * @var{imag}}, this works even when
+infinities, NaNs and negative zeros are involved.
+
+@end deftypefn
+
 @deftypefn {Built-in Function} int __builtin_constant_p (@var{exp})
 You can use the built-in function @code{__builtin_constant_p} to
 determine if a value is known to be constant at compile-time and hence
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 177894)
+++ gcc/c-family/c-common.c	(working copy)
@@ -424,6 +424,7 @@ const struct c_common_resword c_common_r
   { "__attribute",	RID_ATTRIBUTE,	0 },
   { "__attribute__",	RID_ATTRIBUTE,	0 },
   { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
+  { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
   { "__builtin_offsetof", RID_OFFSETOF, 0 },
   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, D_CONLY },
   { "__builtin_va_arg",	RID_VA_ARG,	0 },
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h	(revision 177894)
+++ gcc/c-family/c-common.h	(working copy)
@@ -103,7 +103,7 @@ enum rid
   /* C extensions */
   RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,
-  RID_TYPES_COMPATIBLE_P,
+  RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,
   RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
   RID_FRACT, RID_ACCUM,
 
Index: gcc/testsuite/gcc.dg/dfp/builtin-complex.c
===================================================================
--- gcc/testsuite/gcc.dg/dfp/builtin-complex.c	(revision 0)
+++ gcc/testsuite/gcc.dg/dfp/builtin-complex.c	(revision 0)
@@ -0,0 +1,10 @@
+/* Test __builtin_complex errors with DFP.  */
+/* { dg-do compile } */
+
+_Decimal32 a, b;
+
+void
+f (void)
+{
+  __builtin_complex (a, b); /* { dg-error "not of real binary floating-point type" } */
+}
Index: gcc/testsuite/gcc.dg/builtin-complex-err-1.c
===================================================================
--- gcc/testsuite/gcc.dg/builtin-complex-err-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/builtin-complex-err-1.c	(revision 0)
@@ -0,0 +1,26 @@
+/* Test __builtin_complex errors.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+typedef double D;
+
+double d;
+
+_Complex double dc = __builtin_complex (1.0, (D) 0.0);
+
+_Complex double dc2 = __builtin_complex (d, 0.0); /* { dg-error "not constant" } */
+
+_Complex float fc = __builtin_complex (1.0f, 1); /* { dg-error "not of real binary floating-point type" } */
+
+_Complex float fc2 = __builtin_complex (1, 1.0f); /* { dg-error "not of real binary floating-point type" } */
+
+_Complex float fc3 = __builtin_complex (1.0f, 1.0); /* { dg-error "different types" } */
+
+void
+f (void)
+{
+  __builtin_complex (0.0); /* { dg-error "expected" } */
+  __builtin_complex (0.0, 0.0, 0.0); /* { dg-error "expected" } */
+}
+
+void (*p) (void) = __builtin_complex; /* { dg-error "expected" } */
Index: gcc/testsuite/gcc.dg/torture/builtin-complex-1.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/builtin-complex-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/builtin-complex-1.c	(revision 0)
@@ -0,0 +1,117 @@
+/* Test __builtin_complex semantics.  */
+/* { dg-do run } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+extern void exit (int);
+extern void abort (void);
+
+#define COMPARE_BODY(A, B, TYPE, COPYSIGN)				\
+  do {									\
+    TYPE s1 = COPYSIGN ((TYPE) 1.0, A);					\
+    TYPE s2 = COPYSIGN ((TYPE) 1.0, B);					\
+    if (s1 != s2)							\
+      abort ();								\
+    if ((__builtin_isnan (A) != 0) != (__builtin_isnan (B) != 0))	\
+      abort ();								\
+    if ((A != B) != (__builtin_isnan (A) != 0))				\
+      abort ();								\
+  } while (0)
+
+void
+comparef (float a, float b)
+{
+  COMPARE_BODY (a, b, float, __builtin_copysignf);
+}
+
+void
+compare (double a, double b)
+{
+  COMPARE_BODY (a, b, double, __builtin_copysign);
+}
+
+void
+comparel (long double a, long double b)
+{
+  COMPARE_BODY (a, b, long double, __builtin_copysignl);
+}
+
+void
+comparecf (_Complex float a, float r, float i)
+{
+  comparef (__real__ a, r);
+  comparef (__imag__ a, i);
+}
+
+void
+comparec (_Complex double a, double r, double i)
+{
+  compare (__real__ a, r);
+  compare (__imag__ a, i);
+}
+
+void
+comparecl (_Complex long double a, long double r, long double i)
+{
+  comparel (__real__ a, r);
+  comparel (__imag__ a, i);
+}
+
+#define VERIFY(A, B, TYPE, COMPARE)			\
+  do {							\
+    TYPE a = A;						\
+    TYPE b = B;						\
+    _Complex TYPE cr = __builtin_complex (a, b);	\
+    static _Complex TYPE cs = __builtin_complex (A, B);	\
+    COMPARE (cr, A, B);					\
+    COMPARE (cs, A, B);					\
+  } while (0)
+
+#define ALL_CHECKS(PZ, NZ, NAN, INF, TYPE, COMPARE)	\
+  do {							\
+    VERIFY (PZ, PZ, TYPE, COMPARE);			\
+    VERIFY (PZ, NZ, TYPE, COMPARE);			\
+    VERIFY (PZ, NAN, TYPE, COMPARE);			\
+    VERIFY (PZ, INF, TYPE, COMPARE);			\
+    VERIFY (NZ, PZ, TYPE, COMPARE);			\
+    VERIFY (NZ, NZ, TYPE, COMPARE);			\
+    VERIFY (NZ, NAN, TYPE, COMPARE);			\
+    VERIFY (NZ, INF, TYPE, COMPARE);			\
+    VERIFY (NAN, PZ, TYPE, COMPARE);			\
+    VERIFY (NAN, NZ, TYPE, COMPARE);			\
+    VERIFY (NAN, NAN, TYPE, COMPARE);			\
+    VERIFY (NAN, INF, TYPE, COMPARE);			\
+    VERIFY (INF, PZ, TYPE, COMPARE);			\
+    VERIFY (INF, NZ, TYPE, COMPARE);			\
+    VERIFY (INF, NAN, TYPE, COMPARE);			\
+    VERIFY (INF, INF, TYPE, COMPARE);			\
+  } while (0)
+
+void
+check_float (void)
+{
+  ALL_CHECKS (0.0f, -0.0f, __builtin_nanf(""), __builtin_inff(),
+	      float, comparecf);
+}
+
+void
+check_double (void)
+{
+  ALL_CHECKS (0.0, -0.0, __builtin_nan(""), __builtin_inf(),
+	      double, comparec);
+}
+
+void
+check_long_double (void)
+{
+  ALL_CHECKS (0.0l, -0.0l, __builtin_nanl(""), __builtin_infl(),
+	      long double, comparecl);
+}
+
+int
+main (void)
+{
+  check_float ();
+  check_double ();
+  check_long_double ();
+  exit (0);
+}
Index: gcc/testsuite/gcc.dg/builtin-complex-err-2.c
===================================================================
--- gcc/testsuite/gcc.dg/builtin-complex-err-2.c	(revision 0)
+++ gcc/testsuite/gcc.dg/builtin-complex-err-2.c	(revision 0)
@@ -0,0 +1,10 @@
+/* Test __builtin_complex errors.  Verify it does nto allow quiet
+   creation of complex types in C90.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c90 -pedantic-errors" } */
+
+void
+f (void)
+{
+  __builtin_complex (0.0, 0.0); /* { dg-error "ISO C90 does not support complex types" } */
+}
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c	(revision 177894)
+++ gcc/c-parser.c	(working copy)
@@ -6023,6 +6023,7 @@ c_parser_alignof_expression (c_parser *p
 			     assignment-expression ,
 			     assignment-expression )
      __builtin_types_compatible_p ( type-name , type-name )
+     __builtin_complex ( assignment-expression , assignment-expression )
 
    offsetof-member-designator:
      identifier
@@ -6405,6 +6406,52 @@ c_parser_postfix_expression (c_parser *p
 	      = comptypes (e1, e2) ? integer_one_node : integer_zero_node;
 	  }
 	  break;
+	case RID_BUILTIN_COMPLEX:
+	  c_parser_consume_token (parser);
+	  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	    {
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  loc = c_parser_peek_token (parser)->location;
+	  e1 = c_parser_expr_no_commas (parser, NULL);
+	  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+	    {
+	      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  e2 = c_parser_expr_no_commas (parser, NULL);
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  mark_exp_read (e1.value);
+	  mark_exp_read (e2.value);
+	  if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1.value))
+	      || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1.value))
+	      || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2.value))
+	      || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2.value)))
+	    {
+	      error_at (loc, "%<__builtin_complex%> operand "
+			"not of real binary floating-point type");
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  if (TYPE_MAIN_VARIANT (TREE_TYPE (e1.value))
+	      != TYPE_MAIN_VARIANT (TREE_TYPE (e2.value)))
+	    {
+	      error_at (loc,
+			"%<__builtin_complex%> operands of different types");
+	      expr.value = error_mark_node;
+	      break;
+	    }
+	  if (!flag_isoc99)
+	    pedwarn (loc, OPT_pedantic,
+		     "ISO C90 does not support complex types");
+	  expr.value = build2 (COMPLEX_EXPR,
+			       build_complex_type (TYPE_MAIN_VARIANT
+						   (TREE_TYPE (e1.value))),
+			       e1.value, e2.value);
+	  break;
 	case RID_AT_SELECTOR:
 	  gcc_assert (c_dialect_objc ());
 	  c_parser_consume_token (parser);

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]