Support subscript operation on svbool_t.  This considers svbool_t as a packed
bit-vector of 1-bit boolean data.

gcc/ChangeLog:

        * c-family/c-common.cc (convert_vector_to_array_for_subscript): Prepare
        the first stage of the subscript subtree for a later gimplification
        step.  Transform only the base subscript ARRAY_REF type expression.
        * gimple-fold.cc (maybe_canonicalize_mem_ref_addr): We expect all
        packed vector booleans to have been transformed into a wider-element
        vector type, so assert if any vector booleans in their natural form
        have escaped to this point.
        * gimplify.cc (gimplify_compound_lval): Perform the second step of the
        transformation of packed boolean vectors to a wider-element type.
        Unpack to this wider-type using a VEC_CONVERT IFN call; repack once the
        base subscript expression has been gimplified.  Lvalue and Rvalue
        subscripts are handled accordingly.
        * c/c-typeck.cc: Diagnose taking address of svbool_t element.
        * cp/typeck.cc: Diagnose taking address of svbool_t element.
        * config/aarch64/aarch64.cc: Allow subscript operator on svbool_t.

testsuite/ChangeLog:

        * gcc.target/aarch64/sve/acle/general/cops_bool.c: Add subscript tests.
---
 gcc/c-family/c-common.cc                      |  24 ++++-
 gcc/c/c-typeck.cc                             |  15 +++
 gcc/config/aarch64/aarch64.cc                 |   2 -
 gcc/cp/typeck.cc                              |  15 +++
 gcc/gimple-fold.cc                            |   5 +
 gcc/gimplify.cc                               |  68 ++++++++++++
 .../aarch64/sve/acle/general/cops_bool.c      | 100 +++++++++++++++++-
 7 files changed, 223 insertions(+), 6 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 76b54648c43..2b3470f19e8 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -9271,9 +9271,29 @@ convert_vector_to_array_for_subscript (location_t loc,
                                       tree *vecp, tree index)
 {
   bool ret = false;
-  if (gnu_vector_type_p (TREE_TYPE (*vecp)))
+  tree type = TREE_TYPE (*vecp);
+
+  /* Packed vector booleans are tricky.  Reading and writing to individual
+     elements have to done by unpacking them to their container mode vector
+     type, doing the ARRAY_REF on the unpacked vector and then re-packing them
+     back to vector booleans.  This unpacking is set up here i.e. the type
+     of the ARRAY_REF subtree is rewritten to an unpacked type here, and the
+     actual unpacking is done during gimplification in gimplify_compound_lval
+     in gimplify.cc.  See there for notes on the unpacking and re-packing.  The
+     reason it is done in two steps is that the unpacking involves inventing
+     temporaries by IFN calls which are great for rvalues, but don't play ball
+     when the ARRAY_REF is an lvalue.  Therefore all the temporaries are gen
+     during gimplification and any intermediate IFN calls are made rvalues.  */
+  if (VECTOR_BOOLEAN_TYPE_P (type))
+    {
+      machine_mode vmode = TYPE_MODE (type);
+      scalar_mode smode = SCALAR_TYPE_MODE (TREE_TYPE (type));
+      bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (type));
+      type = c_common_related_vtype_for_mode (vmode, smode, unsignedp);
+    }
+
+  if (gnu_vector_type_p (type))
     {
-      tree type = TREE_TYPE (*vecp);
       tree newitype;
 
       ret = !lvalue_p (*vecp);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 286fc6bcd02..96c6cc23591 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -5610,6 +5610,21 @@ build_unary_op (location_t location, enum tree_code 
code, tree xarg,
     case ADDR_EXPR:
       /* Note that this operation never does default_conversion.  */
 
+      /* & of vector boolean element is not allowed.  This is a bit tricky.
+        c_common_convert_vector_to_array_ref () leaves the ARRAY_REF of 
svbool_t
+        in a partially-rewritten format to char[].  Everything except the inner
+        reference to the svbool_t object is rewritten.  Walk down to this ref. 
 */
+      if (TREE_CODE (xarg) == ARRAY_REF
+         && TREE_CODE (TREE_OPERAND (xarg, 0)) == VIEW_CONVERT_EXPR
+         && TREE_CODE (TREE_TYPE (TREE_OPERAND (xarg, 0))) == ARRAY_TYPE
+         && VECTOR_BOOLEAN_TYPE_P
+             (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (xarg, 0), 0))))
+       {
+         error_at (location, "taking address of a boolean vector element %qT",
+                   TREE_TYPE (TREE_OPERAND (TREE_OPERAND (xarg, 0), 0)));
+         return error_mark_node;
+       }
+
       /* The operand of unary '&' must be an lvalue (which excludes
         expressions of type void), or, in C99, the result of a [] or
         unary '*' operator.  */
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 0fa31608f2d..4c11d045e46 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -29634,8 +29634,6 @@ aarch64_valid_vector_boolean_op (int code)
     case GT_EXPR:
     case GE_EXPR:
       return N_("only == and != operations permitted on svbool_t");
