diff mbox series

[RFC] c/106800 - support vector condition operation in C

Message ID 20240718131620.00F1B386076C@sourceware.org
State New
Headers show
Series [RFC] c/106800 - support vector condition operation in C | expand

Commit Message

Richard Biener July 18, 2024, 1:15 p.m. UTC
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 mbox series

Patch

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;
+}