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;
+ }
+)
+
;; 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