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]

[C++] Handle && || ! for simd vectors


Hello,

as discussed in the PR, I did not add a sequence point, it can be done later if we decide so (the other direction would be bad), but if we ever do I believe we should add one to ?: at the same time.

For the mixed 'scalar && vector', I chose to implement it with a branch, since we can, it made sense to me to give it semantics closer to scalar && scalar, while 'vector && scalar' gets the same semantics as 'vector && vector' because there is no choice. So a&&b is always equivalent to a?(b?T:F):F where T and F are vectors of the right type.

I replaced vector27, it was mostly a placeholder. I should probably remove vector9 instead of updating it, it is pretty useless now.

I swapped save_expr and convert because gratuitously repeating the conversion as many times as there are elements in the vector makes the dumps quite horrible (and wastes compilation time).

Bootstrap+testsuite on x86_64-linux-gnu.

2014-08-18  Marc Glisse  <marc.glisse@inria.fr>

	PR c++/54427
	PR c++/57198
	PR c++/58845
gcc/c-family/
	* c-common.c (warn_logical_operator): Punt for vectors.
gcc/cp/
	* typeck.c (cp_build_binary_op): save_expr after convert to save
	redundant operations.
	[TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR]: Handle vectors.
	(cp_build_unary_op) [TRUTH_NOT_EXPR]: Likewise.
gcc/
	* doc/extend.texi (Vector Extensions): Document &&, ||, ! in C++.
gcc/testsuite/
	* g++.dg/ext/vector9.C: Update, not an error anymore.
	* g++.dg/ext/vector27.C: Replace with new test.
	* g++.dg/ext/vector28.C: New file.
	* g++.dg/other/error23.C: Update to a different error.

