> -----Original Message-----
> From: Tejas Belagod <[email protected]>
> Sent: 04 November 2025 12:28
> To: [email protected]
> Cc: Tejas Belagod <[email protected]>; Tamar Christina
> <[email protected]>; [email protected]; [email protected]
> Subject: [PATCH v4 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 | 26 +-
> gcc/config/aarch64/aarch64-sve-builtins.cc | 5 +-
> gcc/config/aarch64/aarch64-sve.md | 68 ++++
> gcc/config/aarch64/aarch64.cc | 93 +++++-
> 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, 503 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 f2eed033706..1c382540b38 100644
> --- a/gcc/c-family/c-common.cc
> +++ b/gcc/c-family/c-common.cc
> @@ -1312,6 +1312,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)
> @@ -1321,7 +1322,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 2cef4636bd7..e1d2d1173dc 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -14693,18 +14693,24 @@ 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;
> + auto nelts = TYPE_VECTOR_SUBPARTS (type0);
> +
> + 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, nelts);
> }
> - 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 b2b03dc8cea..dbd80cab627 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
> @@ -4691,9 +4691,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
> {
> @@ -4710,12 +4707,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 f459f63d6bb..4648aa67e0c 100644
> --- a/gcc/config/aarch64/aarch64-sve.md
> +++ b/gcc/config/aarch64/aarch64-sve.md
> @@ -3520,6 +3520,47 @@
> }
> )
>
> +;; Unpredicated sign and zero extension from a boolean mode.
> +(define_expand "extend<vpred><mode>2"
> + [(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 (<MODE>mode);
> + operands[3] = CONST0_RTX (<MODE>mode);
> + }
> +)
> +
> +(define_expand "zero_extend<vpred><mode>2"
> + [(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] = CONST1_RTX (<MODE>mode);
> + operands[3] = CONST0_RTX (<MODE>mode);
> + }
> +)
> +
> +(define_expand "trunc<mode><vpred>2"
> + [(match_operand:<VPRED> 0 "register_operand")
> + (match_operand:SVE_I 1 "register_operand")]
> + "TARGET_SVE"
> + {
> + rtx mone = CONSTM1_RTX (<MODE>mode);
> + rtx cmp = gen_rtx_EQ (<MODE>mode, operands[1], mone);
> + emit_insn (gen_vec_cmp<mode><vpred> (operands[0], cmp, operands[1],
> mone));
> + DONE;
> + }
> +)
> +
> ;; 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")
> @@ -8528,6 +8569,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;
> + }
> +)
The else and the gcc_unreachable() aren't needed since the predicate
enforces this. But I don't mind it.
The AArch64 parts are OK.
Thanks,
Tamar
> +
> ;; 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 6f6dea67e0d..d9e428de7b8 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -23006,6 +23006,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 *
> @@ -30299,11 +30317,58 @@ 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_BOOLEAN_TYPE_P (type)
> + && !TYPE_INDIVISIBLE_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%>");
> @@ -30312,19 +30377,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
> @@ -32412,6 +32487,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
>
> @@ -32602,6 +32680,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 77dfa7d2982..f80d597b339 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..68d51b61375 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. */
> + if (tree e2 = targetm.convert_to_type (type, e))
> + 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 dbadeb77085..2ab45f3fff6 100644
> --- a/gcc/cp/typeck.cc
> +++ b/gcc/cp/typeck.cc
> @@ -6272,18 +6272,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. */
> + auto intmode = SCALAR_TYPE_MODE (TREE_TYPE (type0));
> + auto nelts = TYPE_VECTOR_SUBPARTS (type0);
> +
> + intt = c_common_type_for_size (GET_MODE_BITSIZE (intmode), 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, nelts);
> }
> - 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