-    case ARRAY_REF:
-      return N_("subscript operation not supported on svbool_t");
     default:
       /* Operation permitted.  */
       return NULL;
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 083e577bab4..27fe81aff54 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -7196,6 +7196,21 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, 
tsubst_flags_t complain)
 
   gcc_assert (!(identifier_p (arg) && IDENTIFIER_ANY_OP_P (arg)));
 
+  /* & of vector boolean element is not allowed.  This is a bit tricky.
+     c_common_convert_vector_to_array_ref () leaves the ARRAY_REF of svbool_t
+     in a partially-rewritten format to char[].  Everything except the inner
+     reference to the svbool_t object is rewritten.  Walk down to this ref.  */
+  if (TREE_CODE (arg) == ARRAY_REF
+      && TREE_CODE (TREE_OPERAND (arg, 0)) == VIEW_CONVERT_EXPR
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))) == ARRAY_TYPE
+      && VECTOR_BOOLEAN_TYPE_P
+         (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0))))
+    {
+      error_at (loc, "taking address of a boolean vector element %qT",
+               TREE_TYPE (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)));
+      return error_mark_node;
+    }
+
   if (TREE_CODE (arg) == COMPONENT_REF && type_unknown_p (arg)
       && !really_overloaded_fn (arg))
     {
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index b6456139687..3a35e912496 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -6334,6 +6334,11 @@ maybe_canonicalize_mem_ref_addr (tree *t, bool is_debug 
= false)
       && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*t, 0), 0))))
     {
       tree vtype = TREE_TYPE (TREE_OPERAND (TREE_OPERAND (*t, 0), 0));
+
+      /* By now all ARRAY_REFs on packed bool vectors ought to have been
+         transformed to ARRAY_REFs on unpacked bool vectors.  */
+      gcc_assert (!VECTOR_BOOLEAN_TYPE_P (vtype));
+
       if (VECTOR_TYPE_P (vtype))
        {
          tree low = array_ref_low_bound (*t);
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 160e7fc9df6..a18f8c7bde4 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -3565,6 +3565,62 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, 
gimple_seq *post_p,
        need_non_reg = true;
     }
 
+  /* Step 1a: If the base expression is a packed boolean vector type , it 
cannot
+     live in its current form beyond this point. It needs transfomation into
+     a vector of its elements its container size.
+
+     If the ARRAY_REF is on LHS:
+
+       foo (bool_vec b, ...)
+       {
+         ...
+         b[i] = rhs;
+         ...
+       }
+
+     The statement transforms to:
+
+       char_vec t = .VEC_CONVERT (b);
+       t[i] = rhs;
+       b = .VEC_CONVERT (t);
+
+     If the ARRAY_REF is an RHS:
+
+       foo (bool_vec b, ...)
+       {
+         ...
+         lhs = b[i];
+         ...
+       }
+
+     The statement transforms to:
+
+       char_vec t = .VEC_CONVERT (b);
+       lhs = t[i];
+   */
+  tree vbool_type = NULL_TREE;
+  tree vbool_lhs = NULL_TREE;
+  if (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (*p)))
+    {
+      machine_mode vmode = TYPE_MODE (TREE_TYPE (*p));
+      scalar_mode smode = SCALAR_TYPE_MODE (TREE_TYPE (TREE_TYPE (*p)));
+      bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (*p)));
+      tree t1 = lang_hooks.types.related_vtype_for_mode (vmode, smode, 
unsignedp);
+      vbool_type = TREE_TYPE (*p);
+      vbool_lhs = *p;
+
+      /* Unpack a bool vector to a vector of elements of type returned by
+        c_vector_type_for_mode.  */
+      t1 = build_call_expr_internal_loc (loc, IFN_VEC_CONVERT, t1, 1, *p);
+
+      /* Get a tmp var and replace the base expression with lhs.
+        Replace the innermost ref to the new temp.  */
+      *p = get_initialized_tmp_var (t1, pre_p);
+
+      /* Its OK to generate an rvalue for *p.  */
+      fallback |= fb_rvalue;
+    }
+
   /* Step 2 is to gimplify the base expression.  Make sure lvalue is set
      so as to match the min_lval predicate.  Failure to do so may result
      in the creation of large aggregate temporaries.  */
