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.
--
Marc GlisseIndex: tree.c
===================================================================
--- tree.c (revision 192542)
+++ tree.c (working copy)
@@ -10229,20 +10229,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: c-family/c-common.c
===================================================================
--- c-family/c-common.c (revision 192542)
+++ 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: cp/call.c
===================================================================
--- cp/call.c (revision 192542)
+++ cp/call.c (working copy)
@@ -4366,43 +4366,120 @@ 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))
+ {
+ if (TYPE_UNSIGNED (TREE_TYPE (arg1_type)))
+ {
+ arg1_type = signed_type_for (arg1_type);
+ arg1 = convert (arg1_type, arg1);
+ }
+ arg1 = build2 (LT_EXPR, 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))
Index: cp/typeck.c
===================================================================
--- cp/typeck.c (revision 192542)
+++ 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: testsuite/g++.dg/ext/vector19.C
===================================================================
--- testsuite/g++.dg/ext/vector19.C (revision 0)
+++ 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: testsuite/g++.dg/ext/vector19.C
___________________________________________________________________
Added: svn:keywords
+ Author Date Id Revision URL
Added: svn:eol-style
+ native