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