@@ -3580,6 +3636,18 @@ gimplify_compound_lval (tree *expr_p, gimple_seq *pre_p, 
gimple_seq *post_p,
   if (need_non_reg && (fallback & fb_rvalue))
     prepare_gimple_addressable (p, pre_p);
 
+  /* Step 2b: if we encountered a packed vector bool as an lvalue, repack the
+     unpacked char vector into a packed bool vector.  */
+  if (vbool_lhs != NULL_TREE)
+    {
+      mark_addressable (*p);
+      if (fallback & fb_lvalue)
+       {
+         tree rhs = *p;
+         rhs = build_call_expr_internal_loc (loc, IFN_VEC_CONVERT, vbool_type, 
1, rhs);
+         gimplify_assign (vbool_lhs, rhs, post_p);
+       }
+    }
 
   /* Step 3: gimplify size expressions and the indices and operands of
      ARRAY_REF.  During this loop we also remove any useless conversions.
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops_bool.c 
b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops_bool.c
index 1f0b599cfbe..ecfa28f0fb4 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops_bool.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops_bool.c
@@ -46,8 +46,94 @@
       __builtin_abort (); \
   }
 
-#define VECT_CST { -1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1 }
-#define VECT_CSTN { -1, t (), 0, -1, 0, f (), 0, 0, 0, -1, 0, -1, 0, -1, 0, -1 
}
+#define DECL_FUNC_INDEX(n) \
+  BOOL  __attribute__((noipa)) \
+  func_vindex (svbool_t a, int idx) { \
+    return (a[idx]); \
+  } \
+  BOOL  __attribute__((noipa)) \
+  func_cindex (svbool_t a) { \
+    return (a[0]); \
+  } \
+  svbool_t  __attribute__((noipa)) \
+  func_index () { \
+    int i; \
+    svbool_t b; \
+    for (i = 0; i < svcntb (); i++) \
+      b[i] = 0; \
+    for (i = 0; i < svcntw (); i++) \
+      b[i * sizeof (int)] = -1;  \
+    return b; \
+  } \
+  svbool_t  __attribute__((noipa)) \
+  func_index_rw (svbool_t a, svbool_t b, svbool_t c, int i) { \
+    svbool_t t = a ^ c; \
+    a[i] = b[i] | c [i - 1]; \
+    t[6] = a[5] ^ b[i] & ~c[2]; \
+    return t & a | b ^ c; \
+  } \
+  void __attribute__((noipa)) \
+  checkfunc_cindex () { \
+    svbool_t pg = svptrue_b8 (); \
+    svbool_t data = svptrue_pat_b8 (SV_VL ## n); \
+    BOOL  actual = func_cindex (data); \
+    svint8_t tmp = svdup_s8_z (data, -1); \
+    BOOL  exp = tmp[0]; \
+    if (exp != actual) \
+      __builtin_abort (); \
+  } \
+  void __attribute__((noipa)) \
+  checkfunc_vindex () { \
+    svbool_t data = svptrue_pat_b8 (SV_VL ## n); \
+    BOOL  actual = func_vindex (data, n); \
+    svint8_t tmp = svdup_s8_z (data, -1); \
+    BOOL  exp = tmp[n]; \
+    if (exp != actual) \
+      __builtin_abort (); \
+  } \
+  void __attribute__((noipa)) \
+  checkfunc_index () { \
+    svbool_t exp = svptrue_b32 (); \
+    svbool_t actual = func_index (); \
+    svbool_t cmp = sveor_b_z (exp, exp, actual); \
+    int i; \
+    if (svptest_any (exp, cmp)) \
+      __builtin_abort (); \
+    for (i = 0; i < svcntb (); i++) \
+      { \
+       BOOL e = exp[i]; \
+       BOOL a = actual[i]; \
+        if (e != a) \
+         __builtin_abort (); \
+      } \
+    for (i = 0; i < svcntb (); i++) \
+      if (exp[i] != actual[i]) \
+       __builtin_abort (); \
+    for (i = 0; i < svcntb (); i++) \
+      if ((BOOL)exp[i] != (BOOL)actual[i]) \
+       __builtin_abort (); \
+    for (i = 0; i < svcntb (); i++) \
+      if (exp[i] ^ actual[i]) \
+       __builtin_abort (); \
+  } \
+  void __attribute__((noipa)) \
+  checkfunc_index_rw () { \
+    svbool_t all_true = svptrue_b8 (); \
+    svbool_t a = svptrue_pat_b8 (SV_VL4); \
+    svbool_t b = svptrue_pat_b8 (SV_VL8); \
+    svbool_t c = svptrue_pat_b8 (SV_VL16); \
+      \
+    svbool_t actual = func_index_rw (a, b, c, 15); \
+    svbool_t exp = { 0, 0, 0, 0, 0, 0, 0, 0, \
+                    -1, -1, -1, -1, -1, -1, -1, -1 }; /* { dg-warning 
{overflow in conversion from} } */\
+    svbool_t cmp = sveor_b_z (all_true, exp, actual); \
+      \
+    if (svptest_any (all_true, cmp)) \
+      __builtin_abort (); \
+  }
+
+#define VECT_CST { -1, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1 } 
/* { dg-warning {overflow in conversion from} } */
+#define VECT_CSTN { -1, t (), 0, -1, 0, f (), 0, 0, 0, -1, 0, -1, 0, -1, 0, -1 
} /* { dg-warning {overflow in conversion from} } */
 
 #define DECL_FUNC_INIT() \
   svbool_t __attribute__ ((noipa)) \