--
Marc Glisse
Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c	(revision 214073)
+++ gcc/c-family/c-common.c	(working copy)
@@ -1663,20 +1663,24 @@ warn_logical_operator (location_t locati
   if (CONSTANT_CLASS_P (op_left) || CONSTANT_CLASS_P (op_right))
     return;
 
   /* This warning only makes sense with logical operands.  */
   if (!(truth_value_p (TREE_CODE (op_left))
 	|| INTEGRAL_TYPE_P (TREE_TYPE (op_left)))
       || !(truth_value_p (TREE_CODE (op_right))
 	   || INTEGRAL_TYPE_P (TREE_TYPE (op_right))))
     return;
 
+  /* The range computations only work with scalars.  */
+  if (VECTOR_TYPE_P (TREE_TYPE (op_left))
+      || VECTOR_TYPE_P (TREE_TYPE (op_right)))
+    return;
 
   /* We first test whether either side separately is trivially true
      (with OR) or trivially false (with AND).  If so, do not warn.
      This is a common idiom for testing ranges of data types in
      portable code.  */
   lhs = make_range (op_left, &in0_p, &low0, &high0, &strict_overflow_p);
   if (!lhs)
     return;
   if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
     lhs = C_MAYBE_CONST_EXPR_EXPR (lhs);
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c	(revision 214073)
+++ gcc/cp/typeck.c	(working copy)
@@ -4061,32 +4061,32 @@ cp_build_binary_op (location_t location,
     {
       enum stv_conv convert_flag = scalar_to_vector (location, code, op0, op1,
 						     complain & tf_error);
 
       switch (convert_flag)
         {
           case stv_error:
             return error_mark_node;
           case stv_firstarg:
             {
-	      op0 = save_expr (op0);
               op0 = convert (TREE_TYPE (type1), op0);
+	      op0 = save_expr (op0);
               op0 = build_vector_from_val (type1, op0);
               type0 = TREE_TYPE (op0);
               code0 = TREE_CODE (type0);
               converted = 1;
               break;
             }
           case stv_secondarg:
             {
-	      op1 = save_expr (op1);
               op1 = convert (TREE_TYPE (type0), op1);
+	      op1 = save_expr (op1);
               op1 = build_vector_from_val (type0, op1);
               type1 = TREE_TYPE (op1);
               code1 = TREE_CODE (type1);
               converted = 1;
               break;
             }
           default:
             break;
         }
     }
@@ -4207,25 +4207,63 @@ cp_build_binary_op (location_t location,
 		     || (TREE_CODE (op1) == INTEGER_CST
 			 && ! integer_all_onesp (op1)));
 	  common = 1;
 	}
       break;
 
     case TRUTH_ANDIF_EXPR:
     case TRUTH_ORIF_EXPR:
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
-      if (VECTOR_TYPE_P (type0) || VECTOR_TYPE_P (type1))
+      if (!VECTOR_TYPE_P (type0) && VECTOR_TYPE_P (type1))
 	{
-	  sorry ("logical operation on vector type");
-	  return error_mark_node;
+	  if (!COMPARISON_CLASS_P (op1))
+	    op1 = cp_build_binary_op (EXPR_LOCATION (op1), NE_EXPR, op1,
+				      build_zero_cst (type1), complain);
+	  if (code == TRUTH_ANDIF_EXPR)
+	    {
+	      tree z = build_zero_cst (TREE_TYPE (op1));
+	      return build_conditional_expr (location, op0, op1, z, complain);
+	    }
+	  else if (code == TRUTH_ORIF_EXPR)
+	    {
+	      tree m1 = build_all_ones_cst (TREE_TYPE (op1));
+	      return build_conditional_expr (location, op0, m1, op1, complain);
+	    }
+	  else
+	    gcc_unreachable ();
 	}
+      if (VECTOR_TYPE_P (type0))
+	{
+	  if (!COMPARISON_CLASS_P (op0))
+	    op0 = cp_build_binary_op (EXPR_LOCATION (op0), NE_EXPR, op0,
+				      build_zero_cst (type0), complain);
+	  if (!VECTOR_TYPE_P (type1))
+	    {
+	      tree m1 = build_all_ones_cst (TREE_TYPE (op0));
+	      tree z = build_zero_cst (TREE_TYPE (op0));
+	      op1 = build_conditional_expr (location, op1, z, m1, complain);
+	    }
+	  else if (!COMPARISON_CLASS_P (op1))
+	    op1 = cp_build_binary_op (EXPR_LOCATION (op1), NE_EXPR, op1,
+				      build_zero_cst (type1), complain);
+
+	  if (code == TRUTH_ANDIF_EXPR)
+	    code = BIT_AND_EXPR;
+	  else if (code == TRUTH_ORIF_EXPR)
+	    code = BIT_IOR_EXPR;
+	  else
+	    gcc_unreachable ();
+
+	  return cp_build_binary_op (location, code, op0, op1, complain);
+	}
+
       result_type = boolean_type_node;
       break;
 
       /* Shift operations: result has same type as first operand;
 	 always convert second operand to int.
 	 Also set SHORT_SHIFT if shifting rightward.  */
 
     case RSHIFT_EXPR:
       if (code0 == VECTOR_TYPE && code1 == INTEGER_TYPE
           && TREE_CODE (TREE_TYPE (type0)) == INTEGER_TYPE)
@@ -5701,20 +5739,23 @@ cp_build_unary_op (enum tree_code code,
 	errstring = _("wrong type argument to conjugation");
       else if (!noconvert)
 	{
 	  arg = cp_default_conversion (arg, complain);
 	  if (arg == error_mark_node)
 	    return error_mark_node;
 	}
       break;
 
     case TRUTH_NOT_EXPR:
+      if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg)))
+	return cp_build_binary_op (input_location, EQ_EXPR, arg,
+				   build_zero_cst (TREE_TYPE (arg)), complain);
       arg = perform_implicit_conversion (boolean_type_node, arg,
 					 complain);
       val = invert_truthvalue_loc (input_location, arg);
       if (arg != error_mark_node)
 	return val;
       errstring = _("in argument to unary !");
       break;
 
     case NOP_EXPR:
       break;
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 214073)
+++ gcc/doc/extend.texi	(working copy)
@@ -7901,20 +7901,27 @@ integer vector with the same number of e
 and @code{c}, computes all three arguments and creates a vector
 @code{@{a[0]?b[0]:c[0], a[1]?b[1]:c[1], @dots{}@}}.  Note that unlike in
 OpenCL, @code{a} is thus interpreted as @code{a != 0} and not @code{a < 0}.
 As in the case of binary operations, this syntax is also accepted when
 one of @code{b} or @code{c} is a scalar that is then transformed into a
 vector. If both @code{b} and @code{c} are scalars and the type of
 @code{true?b:c} has the same size as the element type of @code{a}, then
 @code{b} and @code{c} are converted to a vector type whose elements have
 this type and with the same number of elements as @code{a}.
 
