Patchwork [C++] Handle ?: for vectors

login
register
mail settings
Submitter Marc Glisse
Date Oct. 25, 2012, 9:09 a.m.
Message ID <alpine.DEB.2.02.1210251106500.30565@stedding.saclay.inria.fr>
Download mbox | patch
Permalink /patch/194080/
State New
Headers show

Comments

Marc Glisse - Oct. 25, 2012, 9:09 a.m.
On Wed, 17 Oct 2012, Marc Glisse wrote:

> Hello,
>
> this patch adds support for vector conditions to the C++ front-end. Note that 
> the testcase currently only applies to x86. This is because there is work 
> remaining in the middle-end for the case where vector selection for this 
> vector mode is not provided by the target. There are also many middle-end 
> bugs, so the testcase will crash with -O. I believe it makes sense to 
> introduce front-end support early, because this way I'll be able to add 
> testcases when I fix middle-end issues. Not documenting until this is 
> actually usable.
>
> gcc/
> 	* tree.c (signed_or_unsigned_type_for): Handle vectors.
>
> gcc/cp/
> 	* typeck.c (build_x_conditional_expr): Handle VEC_COND_EXPR.
> 	* call.c (build_conditional_expr_1): Likewise.
>
> gcc/c-family/
> 	* c-common.c (scalar_to_vector): Handle VEC_COND_EXPR.
>
> gcc/testsuite/
> 	* g++.dg/ext/vector19.C: New testcase.

Here is a version with != 0, as discussed.
Jason Merrill - Oct. 25, 2012, 12:33 p.m.
OK.

Jason

Patch

Index: gcc/c-family/c-common.c

===================================================================
--- gcc/c-family/c-common.c	(revision 192797)

+++ gcc/c-family/c-common.c	(working copy)

@@ -11467,20 +11467,22 @@  scalar_to_vector (location_t loc, enum t

 	      return stv_firstarg;
 	  }
 	break;
 
       case BIT_IOR_EXPR:
       case BIT_XOR_EXPR:
       case BIT_AND_EXPR:
 	integer_only_op = true;
 	/* ... fall through ...  */
 
+      case VEC_COND_EXPR:

+

       case PLUS_EXPR:
       case MINUS_EXPR:
       case MULT_EXPR:
       case TRUNC_DIV_EXPR:
       case CEIL_DIV_EXPR:
       case FLOOR_DIV_EXPR:
       case ROUND_DIV_EXPR:
       case EXACT_DIV_EXPR:
       case TRUNC_MOD_EXPR:
       case FLOOR_MOD_EXPR:
Index: gcc/testsuite/g++.dg/ext/vector19.C

===================================================================
--- gcc/testsuite/g++.dg/ext/vector19.C	(revision 0)

+++ gcc/testsuite/g++.dg/ext/vector19.C	(revision 0)

@@ -0,0 +1,56 @@ 

+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */

+/* { dg-options "-std=c++11 -mavx2" } */

+

+// The target restrictions and the -mavx2 flag are meant to disappear

+// once vector lowering is in place.

+

+typedef double vec __attribute__((vector_size(2*sizeof(double))));

+typedef signed char vec2 __attribute__((vector_size(16)));

+typedef unsigned char vec2u __attribute__((vector_size(16)));

+

+void f (vec *x, vec *y, vec *z)

+{

+  *x = (*y < *z) ? *x : *y;

+}

+

+void g (vec *x, vec *y, vec *z)

+{

+  *x = (*y < *z) ? *x : 42;

+}

+

+void h (vec *x, vec *y, vec *z)

+{

+  *x = (*y < *z) ? 3. : *y;

+}

+

+void i1 (vec *x, vec *y, vec *z)

+{

+  auto c = *y < *z;

+  *x = c ? *x : *y;

+}

+

+void i2 (vec2 *x, vec2 *y, vec2u *z)

+{

+  *x = *y ? *x : *y;

+  *y = *z ? *x : *y;

+}

+

+void j (vec2 *x, vec2 *y, vec2 *z, vec *t)

