@@ -9281,9 +9281,10 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
}
else
{
- cond.value
- = c_objc_common_truthvalue_conversion
- (cond_loc, default_conversion (cond.value));
+ /* Vector conditions see no default or truthvalue conversion. */
+ if (!VECTOR_INTEGER_TYPE_P (TREE_TYPE (cond.value)))
+ cond.value = c_objc_common_truthvalue_conversion
+ (cond_loc, default_conversion (cond.value));
c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node;
exp1 = c_parser_expression_conv (parser);
mark_exp_read (exp1.value);
@@ -5677,6 +5677,57 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
if (ifexp_int_operands)
ifexp = remove_c_maybe_const_expr (ifexp);
+ /* When this is a vector conditional but both alternatives are not vector
+ types promote them before applying default conversions. */
+ if (VECTOR_TYPE_P (TREE_TYPE (ifexp))
+ && !VECTOR_TYPE_P (TREE_TYPE (op1))
+ && !VECTOR_TYPE_P (TREE_TYPE (op2)))
+ {
+ tree ifexp_type = TREE_TYPE (ifexp);
+ if (TREE_CODE (ifexp) == VEC_COND_EXPR
+ && COMPARISON_CLASS_P (TREE_OPERAND (ifexp, 0)))
+ ifexp_type = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (ifexp, 0), 0));
+ tree stype;
+ if ((TREE_CODE (TREE_TYPE (op1)) != REAL_TYPE
+ && TREE_CODE (TREE_TYPE (op1)) != INTEGER_TYPE)
+ || (TREE_CODE (TREE_TYPE (op2)) != REAL_TYPE
+ && TREE_CODE (TREE_TYPE (op2)) != INTEGER_TYPE)
+ || ((stype = c_common_type (TREE_TYPE (op1), TREE_TYPE (op2)))
+ == error_mark_node))
+ {
+ error_at (colon_loc, "cannot infer scalar type from operands %qE, "
+ "%qE and %qT", op1, op2, TREE_TYPE (ifexp_type));
+ return error_mark_node;
+ }
+ if (TYPE_SIZE (stype) != TYPE_SIZE (TREE_TYPE (TREE_TYPE (ifexp)))
+ || (!INTEGRAL_TYPE_P (stype) && !SCALAR_FLOAT_TYPE_P (stype)))
+ {
+ error_at (colon_loc, "inferred scalar type %qT is not an integer or "
+ "floating-point type of the same size as %qT", stype,
+ TREE_TYPE (ifexp_type));
+ return error_mark_node;
+ }
+ tree vtype
+ = build_opaque_vector_type (stype,
+ TYPE_VECTOR_SUBPARTS (TREE_TYPE (ifexp)));
+ if (unsafe_conversion_p (stype, op1, NULL_TREE, false))
+ {
+ error_at (op1_loc, "conversion of scalar %qT to vector %qT "
+ "involves truncation", TREE_TYPE (op1), vtype);
+ return error_mark_node;
+ }
+ if (unsafe_conversion_p (stype, op2, NULL_TREE, false))
+ {
+ error_at (op2_loc, "conversion of scalar %qT to vector %qT "
+ "involves truncation", TREE_TYPE (op2), vtype);
+ return error_mark_node;
+ }
+ op1 = convert_and_check (op1_loc, stype, op1, false);
+ op2 = convert_and_check (op2_loc, stype, op2, false);
+ op1 = build_vector_from_val (vtype, save_expr (op1));
+ op2 = build_vector_from_val (vtype, save_expr (op2));
+ }
+
/* Promote both alternatives. */
if (TREE_CODE (TREE_TYPE (op1)) != VOID_TYPE)
@@ -5990,6 +6041,50 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
TYPE_MAIN_VARIANT (type2)))
result_type = composite_type (TYPE_MAIN_VARIANT (type1),
TYPE_MAIN_VARIANT (type2));
+ else if (VECTOR_TYPE_P (TREE_TYPE (ifexp))
+ && ((gnu_vector_type_p (type1) && code2 != VECTOR_TYPE)
+ || (gnu_vector_type_p (type2) && code1 != VECTOR_TYPE)))
+ {
+ enum stv_conv convert_flag = scalar_to_vector (colon_loc, VEC_COND_EXPR,
+ orig_op1, orig_op2, true);
+ switch (convert_flag)
+ {
+ case stv_error:
+ return error_mark_node;
+ case stv_firstarg:
+ {
+ bool maybe_const = true;
+ tree sc;
+ sc = c_fully_fold (op1, false, &maybe_const);
+ sc = save_expr (sc);
+ sc = convert (TREE_TYPE (type2), sc);
+ op1 = build_vector_from_val (type2, sc);
+ if (!maybe_const)
+ op1 = c_wrap_maybe_const (op1, true);
+ type1 = TREE_TYPE (op1);
+ code1 = TREE_CODE (type1);
+ result_type = type2;
+ break;
+ }
+ case stv_secondarg:
+ {
+ bool maybe_const = true;
+ tree sc;
+ sc = c_fully_fold (op2, false, &maybe_const);
+ sc = save_expr (sc);
+ sc = convert (TREE_TYPE (type1), sc);
+ op2 = build_vector_from_val (type1, sc);
+ if (!maybe_const)
+ op2 = c_wrap_maybe_const (op2, true);
+ type2 = TREE_TYPE (op2);
+ code2 = TREE_CODE (type2);
+ result_type = type1;
+ break;
+ }
+ default:
+ break;
+ }
+ }
if (!result_type)
{
@@ -6036,18 +6131,30 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
&& !TREE_OVERFLOW (orig_op2)));
}
- /* Need to convert condition operand into a vector mask. */
- if (VECTOR_TYPE_P (TREE_TYPE (ifexp)))
+ if (VECTOR_INTEGER_TYPE_P (TREE_TYPE (ifexp)))
{
+ /* Need to convert condition operand into a vector mask. */
tree vectype = TREE_TYPE (ifexp);
- tree elem_type = TREE_TYPE (vectype);
- tree zero = build_int_cst (elem_type, 0);
- tree zero_vec = build_vector_from_val (vectype, zero);
+ tree zero_vec = build_zero_cst (vectype);
tree cmp_type = truth_type_for (vectype);
ifexp = build2 (NE_EXPR, cmp_type, ifexp, zero_vec);
- }
- if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST))
+ if (!VECTOR_TYPE_P (type1)
+ || !VECTOR_TYPE_P (type2)
+ || TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)
+ || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype),
+ TYPE_VECTOR_SUBPARTS (type1))
+ || TYPE_SIZE (vectype) != TYPE_SIZE (type1))
+ {
+ error_at (op1_loc,
+ "incompatible vector types in conditional expression: "
+ "%qT, %qT and %qT", vectype, type1, type2);
+ return error_mark_node;
+ }
+
+ ret = build3_loc (colon_loc, VEC_COND_EXPR, result_type, ifexp, op1, op2);
+ }
+ else if (int_const || (ifexp_bcp && TREE_CODE (ifexp) == INTEGER_CST))
ret = fold_build3_loc (colon_loc, COND_EXPR, result_type, ifexp, op1, op2);
else
{
@@ -13175,7 +13175,7 @@ c = a > b; /* The result would be @{0, 0,-1, 0@} */
c = a == b; /* The result would be @{0,-1, 0,-1@} */
@end smallexample
-In C++, the ternary operator @code{?:} is available. @code{a?b:c}, where
+The ternary operator @code{?:} is supported for vectors. @code{a?b:c}, where
@code{b} and @code{c} are vectors of the same type and @code{a} is an
integer vector with the same number of elements of the same size as @code{b}
and @code{c}, computes all three arguments and creates a vector
similarity index 100%
rename from gcc/testsuite/g++.dg/ext/pr56790-1.C
rename to gcc/testsuite/c-c++-common/pr56790-1.c
similarity index 100%
rename from gcc/testsuite/g++.dg/opt/vectcond-1.C
rename to gcc/testsuite/c-c++-common/vectcond-1.c
new file mode 100644
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+
+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 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)
+{
+ *z = (*x < *z) ? (char)'1' : (char)'0';
+ *x = (*y < *z) ? *x : 4.2; /* { dg-error "" } */
+ *y = (*x < *z) ? 2.5 : *y; /* { dg-error "" } */
+ *t = *t ? *t : *t; /* { dg-error "" } */
+}
similarity index 100%
rename from gcc/testsuite/g++.dg/ext/vector21.C
rename to gcc/testsuite/c-c++-common/vector21.c
similarity index 100%
rename from gcc/testsuite/g++.dg/ext/vector22.C
rename to gcc/testsuite/c-c++-common/vector22.c
new file mode 100644
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-Wsign-conversion" } */
+// Ignore warning on some powerpc-linux configurations.
+// { dg-prune-output "non-standard ABI extension" }
+// Ignore warning on Linux/x86
+// { dg-prune-output "changes the ABI" }
+
+typedef double vecd __attribute__((vector_size(4*sizeof(double))));
+typedef float vecf __attribute__((vector_size(8*sizeof(float))));
+typedef long vecl __attribute__((vector_size(4*sizeof(long))));
+typedef short vecs __attribute__((vector_size(8*sizeof(short))));
+typedef char vecc __attribute__((vector_size(16*sizeof(char))));
+
+vecf f(vecf*a,float d,long long i){
+ return (*a<0)?d:i; // { dg-error "truncation" }
+}
+vecc g(vecc*a){
+ return (*a<0)?3LL:42UL; // { dg-error "inferred scalar type" }
+}
+vecc h(vecd*a){
+ return (*a<0)?'a':'c'; // { dg-error "inferred scalar type \[^\\n\]*double" }
+}
+vecd i(vecc*a){
+ return (*a<0)?1:0.; // { dg-error "inferred scalar type" }
+}
+vecl j(vecl*a,long i,unsigned long k){
+ return (*a<0)?i:k; // { dg-warning "may change the sign" }
+}
similarity index 100%
rename from gcc/testsuite/g++.dg/ext/vector35.C
rename to gcc/testsuite/c-c++-common/vector35.c
@@ -4,38 +4,14 @@ 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';
}
@@ -48,4 +24,3 @@ void l (vec2 *v, double x)
{
k (v, x);
}
-
new file mode 100644
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu23" } */
+
+typedef double vec __attribute__((vector_size(2*sizeof(double))));
+
+void i1 (vec *x, vec *y, vec *z)
+{
+ auto c = *y < *z;
+ *x = c ? *x : *y;
+}