+In C++, the logic operators @code{!, &&, ||} are available for vectors.
+@code{!v} is equivalent to @code{v == 0}, @code{a && b} is equivalent to
+@code{a!=0 & b!=0} and @code{a || b} is equivalent to @code{a!=0 | b!=0}.
+For mixed operations between a scalar @code{s} and a vector @code{v},
+@code{s && v} is equivalent to @code{s?v!=0:0} (the evaluation is
+short-circuit) and @code{v && s} is equivalent to @code{v!=0 & (s?-1:0)}.
+
 Vector shuffling is available using functions
 @code{__builtin_shuffle (vec, mask)} and
 @code{__builtin_shuffle (vec0, vec1, mask)}.
 Both functions construct a permutation of elements from one or two
 vectors and return a vector of the same type as the input vector(s).
 The @var{mask} is an integral vector with the same width (@var{W})
 and element count (@var{N}) as the output vector.
 
 The elements of the input vectors are numbered in memory ordering of
 @var{vec0} beginning at 0 and @var{vec1} beginning at @var{N}.  The
Index: gcc/testsuite/g++.dg/ext/vector27.C
===================================================================
--- gcc/testsuite/g++.dg/ext/vector27.C	(revision 214073)
+++ gcc/testsuite/g++.dg/ext/vector27.C	(working copy)
@@ -1,7 +1,13 @@
-// PR c++/58845
+/* { dg-do compile } */
 
-void foo()
+typedef int veci __attribute__ ((vector_size (4 * sizeof (int))));
+typedef float vecf __attribute__ ((vector_size (4 * sizeof (float))));
+
+void f (veci *a, veci *b, int c)
+{
+  *a = !*a || *b < ++c;
+}
+void g (vecf *a, vecf *b)
 {
-  int v __attribute__((vector_size(8)));
-  v = v || v;			// { dg-bogus "" "" { xfail *-*-* } }
+  *a = (*a < 1 && !(*b > 2)) ? *a + *b : 3;
 }
Index: gcc/testsuite/g++.dg/ext/vector28.C
===================================================================
--- gcc/testsuite/g++.dg/ext/vector28.C	(revision 0)
+++ gcc/testsuite/g++.dg/ext/vector28.C	(working copy)
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+
+typedef int veci __attribute__ ((vector_size (4 * sizeof (int))));
+typedef float vecf __attribute__ ((vector_size (4 * sizeof (float))));
+
+void f (veci *a, vecf *b, int c)
+{
+  *a = c || *b;
+  *a = *a || c;
+}
Index: gcc/testsuite/g++.dg/ext/vector9.C
===================================================================
--- gcc/testsuite/g++.dg/ext/vector9.C	(revision 214073)
+++ gcc/testsuite/g++.dg/ext/vector9.C	(working copy)
@@ -1,10 +1,10 @@
 // PR c++/34891
 
 typedef float v4f __attribute__((vector_size(8)));
 typedef int   v4i __attribute__((vector_size(8)));
 
 void foo()
 {
   v4f v;
-  !(v4i)v; // { dg-error "v4i|argument" }
+  !(v4i)v;
 }
Index: gcc/testsuite/g++.dg/other/error23.C
===================================================================
--- gcc/testsuite/g++.dg/other/error23.C	(revision 214073)
+++ gcc/testsuite/g++.dg/other/error23.C	(working copy)
@@ -1,5 +1,5 @@
 // PR c++/34918
 // { dg-do compile }
 
 int v __attribute ((vector_size (8)));
-bool b = !(v - v);	// { dg-error "could not convert .\\(__vector.2. int\\)\\{0, 0\\}. from .__vector.2. int. to .bool.|in argument to unary" }
+bool b = !(v - v);	// { dg-error "not convert .__vector.2. int. to .bool. in initialization" }

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