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.gli...@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" }