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_common_bool_type): New. Given precision and signedness, return the appropriate common boolean type. * c-family/c-common.h (c_common_bool_type): Declare. * 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 binaries. gcc/testsuite/ChangeLog: * gcc.target/aarch64/sve/acle/general/cops_bool.c: New. --- gcc/c-family/c-common.cc | 25 +- gcc/c-family/c-common.h | 1 + gcc/c/c-typeck.cc | 28 +- 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 | 30 +- .../aarch64/sve/acle/general/cops_bool.c | 300 ++++++++++++++++++ 10 files changed, 525 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 0895c24ba97..76b54648c43 100644 --- a/gcc/c-family/c-common.cc +++ b/gcc/c-family/c-common.cc @@ -1309,6 +1309,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) @@ -1318,7 +1319,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 " @@ -2398,6 +2400,27 @@ c_common_type_for_size (unsigned int bits, int unsignedp) return NULL_TREE; } +tree +c_common_bool_type (unsigned int precision, bool unsigned_p) +{ + /* Standard boolean types. */ + if (precision == TYPE_PRECISION (boolean_type_node) + && unsigned_p == TYPE_UNSIGNED (boolean_type_node)) + return boolean_type_node; + + /* Non-standard boolean types created by targets. */ + for (tree t = registered_builtin_types; t; t = TREE_CHAIN (t)) + { + tree type = TREE_VALUE (t); + if (VECTOR_BOOLEAN_TYPE_P (type) + && precision == TYPE_PRECISION (TREE_TYPE (type)) + && unsigned_p == TYPE_UNSIGNED (type)) + return type; + } + + return NULL_TREE; +} + /* Return a fixed-point type that has at least IBIT ibits and FBIT fbits that is unsigned if UNSIGNEDP is nonzero, otherwise signed; and saturating if SATP is nonzero, otherwise not saturating. */ diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 0178a106343..a2e63cf2550 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -876,6 +876,7 @@ extern bool default_handle_c_option (size_t, const char *, int); extern tree c_common_type_for_mode (machine_mode, int); extern tree c_common_related_vtype_for_mode (machine_mode, scalar_mode, int); extern tree c_common_type_for_size (unsigned int, int); +extern tree c_common_bool_type (unsigned int, bool); extern tree c_common_fixed_point_type_for_size (unsigned int, unsigned int, int, int); extern tree c_common_unsigned_type (tree); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 691b583db3f..286fc6bcd02 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -14162,18 +14162,26 @@ 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)) { - error_at (location, "could not find an integer type " - "of the same size as %qT", - TREE_TYPE (type0)); - return error_mark_node; + result_type = c_common_bool_type (TYPE_PRECISION (TREE_TYPE (type0)), + TYPE_UNSIGNED (TREE_TYPE (type0))); + } + else + { + 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 5d2062726d6..640bc303f97 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -4674,9 +4674,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 { @@ -4693,12 +4690,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 a93bc463a90..c264b4b758c 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -3344,6 +3344,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))] + 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; + } +) + ;; 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") @@ -8128,6 +8163,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; + } +) + ;; 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 fe76730b0a7..0fa31608f2d 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -22576,6 +22576,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 * @@ -29584,11 +29602,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) + && !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%>"); @@ -29597,19 +29663,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 @@ -31551,6 +31627,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 @@ -31729,6 +31808,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 be9b0cf62f1..cddd45f97be 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -5841,7 +5841,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 bd1f147f2c5..86554cff4e3 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -872,15 +872,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 bbaca960bd7..083e577bab4 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -6201,18 +6201,28 @@ 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)) { - 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 = c_common_bool_type + (TYPE_PRECISION (TREE_TYPE (type0)), + TYPE_UNSIGNED (TREE_TYPE (type0))); + } + else + { + /* 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..1f0b599cfbe --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/cops_bool.c @@ -0,0 +1,300 @@ +/* { 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 } +#define VECT_CSTN { -1, t (), 0, -1, 0, f (), 0, 0, 0, -1, 0, -1, 0, -1, 0, -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 (all_true, cmp)) \ + __builtin_abort (); \ + \ + svbool_t res_init2 = func_init2 (); \ + cmp = sveor_b_z (all_true, init2, res_init2); \ + if (svptest_any (all_true, cmp)) \ + __builtin_abort (); \ + \ + svbool_t res_init3 = func_init3 (); \ + cmp = sveor_b_z (all_true, init3, res_init3); \ + if (svptest_any (all_true, cmp)) \ + __builtin_abort (); \ + \ + svbool_t res_init4 = func_init4 (); \ + cmp = sveor_b_z (all_true, init4, res_init4); \ + if (svptest_any (all_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.25.1