Hi Tejas,
> -----Original Message-----
> From: Tejas Belagod <[email protected]>
> Sent: 06 October 2025 10:37
> To: [email protected]
> Cc: Tejas Belagod <[email protected]>; Tamar Christina
> <[email protected]>; [email protected]
> Subject: [PATCH v3 1/3] AArch64: Support C/C++ operations on svbool_t
>
> Support a subset of C/C++ operations (bitwise, conditional etc.) on svbool_t.
>
> gcc/ChangeLog:
>
> * c-family/c-common.cc (c_build_vec_convert): Support vector
> boolean
> types for __builtin_convertvector ().
> * c/c-typeck.cc (build_binary_op): Support vector boolean types.
> * cp/typeck.cc (cp_build_binary_op): Likewise.
> * config/aarch64/aarch64-sve-builtins.cc (register_builtin_types):
> Make
> SVE vector boolean type equivalent to GNU vectors.
> * config/aarch64/aarch64-sve.md (<optab>vnx16bivnx16qi2,
> truncvnx16qivnx16bi2, vec_cmp<mode><mode>): New patterns to
> support
> additional operations on predicate modes.
> * config/aarch64/aarch64.cc (aarch64_valid_vector_boolean_op):
> New.
> (aarch64_invalid_unary_op): Consider vector bool types.
> (aarch64_invalid_binary_op): Likewise.
> (aarch64_convert_to_type): Define target hook and handle standard
> to
> non-standard bool conversion.
> * cp/call.cc (build_conditional_expr): Support vector booleans.
> * cp/cvt.cc (ocp_convert): Call target hook to resolve conversion
> between standard and non-standard booleans.
>
> gcc/testsuite/ChangeLog:
>
> * gcc.target/aarch64/sve/acle/general/cops_bool.c: New.
> ---
> gcc/c-family/c-common.cc | 4 +-
> gcc/c/c-typeck.cc | 25 +-
> gcc/config/aarch64/aarch64-sve-builtins.cc | 5 +-
> gcc/config/aarch64/aarch64-sve.md | 62 ++++
> gcc/config/aarch64/aarch64.cc | 94 +++++-
> gcc/cp/call.cc | 3 +-
> gcc/cp/cvt.cc | 11 +-
> gcc/cp/typeck.cc | 26 +-
> .../aarch64/sve/acle/general/cops_bool.c | 301 ++++++++++++++++++
> 9 files changed, 497 insertions(+), 34 deletions(-)
> create mode 100644
> gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops_bool.c
>
> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
> index e7dd4602ac1..46787e57c3a 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -1311,6 +1311,7 @@ c_build_vec_convert (location_t loc1, tree expr,
> location_t loc2, tree type,
>
> if (!gnu_vector_type_p (TREE_TYPE (expr))
> || (!VECTOR_INTEGER_TYPE_P (TREE_TYPE (expr))
> + && !VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (expr))
> && !VECTOR_FLOAT_TYPE_P (TREE_TYPE (expr))))
> {
> if (complain)
> @@ -1320,7 +1321,8 @@ c_build_vec_convert (location_t loc1, tree expr,
> location_t loc2, tree type,
> }
>
> if (!gnu_vector_type_p (type)
> - || (!VECTOR_INTEGER_TYPE_P (type) && !VECTOR_FLOAT_TYPE_P
> (type)))
> + || (!VECTOR_INTEGER_TYPE_P (type) && !VECTOR_FLOAT_TYPE_P (type)
> + && !VECTOR_BOOLEAN_TYPE_P (type)))
> {
> if (complain)
> error_at (loc2, "%<__builtin_convertvector%> second argument must
> "
> diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> index 9b2aeea50f4..37e4c5a7778 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -14666,18 +14666,23 @@ build_binary_op (location_t location, enum
> tree_code code,
> }
>
> /* Always construct signed integer vector type. */
> - intt = c_common_type_for_size (GET_MODE_BITSIZE
> - (SCALAR_TYPE_MODE
> - (TREE_TYPE (type0))), 0);
> - if (!intt)
> + if (VECTOR_BOOLEAN_TYPE_P (type0) &&
> VECTOR_BOOLEAN_TYPE_P (type1))
> + result_type = type0;
> + else
> {
> - error_at (location, "could not find an integer type "
> - "of the same size as %qT",
> - TREE_TYPE (type0));
> - return error_mark_node;
> + intt = c_common_type_for_size (GET_MODE_BITSIZE
> + (SCALAR_TYPE_MODE
> + (TREE_TYPE (type0))), 0);
> + if (!intt)
> + {
> + error_at (location, "could not find an integer type "
> + "of the same size as %qT",
> + TREE_TYPE (type0));
> + return error_mark_node;
> + }
> + result_type = build_opaque_vector_type
> + (intt, TYPE_VECTOR_SUBPARTS (type0));
> }
> - result_type = build_opaque_vector_type (intt,
> - TYPE_VECTOR_SUBPARTS
> (type0));
> converted = 1;
> ret = build_vec_cmp (resultcode, result_type, op0, op1);
> goto return_build_binary_op;
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc
> b/gcc/config/aarch64/aarch64-sve-builtins.cc
> index 22d75197188..5ff4d7cc293 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
> @@ -4689,9 +4689,6 @@ register_builtin_types ()
> vectype = build_truth_vector_type_for_mode
> (BYTES_PER_SVE_VECTOR,
> VNx16BImode);
> num_pr = 1;
> - /* Leave svbool_t as indivisible for now. We don't yet support
> - C/C++ operators on predicates. */
> - TYPE_INDIVISIBLE_P (vectype) = 1;
> }
> else
> {
> @@ -4708,12 +4705,12 @@ register_builtin_types ()
> && TYPE_ALIGN (vectype) == 128
> && known_eq (size, BITS_PER_SVE_VECTOR));
> num_zr = 1;
> - TYPE_INDIVISIBLE_P (vectype) = 0;
> }
> vectype = build_distinct_type_copy (vectype);
> gcc_assert (vectype == TYPE_MAIN_VARIANT (vectype));
> SET_TYPE_STRUCTURAL_EQUALITY (vectype);
> TYPE_ARTIFICIAL (vectype) = 1;
> + TYPE_INDIVISIBLE_P (vectype) = 0;
> make_type_sizeless (vectype);
> }
> if (num_pr)
> diff --git a/gcc/config/aarch64/aarch64-sve.md
> b/gcc/config/aarch64/aarch64-sve.md
> index 8c47d441c3f..6c818f1e63e 100644
> --- a/gcc/config/aarch64/aarch64-sve.md
> +++ b/gcc/config/aarch64/aarch64-sve.md
> @@ -3519,6 +3519,41 @@
> }
> )
>
> +;; Unpredicated sign and zero extension from a boolean mode.
> +(define_expand "<optab>vnx16bivnx16qi2"
> + [(set (match_operand:VNx16QI 0 "register_operand")
> + (unspec:VNx16QI
> + [(match_operand:VNx16BI 1 "register_operand")
> + (ANY_EXTEND:VNx16QI
> + (match_dup 2))]
The RTL template is a bit weird, it's extending an unknown/unused
register? I guess because you were trying to follow the existing
extension patterns? Since you're replacing the entire pattern maybe just define
this declaratively so we never have an invalid rtl? E.g.
(define_expand "<optab>vnx16bivnx16qi2"
[(set (match_operand:SVE_ALL 0 "register_operand")
(unspec:SVE_ALL
[(match_operand:<VPRED> 1 "register_operand")
(match_dup 2)
(match_dup 3)]
UNSPEC_SEL))]
"TARGET_SVE"
{
operands[2] = CONSTM1_RTX (VNx16QImode);
operands[3] = CONST0_RTX (VNx16QImode);
}
)
> + UNSPEC_PRED_X))]
> + "TARGET_SVE"
> + {
> + emit_insn (gen_vcond_mask_vnx16qivnx16bi (operands[0],
> + CONSTM1_RTX (VNx16QImode),
> + CONST0_RTX (VNx16QImode),
> + operands[1]));
> + DONE;
> + }
> +)
> +
> +;; Unpredicated truncation from QImode to boolean mode.
> +(define_expand "truncvnx16qivnx16bi2"
> + [(set (match_operand:VNx16BI 0 "register_operand")
> + (unspec:VNx16BI
> + [(match_dup 2)
> + (truncate:VNx16BI
> + (match_operand:VNx16QI 1 "register_operand"))]
> + UNSPEC_PRED_X))]
> + "TARGET_SVE"
> + {
> + rtx one = CONSTM1_RTX (VNx16QImode);
> + rtx cmp = gen_rtx_EQ (VNx16QImode, operands[1], one);
> + emit_insn (gen_vec_cmpvnx16qivnx16bi (operands[0], cmp, operands[1],
> one));
> + DONE;
> + }
> +)
Same here, dummy 3rd operand is weird and unused.
> +
> ;; Predicated sign and zero extension from a narrower mode.
> (define_insn "*<optab><SVE_PARTIAL_I:mode><SVE_HSDI:mode>2"
> [(set (match_operand:SVE_HSDI 0 "register_operand")
> @@ -8511,6 +8546,33 @@
> }
> )
>
> +(define_expand "vec_cmp<mode><mode>"
> + [(parallel
> + [(set (match_operand:PRED_ALL 0 "register_operand")
> + (match_operator:PRED_ALL 1 "aarch64_equality_operator"
> + [(match_operand:PRED_ALL 2 "register_operand")
> + (match_operand:PRED_ALL 3 "register_operand")]))])]
> + "TARGET_SVE"
> + {
> + rtx ptrue = aarch64_ptrue_reg (<MODE>mode);
> + if (GET_CODE (operands[1]) == EQ)
> + {
> + rtx tmp = gen_reg_rtx (<MODE>mode);
> + emit_insn (gen_aarch64_pred_xor<mode>_z (tmp, ptrue,
> + operands[2], operands[3]));
> + emit_insn (gen_aarch64_pred_xor<mode>_z (operands[0], ptrue,
> + tmp, ptrue));
> + }
> + else if (GET_CODE (operands[1]) == NE)
> + emit_insn (gen_aarch64_pred_xor<mode>_z (operands[0], ptrue,
> + operands[2], operands[3]));
> + else
> + gcc_unreachable ();
> +
> + DONE;
> + }
> +)
I think we'll want an RTL pattern to flip EQ to NE in comparisons, though it's
nicer if we can do this during expand? (We have similar logic for expansion of
cbranch which deals with Boolean expansions).
For instance
svbool_t g (svbool_t p, svbool_t q, svbool_t a, svbool_t b,
svbool_t c, svbool_t d)
{
return (p == q) ? a : b;
}
Generates the two XORs but it's a conditional so we can invert the comparison
and the results into
svbool_t g (svbool_t p, svbool_t q, svbool_t a, svbool_t b,
svbool_t c, svbool_t d)
{
return (p != q) ? b : a;
}
Which will give us much better code.
The middle-end/expand would be best here since they can be nested, like
svbool_t f (svbool_t p, svbool_t q, svbool_t a, svbool_t b,
svbool_t c, svbool_t d)
{
return (p == q) ? (a == b ? c : d) : b;
}
And the nesting may be difficult to handle.
> +
> ;; Unsigned integer comparisons. Don't enforce an immediate range here,
> since
> ;; it depends on the comparison; leave it to
> aarch64_expand_sve_vec_cmp_int
> ;; instead.
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 031da863860..1012aa1e59a 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -23037,6 +23037,24 @@ aarch64_autovectorize_vector_modes
> (vector_modes *modes, bool)
> return flags;
> }
>
> +/* Implement TARGET_CONVERT_TO_TYPE. Convert EXPR to TYPE. */
> +
> +static tree
> +aarch64_convert_to_type (tree type, tree expr)
> +{
> + /* If TYPE is a non-standard boolean type invented by the target, check if
> + EXPR can be converted to TYPE. */
> + if (TREE_CODE (type) == BOOLEAN_TYPE
> + && TREE_CODE (TREE_TYPE (expr)) == BOOLEAN_TYPE
> + && !VECTOR_TYPE_P (type)
> + && !VECTOR_TYPE_P (TREE_TYPE (expr))
> + && TYPE_CANONICAL (type) != TYPE_CANONICAL (TREE_TYPE (expr)))
> + return build1 (VIEW_CONVERT_EXPR, type, expr);
> +
> + /* Use standard rules. */
> + return NULL_TREE;
> +}
> +
> /* Implement TARGET_MANGLE_TYPE. */
>
> static const char *
> @@ -30330,11 +30348,59 @@ aarch64_stack_protect_guard (void)
> return NULL_TREE;
> }
>
> -/* Implement TARGET_INVALID_UNARY_OP. */
> +
> +static const char *
> +aarch64_valid_vector_boolean_op (int code)
> +{
> + switch ((enum tree_code)code)
> + {
> + case PREINCREMENT_EXPR:
> + return N_ ("preincrement operation not permitted on svbool_t");
> + case PREDECREMENT_EXPR:
> + return N_ ("predecrement operation not permitted on svbool_t");
> + case POSTINCREMENT_EXPR:
> + return N_ ("postincrement operation not permitted on svbool_t");
> + case POSTDECREMENT_EXPR:
> + return N_ ("postdecrement operation not permitted on svbool_t");
> + case NEGATE_EXPR:
> + return N_ ("negation operation not permitted on svbool_t");
> + case PLUS_EXPR:
> + return N_ ("plus operation not permitted on svbool_t");
> + case MINUS_EXPR:
> + return N_ ("minus operation not permitted on svbool_t");
> + case MULT_EXPR:
> + return N_ ("multiply operation not permitted on svbool_t");
> + case TRUNC_DIV_EXPR:
> + return N_ ("divide operation not permitted on svbool_t");
> + case LSHIFT_EXPR:
> + case RSHIFT_EXPR:
> + return N_ ("shift operation not permitted on svbool_t");
> + case LT_EXPR:
> + case LE_EXPR:
> + 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;
> + }
> +}
> +
> +/* Implement TARGET_INVALID_BINARY_OP.
> + Return the diagnostic message string if the unary operation OP is
> + not permitted on TYPE, NULL otherwise. */
>
> static const char *
> aarch64_invalid_unary_op (int op, const_tree type)
> {
> + if (VECTOR_TYPE_P (type)
VECTOR_BOOLEAN_TYPE_P below already implies VECTOR_TYPE so it can be dropped.
The patch is looking good!
Thanks,
Tamar
> + && !TYPE_INDIVISIBLE_P (type)
> + && VECTOR_BOOLEAN_TYPE_P (type)
> + && aarch64_sve::builtin_type_p (type))
> + return aarch64_valid_vector_boolean_op (op);
> +
> /* Reject all single-operand operations on __mfp8 except for &. */
> if (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node && op !=
> ADDR_EXPR)
> return N_ ("operation not permitted on type %<mfloat8_t%>");
> @@ -30343,19 +30409,29 @@ aarch64_invalid_unary_op (int op, const_tree
> type)
> return NULL;
> }
>
> -/* Implement TARGET_INVALID_BINARY_OP. */
> +/* Implement TARGET_INVALID_BINARY_OP.
> + Return the diagnostic message string if the binary operation OP is
> + not permitted on TYPE1 and TYPE2, NULL otherwise. */
>
> static const char *
> -aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
> +aarch64_invalid_binary_op (int op, const_tree type1,
> const_tree type2)
> {
> if (VECTOR_TYPE_P (type1)
> && VECTOR_TYPE_P (type2)
> && !TYPE_INDIVISIBLE_P (type1)
> - && !TYPE_INDIVISIBLE_P (type2)
> - && (aarch64_sve::builtin_type_p (type1)
> + && !TYPE_INDIVISIBLE_P (type2))
> + {
> + if ((aarch64_sve::builtin_type_p (type1)
> != aarch64_sve::builtin_type_p (type2)))
> - return N_("cannot combine GNU and SVE vectors in a binary operation");
> + return N_("cannot combine GNU and SVE vectors in a binary
> operation");
> +
> + if (aarch64_sve::builtin_type_p (type1)
> + && aarch64_sve::builtin_type_p (type2)
> + && VECTOR_BOOLEAN_TYPE_P (type1)
> + && VECTOR_BOOLEAN_TYPE_P (type2))
> + return aarch64_valid_vector_boolean_op (op);
> + }
>
> /* Reject all 2-operand operations on __mfp8. */
> if (TYPE_MAIN_VARIANT (type1) == aarch64_mfp8_type_node
> @@ -32438,6 +32514,9 @@ aarch64_libgcc_floating_mode_supported_p
> #undef TARGET_INVALID_BINARY_OP
> #define TARGET_INVALID_BINARY_OP aarch64_invalid_binary_op
>
> +#undef TARGET_INVALID_UNARY_OP
> +#define TARGET_INVALID_UNARY_OP aarch64_invalid_unary_op
> +
> #undef TARGET_VERIFY_TYPE_CONTEXT
> #define TARGET_VERIFY_TYPE_CONTEXT aarch64_verify_type_context
>
> @@ -32628,6 +32707,9 @@ aarch64_libgcc_floating_mode_supported_p
> #define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_MODES \
> aarch64_autovectorize_vector_modes
>
> +#undef TARGET_CONVERT_TO_TYPE
> +#define TARGET_CONVERT_TO_TYPE aarch64_convert_to_type
> +
> #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
> #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV \
> aarch64_atomic_assign_expand_fenv
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 97c8a48c840..a186f81ef78 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -5902,7 +5902,8 @@ build_conditional_expr (const op_location_t &loc,
> orig_arg3 = arg3;
>
> if (gnu_vector_type_p (TREE_TYPE (arg1))
> - && VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg1)))
> + && (VECTOR_INTEGER_TYPE_P (TREE_TYPE (arg1))
> + || VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (arg1))))
> {
> tree arg1_type = TREE_TYPE (arg1);
>
> diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
> index 55be12db951..b5c2e07c6f8 100644
> --- a/gcc/cp/cvt.cc
> +++ b/gcc/cp/cvt.cc
> @@ -885,15 +885,22 @@ ocp_convert (tree type, tree expr, int convtype, int
> flags,
> if (SCOPED_ENUM_P (intype) && (convtype & CONV_STATIC))
> e = build_nop (ENUM_UNDERLYING_TYPE (intype), e);
> if (complain & tf_warning)
> - return cp_truthvalue_conversion (e, complain);
> + e = cp_truthvalue_conversion (e, complain);
> else
> {
> /* Prevent bogus -Wint-in-bool-context warnings coming
> from c_common_truthvalue_conversion down the line. */
> warning_sentinel w (warn_int_in_bool_context);
> warning_sentinel c (warn_sign_compare);
> - return cp_truthvalue_conversion (e, complain);
> + e = cp_truthvalue_conversion (e, complain);
> }
> +
> + /* Sometimes boolean types don't match if a non-standard boolean
> + type has been invented by the target. */
> + tree e2 = targetm.convert_to_type (type, e);
> + if (e2)
> + return e2;
> + return e;
> }
>
> converted = convert_to_integer_maybe_fold (type, e, dofold);
> diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
> index b876409d847..93de6bf3df9 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -6269,18 +6269,24 @@ cp_build_binary_op (const op_location_t
> &location,
> return error_mark_node;
> }
>
> - /* Always construct signed integer vector type. */
> - intt = c_common_type_for_size
> - (GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE (type0))),
> 0);
> - if (!intt)
> + if (VECTOR_BOOLEAN_TYPE_P (type0) &&
> VECTOR_BOOLEAN_TYPE_P (type1))
> + result_type = type0;
> + else
> {
> - if (complain & tf_error)
> - error_at (location, "could not find an integer type "
> - "of the same size as %qT", TREE_TYPE (type0));
> - return error_mark_node;
> + /* Always construct signed integer vector type. */
> + intt = c_common_type_for_size
> + (GET_MODE_BITSIZE (SCALAR_TYPE_MODE (TREE_TYPE
> (type0)))
> + , 0);
> + if (!intt)
> + {
> + if (complain & tf_error)
> + error_at (location, "could not find an integer type "
> + "of the same size as %qT", TREE_TYPE
> (type0));
> + return error_mark_node;
> + }
> + result_type = build_opaque_vector_type
> + (intt, TYPE_VECTOR_SUBPARTS (type0));
> }
> - result_type = build_opaque_vector_type (intt,
> - TYPE_VECTOR_SUBPARTS
> (type0));
> return build_vec_cmp (resultcode, result_type, op0, op1);
> }
> build_type = boolean_type_node;
> 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
> new file mode 100644
> index 00000000000..53017ca9fa2
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops_bool.c
> @@ -0,0 +1,301 @@
> +/* { dg-do run { target aarch64_sve_hw } } */
> +/* { dg-options "-O2" } */
> +
> +#include <arm_sve.h>
> +
> +#ifdef __cplusplus
> +#define BOOL bool
> +#else
> +#define BOOL _Bool
> +#endif
> +
> +#define DECL_FUNC_UNARY(name, op, intr, n) \
> + svbool_t __attribute__((noipa)) \
> + func_ ## name ## _unary (svbool_t a) { \
> + return op (a); \
> + } \
> + void __attribute__((noipa)) \
> + checkfunc_ ## name ## _unary () { \
> + svbool_t pg = svptrue_b8 (); \
> + svbool_t data = svptrue_pat_b8 (SV_VL ## n); \
> + svbool_t exp = intr (pg, data); \
> + svbool_t actual = func_ ## name ## _unary (data); \
> + svbool_t cmp = sveor_b_z (pg, exp, actual); \
> + if (svptest_any (pg, cmp)) \
> + __builtin_abort (); \
> + }
> +
> +#define DECL_FUNC_UNARY_COND(name, op, n) \
> + svbool_t __attribute__ ((noipa)) \
> + func_ ## name ## _unary_cond (svbool_t a) { \
> + return op (a); \
> + } \
> + svbool_t __attribute__ ((noipa)) \
> + name (svbool_t t, svbool_t a) { \
> + svbool_t pgl = sveor_b_z (t, a, svptrue_b8 ()); \
> + return pgl; \
> + } \
> + void __attribute__((noipa)) \
> + checkfunc_ ## name ## _unary_cond () { \
> + svbool_t a = svptrue_pat_b8 (SV_VL ## n); \
> + svbool_t all_true = svptrue_b8 (); \
> + svbool_t cmp = func_ ## name ## _unary_cond (a); \
> + svbool_t pgc = name (all_true, a) ; \
> + svbool_t res = sveor_b_z (all_true, cmp, pgc); \
> + if (svptest_any (all_true, res)) \
> + __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" "" { target c } } */
> +#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" "" { target c } } */
> + /* { dg-warning "narrowing conversion of" "" { target c++ } .-1 } */
> +
> +#define DECL_FUNC_INIT() \
> + svbool_t __attribute__ ((noipa)) \
> + func_init1 () { \
> + svbool_t temp = VECT_CST; \
> + return temp; \
> + } \
> + svbool_t __attribute__ ((noipa)) \
> + func_init2 () { \
> + svbool_t temp = { 0 }; \
> + return temp; \
> + } \
> + svbool_t __attribute__ ((noipa)) \
> + func_init3 () { \
> + svbool_t temp = { }; \
> + return temp; \
> + } \
> + int __attribute__ ((noipa)) \
> + t () { \
> + return -1; \
> + } \
> + int __attribute__ ((noipa)) \
> + f () { \
> + return 0; \
> + } \
> + svbool_t __attribute__ ((noipa)) \
> + func_init4 () { \
> + svbool_t temp = VECT_CSTN; \
> + return temp; \
> + } \
> + void __attribute__((noipa)) \
> + checkfunc_init() { \
> + svbool_t all_true = svptrue_b8 (); \
> + svbool_t v16_true = svptrue_pat_b8 (SV_VL16); \
> + int8_t mem[] = VECT_CST; \
> + int8_t memn[] = VECT_CSTN; \
> + svint8_t t8 = svld1_s8 (v16_true, mem); \
> + svbool_t init1 = __builtin_convertvector (t8, svbool_t); \
> + svbool_t init2 = __builtin_convertvector (svindex_s8 (0, 0), svbool_t); \
> + svbool_t init3 = __builtin_convertvector (svindex_s8 (0, 0), svbool_t); \
> + svint8_t tn8 = svld1_s8 (v16_true, memn); \
> + svbool_t init4 = __builtin_convertvector (tn8, svbool_t); \
> + \
> + svbool_t res_init1 = func_init1 (); \
> + svbool_t cmp = sveor_b_z (all_true, init1, res_init1); \
> + if (svptest_any (v16_true, cmp)) \
> + __builtin_abort (); \
> + \
> + svbool_t res_init2 = func_init2 (); \
> + cmp = sveor_b_z (all_true, init2, res_init2); \
> + if (svptest_any (v16_true, cmp)) \
> + __builtin_abort (); \
> + \
> + svbool_t res_init3 = func_init3 (); \
> + cmp = sveor_b_z (all_true, init3, res_init3); \
> + if (svptest_any (v16_true, cmp)) \
> + __builtin_abort (); \
> + \
> + svbool_t res_init4 = func_init4 (); \
> + cmp = sveor_b_z (all_true, init4, res_init4); \
> + if (svptest_any (v16_true, cmp)) \
> + __builtin_abort (); \
> + }
> +
> +#define DECL_FUNC_BINARY(name, op, intr, n) \
> + svbool_t __attribute__((noipa)) \
> + func_ ## name ## _binary(svbool_t a, svbool_t b) { \
> + return (a) op (b); \
> + } \
> + void __attribute__((noipa)) \
> + checkfunc_ ## name ## _binary () { \
> + svbool_t pg = svptrue_b8 (); \
> + svbool_t data1 = svptrue_pat_b8 (SV_VL ## n); \
> + svbool_t data2 = svnot_b_z (pg, data1); \
> + svbool_t exp = intr (pg, data1, data2); \
> + svbool_t actual = func_ ## name ## _binary (data1, data2); \
> + svbool_t cmp = sveor_b_z (pg, exp, actual); \
> + if (svptest_any (pg, cmp)) \
> + __builtin_abort (); \
> + }
> +
> +#define DECL_FUNC_BINARY_COND(name, op, intr, n) \
> + svbool_t __attribute__ ((noipa)) \
> + func_ ## name ## _binary_cond(svbool_t a, svbool_t b) { \
> + return (a) op (b); \
> + } \
> + svbool_t __attribute__ ((noipa)) \
> + name ## intr (svbool_t t, svbool_t a, svbool_t b) { \
> + return sv ## intr ## _b_z (t, a, b); \
> + } \
> + void __attribute__((noipa)) \
> + checkfunc_ ## name ## _binary_cond () { \
> + svbool_t all_true = svptrue_b8 (); \
> + svbool_t a = svptrue_pat_b8 (SV_VL ## n); \
> + svbool_t b = svnot_b_z (all_true, a); \
> + svbool_t cmp = func_ ## name ## _binary_cond (a, b); \
> + svbool_t pgc = name ## intr (all_true, a, b) ; \
> + svbool_t res = sveor_b_z (all_true, cmp, pgc); \
> + if (svptest_any (all_true, res)) \
> + __builtin_abort (); \
> + }
> +
> +#define DECL_FUNC_BOOL_TERNARY(n) \
> + svbool_t __attribute__((noipa)) \
> + func_svbool_t_ternary_eq(svbool_t p, svbool_t q, svbool_t a, svbool_t b) {
> \
> + return (p == q) ? a : b; \
> + } \
> + svbool_t __attribute__((noipa)) \
> + func_svbool_t_ternary_ne(svbool_t p, svbool_t q, svbool_t a, svbool_t b) {
> \
> + return (p != q) ? a : b; \
> + } \
> + svbool_t __attribute__((noipa)) \
> + func_svbool_t_ternary_ex(svbool_t p, svbool_t a, svbool_t b) { \
> + return (p) ? a : b; \
> + } \
> + void __attribute__((noipa)) \
> + checkfunc_svbool_t_ternary () { \
> + svbool_t pg = svptrue_b8 (); \
> + svbool_t p = svptrue_pat_b8 (SV_VL ## n); \
> + svbool_t q = svnot_b_z (pg, p); \
> + svbool_t a = p; \
> + svbool_t b = q; \
> + svbool_t ne = sveor_b_z (pg, p, q); \
> + svbool_t eq = svnot_b_z (pg, sveor_b_z (pg, p, q)); \
> + svbool_t ex = p; \
> + svbool_t expeq = svsel_b (eq, a, b); \
> + svbool_t expne = svsel_b (ne, a, b); \
> + svbool_t expex = svsel_b (ex, a, b); \
> + svbool_t actualeq = func_svbool_t_ternary_eq (p, q, a, b); \
> + svbool_t actualne = func_svbool_t_ternary_ne (p, q, a, b); \
> + svbool_t actualex = func_svbool_t_ternary_ex (p, a, b); \
> + svbool_t pgc_eq = sveor_b_z (pg, actualeq, expeq); \
> + svbool_t pgc_ne = sveor_b_z (pg, actualne, expne); \
> + svbool_t pgc_ex = sveor_b_z (pg, actualex, expex); \
> + if (svptest_any (pg, pgc_eq)) \
> + __builtin_abort (); \
> + if (svptest_any (pg, pgc_ne)) \
> + __builtin_abort (); \
> + if (svptest_any (pg, pgc_ex)) \
> + __builtin_abort (); \
> + }
> +
> +svbool_t __attribute__((noipa))
> +my_svneor_b_z (svbool_t pg, svbool_t a, svbool_t b)
> +{
> + return svnot_b_z (pg, sveor_b_z (pg, a, b));
> +}
> +
> +svbool_t __attribute__((noipa))
> +func_svbool_t_bc (svint8_t a)
> +{
> + return __builtin_convertvector (a, svbool_t);
> +}
> +
> +void __attribute__((noipa))
> +checkfunc_svbool_t_bc ()
> +{
> + svbool_t pg = svptrue_b8 ();
> + svint8_t data = { -1, -1, -1, -1 };
> + svbool_t actual = func_svbool_t_bc (data);
> + svbool_t exp = svptrue_pat_b8 (SV_VL4);
> + svbool_t cmp = sveor_b_z (pg, exp, actual);
> + if (svptest_any (pg, cmp))
> + __builtin_abort ();
> +}
> +
> +svint8_t __attribute__((noipa))
> +func_svint8_t_bc (svbool_t a)
> +{
> + return __builtin_convertvector (a, svint8_t);
> +}
> +
> +void __attribute__((noipa))
> +checkfunc_svint8_t_bc ()
> +{
> + svbool_t pg = svptrue_b8 ();
> + svbool_t data = svptrue_pat_b8 (SV_VL4);
> + svint8_t actual = func_svint8_t_bc (data);
> + svint8_t exp = { -1, -1, -1, -1 };
> + svbool_t cmp = svcmpne_s8 (pg, exp, actual);
> + if (svptest_any (pg, cmp))
> + __builtin_abort ();
> +}
> +
> +DECL_FUNC_UNARY (not, ~, svnot_b_z, 4)
> +DECL_FUNC_BINARY (and, &, svand_b_z, 8)
> +DECL_FUNC_BINARY (orr, |, svorr_b_z, 6)
> +DECL_FUNC_BINARY (eor, ^, sveor_b_z, 3)
> +
> +DECL_FUNC_BINARY (eq, ==, my_svneor_b_z, 4)
> +DECL_FUNC_BINARY (ne, !=, sveor_b_z, 4)
> +
> +DECL_FUNC_INIT ()
> +
> +#ifdef __cplusplus
> +DECL_FUNC_UNARY_COND (lnot, !, 8)
> +DECL_FUNC_BINARY_COND (and_and, &&, and, 8)
> +DECL_FUNC_BINARY_COND (or_or, ||, orr, 8)
> +DECL_FUNC_BOOL_TERNARY (3)
> +#endif
> +
> +#undef DECL_FUNC_UNARY
> +#define DECL_FUNC_UNARY(name, op, intr, n) \
> + checkfunc_ ## name ## _unary ();
> +
> +#undef DECL_FUNC_UNARY_COND
> +#define DECL_FUNC_UNARY_COND(name, op, n) \
> + checkfunc_ ## name ## _unary_cond ();
> +
> +#undef DECL_FUNC_INIT
> +#define DECL_FUNC_INIT() \
> + checkfunc_init ();
> +
> +#undef DECL_FUNC_BINARY
> +#define DECL_FUNC_BINARY(name, op, intr, n) \
> + checkfunc_ ## name ## _binary ();
> +
> +#undef DECL_FUNC_BINARY_COND
> +#define DECL_FUNC_BINARY_COND(name, op, intr, n) \
> + checkfunc_ ## name ## _binary_cond ();
> +
> +#undef DECL_FUNC_BOOL_TERNARY
> +#define DECL_FUNC_BOOL_TERNARY(n) \
> + checkfunc_svbool_t_ternary ();
> +
> +int
> +main ()
> +{
> + DECL_FUNC_UNARY (not, ~, svnot_b_z, 4)
> + DECL_FUNC_BINARY (and, &, svand_b_z, 8)
> + DECL_FUNC_BINARY (orr, |, svorr_b_z, 6)
> + DECL_FUNC_BINARY (eor, ^, sveor_b_z, 3)
> +
> + DECL_FUNC_BINARY (ne, !=, sveor_b_z, 4)
> + DECL_FUNC_BINARY (eq, ==, my_svneor_b_z, 4)
> +
> + DECL_FUNC_INIT ()
> +
> + checkfunc_svbool_t_bc ();
> + checkfunc_svint8_t_bc ();
> +
> +#ifdef __cplusplus
> + DECL_FUNC_UNARY_COND (lnot, !, 8)
> + DECL_FUNC_BINARY_COND (and_and, &&, and, 8)
> + DECL_FUNC_BINARY_COND (or_or, ||, orr, 8)
> + DECL_FUNC_BOOL_TERNARY (3)
> +#endif
> +
> + return 0;
> +}
> --
> 2.34.1