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