This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++] Handle && || ! for simd vectors
- From: Marc Glisse <marc dot glisse at inria dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Cc: jason at redhat dot com
- Date: Sun, 17 Aug 2014 15:47:48 +0200 (CEST)
- Subject: [C++] Handle && || ! for simd vectors
- Authentication-results: sourceware.org; auth=none
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" }