The following adds support for vector conditionals in C. The support was nearly there already but c_objc_common_truthvalue_conversion rejecting vector types. Instead of letting them pass there unchanged I chose to instead skip it when parsing conditionals instead as a variant with less possible fallout. The part missing was promotion of a scalar second or third operand to vector, I copied the logic from binary operator handling for this.
I've moved the testcases I could easily spot over to c-c++-common. The C++ frontend implements vector ? '1' : '0' with promotion of both scalar to a vector but without applying integer promotions first (r0-124280-g07298ffd6f7c2d). I don't think this is what we document or backed by OpenCL or C++ valarray. I've left this out for now. I think we need better coverage in the testsuite for this and others, for example the patch below now accepts vector(int) ? vector(short) : 0 but the C++ frontend rejects this (I think OpenCL is fine with this). OpenCL says the conditional op is equivalent to select(exp3,exp2,exp1) which is defined as result[i] = if MSB of c[i] is set ? b[i] : a[i], with no restriction on the conditional. I'd appreciate pointers around the truthvalue conversion, supporting the || and && operators is a bit tricky due to this. We build vector compares as VEC_COND <compare, { -1, ... }, { 0, ... }> instead of just the compare - that should be done when not in a truthvalue context, but I'm not sure if there's something like truth-to-rvalue decay or if we should try to strip a VEC_COND on a truthvalue conversion of a compare instead? Bootstrapped and tested on x86_64-unknown-linux-gnu. Any comments? Thanks, Richard. PR c/106800 gcc/c/ * c-parser.cc (c_parser_conditional_expression): Skip truthvalue conversion for vector typed conditions. * c-typeck.cc (build_conditional_expr): Build a VEC_COND_EXPR for vector typed ifexpr. Do basic diagnostics. * g++.dg/ext/pr56790-1.C: Move ... * c-c++-common/pr56790-1.c: ... here. * g++.dg/opt/vectcond-1.C: Move ... * c-c++-common/vectcond-1.c: ... here. * g++.dg/ext/vector21.C: Move ... * c-c++-common/vector21.c: ... here. * g++.dg/ext/vector22.C: Move ... * c-c++-common/vector22.c: ... here. * g++.dg/ext/vector35.C: Move ... * c-c++-common/vector35.c: ... here. * g++.dg/ext/vector19.C: Move common parts ... * c-c++-common/vector19.c: ... here. * gcc.dg/vector-19.c: Add c23 auto case. --- gcc/c/c-parser.cc | 7 +- gcc/c/c-typeck.cc | 71 +++++++++++++++++-- .../pr56790-1.C => c-c++-common/pr56790-1.c} | 0 .../vectcond-1.c} | 0 gcc/testsuite/c-c++-common/vector19.c | 33 +++++++++ .../vector21.C => c-c++-common/vector21.c} | 0 .../vector22.C => c-c++-common/vector22.c} | 0 .../vector35.C => c-c++-common/vector35.c} | 0 gcc/testsuite/g++.dg/ext/vector19.C | 25 ------- gcc/testsuite/gcc.dg/vector-19.c | 10 +++ 10 files changed, 111 insertions(+), 35 deletions(-) rename gcc/testsuite/{g++.dg/ext/pr56790-1.C => c-c++-common/pr56790-1.c} (100%) rename gcc/testsuite/{g++.dg/opt/vectcond-1.C => c-c++-common/vectcond-1.c} (100%) create mode 100644 gcc/testsuite/c-c++-common/vector19.c rename gcc/testsuite/{g++.dg/ext/vector21.C => c-c++-common/vector21.c} (100%) rename gcc/testsuite/{g++.dg/ext/vector22.C => c-c++-common/vector22.c} (100%) rename gcc/testsuite/{g++.dg/ext/vector35.C => c-c++-common/vector35.c} (100%) create mode 100644 gcc/testsuite/gcc.dg/vector-19.c diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 12c5ed5d92c..b11e3afc5b6 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -9236,9 +9236,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); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7e0f01ed22b..f33c5c1ba3f 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -5990,6 +5990,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 +6080,31 @@ 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) + || !VECTOR_TYPE_P (result_type) + || type1 != type2 + || maybe_ne (TYPE_VECTOR_SUBPARTS (result_type), + TYPE_VECTOR_SUBPARTS (type1)) + || TYPE_SIZE (result_type) != 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 { diff --git a/gcc/testsuite/g++.dg/ext/pr56790-1.C b/gcc/testsuite/c-c++-common/pr56790-1.c similarity index 100% rename from gcc/testsuite/g++.dg/ext/pr56790-1.C rename to gcc/testsuite/c-c++-common/pr56790-1.c diff --git a/gcc/testsuite/g++.dg/opt/vectcond-1.C b/gcc/testsuite/c-c++-common/vectcond-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 diff --git a/gcc/testsuite/c-c++-common/vector19.c b/gcc/testsuite/c-c++-common/vector19.c new file mode 100644 index 00000000000..d764e6f6929 --- /dev/null +++ b/gcc/testsuite/c-c++-common/vector19.c @@ -0,0 +1,33 @@ +/* { 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) +{ + *x = (*y < *z) ? *x : 4.2; /* { dg-error "" } */ + *y = (*x < *z) ? 2.5 : *y; /* { dg-error "" } */ + *t = *t ? *t : *t; /* { dg-error "" } */ +} diff --git a/gcc/testsuite/g++.dg/ext/vector21.C b/gcc/testsuite/c-c++-common/vector21.c similarity index 100% rename from gcc/testsuite/g++.dg/ext/vector21.C rename to gcc/testsuite/c-c++-common/vector21.c diff --git a/gcc/testsuite/g++.dg/ext/vector22.C b/gcc/testsuite/c-c++-common/vector22.c similarity index 100% rename from gcc/testsuite/g++.dg/ext/vector22.C rename to gcc/testsuite/c-c++-common/vector22.c diff --git a/gcc/testsuite/g++.dg/ext/vector35.C b/gcc/testsuite/c-c++-common/vector35.c similarity index 100% rename from gcc/testsuite/g++.dg/ext/vector35.C rename to gcc/testsuite/c-c++-common/vector35.c diff --git a/gcc/testsuite/g++.dg/ext/vector19.C b/gcc/testsuite/g++.dg/ext/vector19.C index a41e8d51706..ef94eff7210 100644 --- a/gcc/testsuite/g++.dg/ext/vector19.C +++ b/gcc/testsuite/g++.dg/ext/vector19.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); } - diff --git a/gcc/testsuite/gcc.dg/vector-19.c b/gcc/testsuite/gcc.dg/vector-19.c new file mode 100644 index 00000000000..623d0048eda --- /dev/null +++ b/gcc/testsuite/gcc.dg/vector-19.c @@ -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; +} -- 2.35.3