@@ -242,6 +328,8 @@ DECL_FUNC_BINARY (ne, !=, sveor_b_z, 4)
 
 DECL_FUNC_INIT ()
 
+DECL_FUNC_INDEX (4)
+
 #ifdef __cplusplus
 DECL_FUNC_UNARY_COND (lnot, !, 8)
 DECL_FUNC_BINARY_COND (and_and, &&, and, 8)
@@ -257,6 +345,13 @@ DECL_FUNC_BOOL_TERNARY (3)
 #define DECL_FUNC_UNARY_COND(name, op, n)  \
   checkfunc_ ## name ## _unary_cond ();
 
+#undef DECL_FUNC_INDEX
+#define DECL_FUNC_INDEX(idx) \
+  checkfunc_cindex (); \
+  checkfunc_vindex (); \
+  checkfunc_index ();  \
+  checkfunc_index_rw ();
+
 #undef DECL_FUNC_INIT
 #define DECL_FUNC_INIT() \
   checkfunc_init ();
@@ -284,6 +379,7 @@ main ()
   DECL_FUNC_BINARY (ne, !=, sveor_b_z, 4)
   DECL_FUNC_BINARY (eq, ==, my_svneor_b_z, 4)
 
+  DECL_FUNC_INDEX (10)
   DECL_FUNC_INIT ()
 
   checkfunc_svbool_t_bc ();
-- 
2.25.1

Reply via email to