+{

+  *x = (*y < *z) ? *x : 4.2; /* { dg-error "" } */

+  *y = (*x < *z) ? 2.5 : *y; /* { dg-error "" } */

+  *t = *t ? *t : *t; /* { dg-error "" } */

+  *z = (*x < *z) ? '1' : '0'; /* { dg-error "" } */

+  // The last one may eventually be accepted.

+}

+

+template <class A, class B>

+auto k (A *a, B b) -> decltype (*a ? *a : b);

+

+void k (...) {}

+

+void l (vec2 *v, double x)

+{

+  k (v, x);

+}

+


Property changes on: gcc/testsuite/g++.dg/ext/vector19.C
___________________________________________________________________
Added: svn:eol-style
   + native
Added: svn:keywords
   + Author Date Id Revision URL

Index: gcc/tree.c

===================================================================
--- gcc/tree.c	(revision 192797)

+++ gcc/tree.c	(working copy)

@@ -10234,20 +10234,31 @@  widest_int_cst_value (const_tree x)

 /* If TYPE is an integral or pointer type, return an integer type with
    the same precision which is unsigned iff UNSIGNEDP is true, or itself
    if TYPE is already an integer type of signedness UNSIGNEDP.  */
 
 tree
 signed_or_unsigned_type_for (int unsignedp, tree type)
 {
   if (TREE_CODE (type) == INTEGER_TYPE && TYPE_UNSIGNED (type) == unsignedp)
     return type;
 
+  if (TREE_CODE (type) == VECTOR_TYPE)

+    {

+      tree inner = TREE_TYPE (type);

+      tree inner2 = signed_or_unsigned_type_for (unsignedp, inner);

+      if (!inner2)

+	return NULL_TREE;

+      if (inner == inner2)

+	return type;

+      return build_vector_type (inner2, TYPE_VECTOR_SUBPARTS (type));

+    }

+

   if (!INTEGRAL_TYPE_P (type)
       && !POINTER_TYPE_P (type))
     return NULL_TREE;
 
   return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp);
 }
 
 /* If TYPE is an integral or pointer type, return an integer type with
    the same precision which is unsigned, or itself if TYPE is already an
    unsigned integer type.  */
Index: gcc/cp/typeck.c

===================================================================
--- gcc/cp/typeck.c	(revision 192797)

+++ gcc/cp/typeck.c	(working copy)

@@ -5803,21 +5803,22 @@  build_x_conditional_expr (location_t loc

 	  || (op1 && type_dependent_expression_p (op1))
 	  || type_dependent_expression_p (op2))
 	return build_min_nt_loc (loc, COND_EXPR, ifexp, op1, op2);
       ifexp = build_non_dependent_expr (ifexp);
       if (op1)
 	op1 = build_non_dependent_expr (op1);
       op2 = build_non_dependent_expr (op2);
     }
 
   expr = build_conditional_expr (ifexp, op1, op2, complain);
-  if (processing_template_decl && expr != error_mark_node)

+  if (processing_template_decl && expr != error_mark_node

+      && TREE_CODE (expr) != VEC_COND_EXPR)

     {
       tree min = build_min_non_dep (COND_EXPR, expr,
 				    orig_ifexp, orig_op1, orig_op2);
       /* In C++11, remember that the result is an lvalue or xvalue.
          In C++98, lvalue_kind can just assume lvalue in a template.  */
       if (cxx_dialect >= cxx0x
 	  && lvalue_or_rvalue_with_address_p (expr)
 	  && !lvalue_or_rvalue_with_address_p (min))
 	TREE_TYPE (min) = cp_build_reference_type (TREE_TYPE (min),
 						   !real_lvalue_p (expr));
Index: gcc/cp/call.c

===================================================================
--- gcc/cp/call.c	(revision 192797)

+++ gcc/cp/call.c	(working copy)

@@ -4366,43 +4366,113 @@  build_conditional_expr_1 (tree arg1, tre

 	pedwarn (input_location, OPT_Wpedantic, 
 		 "ISO C++ forbids omitting the middle term of a ?: expression");
 
       /* Make sure that lvalues remain lvalues.  See g++.oliva/ext1.C.  */
       if (real_lvalue_p (arg1))
 	arg2 = arg1 = stabilize_reference (arg1);
       else
 	arg2 = arg1 = save_expr (arg1);
     }
 
+  /* If something has already gone wrong, just pass that fact up the

+     tree.  */

+  if (error_operand_p (arg1)

+      || error_operand_p (arg2)

+      || error_operand_p (arg3))

+    return error_mark_node;

+

+  orig_arg2 = arg2;

+  orig_arg3 = arg3;

+

+  if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg1)))

+    {

+      arg1 = force_rvalue (arg1, complain);

+      arg2 = force_rvalue (arg2, complain);

+      arg3 = force_rvalue (arg3, complain);

+

+      tree arg1_type = TREE_TYPE (arg1);

+      arg2_type = TREE_TYPE (arg2);

+      arg3_type = TREE_TYPE (arg3);

+

+      if (TREE_CODE (arg2_type) != VECTOR_TYPE

+	  && TREE_CODE (arg3_type) != VECTOR_TYPE)

+	{

+	  if (complain & tf_error)

+	    error ("at least one operand of a vector conditional operator "

+		   "must be a vector");

+	  return error_mark_node;

+	}

+

+      if ((TREE_CODE (arg2_type) == VECTOR_TYPE)

+	  != (TREE_CODE (arg3_type) == VECTOR_TYPE))

+	{

+	  enum stv_conv convert_flag =

+	    scalar_to_vector (input_location, VEC_COND_EXPR, arg2, arg3,

+			      complain & tf_error);

+

+	  switch (convert_flag)

+	    {

+	      case stv_error:

+		return error_mark_node;

+	      case stv_firstarg:

+		{

+		  arg2 = convert (TREE_TYPE (arg3_type), arg2);

+		  arg2 = build_vector_from_val (arg3_type, arg2);

+		  arg2_type = TREE_TYPE (arg2);

+		  break;

+		}

+	      case stv_secondarg:

+		{

+		  arg3 = convert (TREE_TYPE (arg2_type), arg3);

+		  arg3 = build_vector_from_val (arg2_type, arg3);

+		  arg3_type = TREE_TYPE (arg3);

+		  break;

+		}

+	      default:

+		break;

+	    }

+	}

+

+      if (!same_type_p (arg2_type, arg3_type)

+	  || TYPE_VECTOR_SUBPARTS (arg1_type)

+	     != TYPE_VECTOR_SUBPARTS (arg2_type)

+	  || TYPE_SIZE (arg1_type) != TYPE_SIZE (arg2_type))

+	{

+	  if (complain & tf_error)

+	    error ("incompatible vector types in conditional expression: "

+		   "%qT, %qT and %qT", TREE_TYPE (arg1), TREE_TYPE (orig_arg2),

+		   TREE_TYPE (orig_arg3));

+	  return error_mark_node;

+	}

+

+      if (!COMPARISON_CLASS_P (arg1))

+	arg1 = build2 (NE_EXPR, signed_type_for (arg1_type), arg1,

+		       build_zero_cst (arg1_type));

+      return build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);

+    }

+

   /* [expr.cond]
 
      The first expression is implicitly converted to bool (clause
      _conv_).  */
   arg1 = perform_implicit_conversion_flags (boolean_type_node, arg1, complain,
 					    LOOKUP_NORMAL);
-

-  /* If something has already gone wrong, just pass that fact up the

-     tree.  */

-  if (error_operand_p (arg1)

-      || error_operand_p (arg2)

-      || error_operand_p (arg3))

+  if (error_operand_p (arg1))

     return error_mark_node;
 
   /* [expr.cond]
 
      If either the second or the third operand has type (possibly
      cv-qualified) void, then the lvalue-to-rvalue (_conv.lval_),
      array-to-pointer (_conv.array_), and function-to-pointer
      (_conv.func_) standard conversions are performed on the second
      and third operands.  */
-  orig_arg2 = arg2;

-  orig_arg3 = arg3;

   arg2_type = unlowered_expr_type (arg2);
   arg3_type = unlowered_expr_type (arg3);
   if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type))
     {
       /* Do the conversions.  We don't these for `void' type arguments
 	 since it can't have any effect and since decay_conversion
 	 does not handle that case gracefully.  */
       if (!VOID_TYPE_P (arg2_type))
 	arg2 = decay_conversion (arg2, complain);
       if (!VOID_TYPE_P (arg3_type))