I committed the following patch which implements svdot to aarch64/sve-acle-branch. branch
Thanks, Kugan
From b75cd8ba8f911c137380677b85882c22a6467bf6 Mon Sep 17 00:00:00 2001 From: Kugan Vivekanandarajah <kugan.vivekanandarajah@linaro.org> Date: Fri, 18 Jan 2019 09:07:10 +1100 Subject: [PATCH] [SVE ACLE] Implements svdot Change-Id: I9d9f77f814a62e03db2ccd749f41bd35fea16035 --- gcc/config/aarch64/aarch64-sve-builtins.c | 148 +++++++++++++++++++++ gcc/config/aarch64/aarch64-sve-builtins.def | 1 + gcc/config/aarch64/aarch64-sve.md | 14 ++ gcc/config/aarch64/iterators.md | 6 +- .../aarch64/sve-acle/general-c++/dot_1.C | 9 ++ .../aarch64/sve-acle/general-c++/dot_2.C | 17 +++ .../gcc.target/aarch64/sve-acle/asm/dot_s32.c | 111 ++++++++++++++++ .../gcc.target/aarch64/sve-acle/asm/dot_s64.c | 111 ++++++++++++++++ .../gcc.target/aarch64/sve-acle/asm/dot_u32.c | 111 ++++++++++++++++ .../gcc.target/aarch64/sve-acle/asm/dot_u64.c | 111 ++++++++++++++++ .../aarch64/sve-acle/asm/test_sve_acle.h | 48 +++++++ .../gcc.target/aarch64/sve-acle/general-c/dot_1.c | 13 ++ .../gcc.target/aarch64/sve-acle/general-c/dot_2.c | 15 +++ 13 files changed, 714 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C create mode 100644 gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c diff --git a/gcc/config/aarch64/aarch64-sve-builtins.c b/gcc/config/aarch64/aarch64-sve-builtins.c index 35ed531..f080a67 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.c +++ b/gcc/config/aarch64/aarch64-sve-builtins.c @@ -115,6 +115,10 @@ enum function_shape { sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0>_t, <t0>_t). */ SHAPE_ternary_opt_n, + /* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0.quarter>_t, sv<t0.quarter>_t) + sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0.quarter>_t, <t0.quarter>_t). */ + SHAPE_ternary_qq_opt_n, + /* sv<t0>_t svfoo[_n_t0])(sv<t0>_t, uint64_t) The final argument must be an integer constant expression in the @@ -161,6 +165,7 @@ enum function { FUNC_svasrd, FUNC_svdiv, FUNC_svdivr, + FUNC_svdot, FUNC_svdup, FUNC_sveor, FUNC_svindex, @@ -261,6 +266,8 @@ struct GTY(()) function_instance { tree scalar_type (unsigned int) const; tree vector_type (unsigned int) const; + tree quarter_vector_type (unsigned int i) const; + tree quarter_scalar_type (unsigned int i) const; /* The explicit "enum"s are required for gengtype. */ enum group_id group; @@ -321,7 +328,9 @@ private: void sig_000 (const function_instance &, vec<tree> &); void sig_n_000 (const function_instance &, vec<tree> &); void sig_0000 (const function_instance &, vec<tree> &); + void sig_qq_0000 (const function_instance &, vec<tree> &); void sig_n_0000 (const function_instance &, vec<tree> &); + void sig_qq_n_0000 (const function_instance &, vec<tree> &); void sig_n_00i (const function_instance &, vec<tree> &); void apply_predication (const function_instance &, vec<tree> &); @@ -361,6 +370,7 @@ public: private: tree resolve_uniform (unsigned int); + tree resolve_dot (); tree resolve_uniform_imm (unsigned int, unsigned int); bool check_first_vector_argument (unsigned int, unsigned int &, @@ -459,6 +469,7 @@ private: rtx expand_and (); rtx expand_asrd (); rtx expand_div (bool); + rtx expand_dot (); rtx expand_dup (); rtx expand_eor (); rtx expand_index (); @@ -618,6 +629,7 @@ DEF_SVE_TYPES_ARRAY (all_integer); DEF_SVE_TYPES_ARRAY (all_data); DEF_SVE_TYPES_ARRAY (all_sdi_and_float); DEF_SVE_TYPES_ARRAY (all_signed_and_float); +DEF_SVE_TYPES_ARRAY (sdi); /* Used by functions in aarch64-sve-builtins.def that have no governing predicate. */ @@ -668,6 +680,43 @@ find_vector_type (const_tree type) return NUM_VECTOR_TYPES; } +/* Return the type suffix associated with integer elements that have + ELEM_BITS bits and the signedness given by UNSIGNED_P. Return + NUM_TYPE_SUFFIXES if no such element exists. */ +static type_suffix +maybe_find_integer_type_suffix (bool unsigned_p, unsigned int elem_bits) +{ + for (unsigned int i = 0; i < NUM_TYPE_SUFFIXES; ++i) + { + if (type_suffixes[i].integer_p + && type_suffixes[i].unsigned_p == unsigned_p + && type_suffixes[i].elem_bits == elem_bits) + return type_suffix (i); + } + return NUM_TYPE_SUFFIXES; +} + +/* Return the type suffix for elements that are a quarter the size of integer + type suffix TYPE. Return NUM_TYPE_SUFFIXES if no such element exists. */ +static type_suffix +maybe_find_quarter_type_suffix (type_suffix type) +{ + return maybe_find_integer_type_suffix (type_suffixes[type].unsigned_p, + type_suffixes[type].elem_bits / 4); +} + +/* Same as maybe_find_quarter_type_suffix but asserts if no such element + exists. */ +static type_suffix +find_quarter_type_suffix (type_suffix type) +{ + type_suffix ret + = maybe_find_integer_type_suffix (type_suffixes[type].unsigned_p, + type_suffixes[type].elem_bits / 4); + gcc_assert (ret != NUM_TYPE_SUFFIXES); + return ret; +} + /* Report that LOCATION has a call to DECL in which argument ARGNO was not an integer constant expression. */ static void @@ -742,6 +791,22 @@ function_instance::vector_type (unsigned int i) const return acle_vector_types[type_suffixes[types[i]].type]; } +/* Return the quarter size vector type associated with type suffix I. */ +tree +function_instance::quarter_vector_type (unsigned int i) const +{ + type_suffix quarter_type = find_quarter_type_suffix (types[i]); + return acle_vector_types[type_suffixes[quarter_type].type]; +} + +/* Return the quarter size scalar type associated with type suffix I. */ +tree +function_instance::quarter_scalar_type (unsigned int i) const +{ + type_suffix quarter_type = find_quarter_type_suffix (types[i]); + return scalar_types[type_suffixes[quarter_type].type]; +} + inline hashval_t registered_function_hasher::hash (value_type value) { @@ -811,6 +876,12 @@ arm_sve_h_builder::build (const function_group &group) build_all (&arm_sve_h_builder::sig_n_0000, group, MODE_n); break; + case SHAPE_ternary_qq_opt_n: + add_overloaded_functions (group, MODE_none); + build_all (&arm_sve_h_builder::sig_qq_0000, group, MODE_none); + build_all (&arm_sve_h_builder::sig_qq_n_0000, group, MODE_n); + break; + case SHAPE_inherent: /* No overloaded functions here. */ build_all (&arm_sve_h_builder::sig_inherent, group, MODE_none); @@ -908,6 +979,20 @@ arm_sve_h_builder::sig_0000 (const function_instance &instance, types.quick_push (instance.vector_type (0)); } +/* Describe the signature + "sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0.quarter>_t, sv<t0.quarter>_t)" + for INSTANCE in TYPES. */ +void +arm_sve_h_builder::sig_qq_0000 (const function_instance &instance, + vec<tree> &types) +{ + tree quarter_type = instance.quarter_vector_type (0); + types.quick_push (instance.vector_type (0)); + types.quick_push (instance.vector_type (0)); + types.quick_push (quarter_type); + types.quick_push (quarter_type); +} + /* Describe the signature "sv<t0>_t svfoo[_n_t0](sv<t0>_t, <t0>_t)" for INSTANCE in TYPES. */ void @@ -930,6 +1015,19 @@ arm_sve_h_builder::sig_n_0000 (const function_instance &instance, types.quick_push (instance.scalar_type (0)); } +/* Describe the signature + "sv<t0>_t svfoo[_n_t0](sv<t0>_t, sv<t0.quarter>_t, <t0.quarter>_t)" + for INSTANCE in TYPES. */ +void +arm_sve_h_builder::sig_qq_n_0000 (const function_instance &instance, + vec<tree> &types) +{ + for (unsigned int i = 0; i < 2; ++i) + types.quick_push (instance.vector_type (0)); + types.quick_push (instance.quarter_vector_type (0)); + types.quick_push (instance.quarter_scalar_type (0)); +} + /* Describe the signature "sv<t0>_t svfoo[_n_t0](sv<t0>_t, uint64_t)" for INSTANCE in TYPES. */ void @@ -1088,6 +1186,7 @@ arm_sve_h_builder::get_attributes (const function_instance &instance) case FUNC_svasrd: case FUNC_svdiv: case FUNC_svdivr: + case FUNC_svdot: case FUNC_svdup: case FUNC_sveor: case FUNC_svindex: @@ -1145,6 +1244,7 @@ arm_sve_h_builder::get_explicit_types (function_shape shape) case SHAPE_unary: case SHAPE_binary_opt_n: case SHAPE_ternary_opt_n: + case SHAPE_ternary_qq_opt_n: case SHAPE_shift_right_imm: return 0; } @@ -1218,6 +1318,8 @@ function_resolver::resolve () return resolve_uniform (3); case SHAPE_shift_right_imm: return resolve_uniform_imm (2, 1); + case SHAPE_ternary_qq_opt_n: + return resolve_dot (); case SHAPE_unary_n: return NULL_TREE; case SHAPE_binary_scalar: @@ -1252,6 +1354,37 @@ function_resolver::resolve_uniform (unsigned int nops) return require_form (m_rfn.instance.mode, get_type_suffix (type)); } +/* Resolve functions like svdot in which the elements of the result and + the first argument are four times wider than the elements of the other + arguments. The final argument can be a vector or a scalar. */ +tree +function_resolver::resolve_dot () +{ + /* Check that we have the right number of arguments. */ + unsigned int i, nargs; + vector_type type; + + if (!check_first_vector_argument (3, i, nargs, type)) + return error_mark_node; + + /* Handle subsequent arguments. */ + type_suffix ts = maybe_find_quarter_type_suffix (get_type_suffix (type)); + if (ts != NUM_TYPE_SUFFIXES) + { + vector_type arg_type = type_suffixes[ts].type; + if (!check_argument (1, arg_type)) + return error_mark_node; + + /* Allow the final argument to be scalar, if an _n form exists. */ + if (scalar_argument_p (2)) + return require_n_form (get_type_suffix (type)); + else if (!check_argument (2, arg_type)) + return error_mark_node; + } + + return require_form (m_rfn.instance.mode, get_type_suffix (type)); +} + /* Like resolve_uniform, except that the final NIMM arguments have type uint64_t and must be integer constant expressions. */ tree @@ -1519,6 +1652,7 @@ function_checker::check () case SHAPE_binary_opt_n: case SHAPE_binary_scalar: case SHAPE_ternary_opt_n: + case SHAPE_ternary_qq_opt_n: return true; } gcc_unreachable (); @@ -1704,6 +1838,7 @@ gimple_folder::fold () case FUNC_svasrd: case FUNC_svdiv: case FUNC_svdivr: + case FUNC_svdot: case FUNC_svdup: case FUNC_sveor: case FUNC_svindex: @@ -1800,6 +1935,9 @@ function_expander::expand () case FUNC_svdivr: return expand_div (true); + case FUNC_svdot: + return expand_dot (); + case FUNC_svdup: return expand_dup (); @@ -1930,6 +2068,16 @@ function_expander::expand_div (bool reversed_p) return expand_signed_pred_op (DIV, UDIV, UNSPEC_COND_DIV, merge_argno); } +/* Expand a call to svdot. */ +rtx +function_expander::expand_dot () +{ + if (type_suffixes[m_fi.types[0]].unsigned_p) + return expand_via_unpred_direct_optab (udot_prod_optab); + else + return expand_via_unpred_direct_optab (sdot_prod_optab); +} + /* Expand a call to svdup. */ rtx function_expander::expand_dup () diff --git a/gcc/config/aarch64/aarch64-sve-builtins.def b/gcc/config/aarch64/aarch64-sve-builtins.def index b855e95..0977d4a 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.def +++ b/gcc/config/aarch64/aarch64-sve-builtins.def @@ -67,6 +67,7 @@ DEF_SVE_FUNCTION (svand, binary_opt_n, all_integer, mxz) DEF_SVE_FUNCTION (svasrd, shift_right_imm, all_signed, mxz) DEF_SVE_FUNCTION (svdiv, binary_opt_n, all_sdi_and_float, mxz) DEF_SVE_FUNCTION (svdivr, binary_opt_n, all_sdi_and_float, mxz) +DEF_SVE_FUNCTION (svdot, ternary_qq_opt_n, sdi, none) DEF_SVE_FUNCTION (svdup, unary_n, all_data, mxznone) DEF_SVE_FUNCTION (sveor, binary_opt_n, all_integer, mxz) DEF_SVE_FUNCTION (svindex, binary_scalar, all_data, none) diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 42a77dd..cbf9a7f 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -3839,3 +3839,17 @@ insr\t%0.<Vetype>, %<vwcore>2 insr\t%0.<Vetype>, %<Vetype>2" ) + +;; Unpredicated DOT product. +(define_insn "<sur>dot_prod<mode>" + [(set (match_operand:SVE_SDI 0 "register_operand" "=w, ?&w") + (plus:SVE_SDI (unspec:SVE_SDI [(match_operand:<VSI2QI> 2 "register_operand" "w, w") + (match_operand:<VSI2QI> 3 "register_operand" "w, w")] + DOTPROD) + (match_operand:SVE_SDI 1 "register_operand" "0, w")))] + "TARGET_SVE" + "@ + <sur>dot\\t%0.<Vetype>, %2.<Vetype_fourth>, %3.<Vetype_fourth> + movprfx\t%0, %1\;<sur>dot\\t%0.<Vetype>, %2.<Vetype_fourth>, %3.<Vetype_fourth>" + [(set_attr "movprfx" "*,yes")] +) diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index fe1a92f..14d6811 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -662,6 +662,9 @@ (QI "b") (HI "h") (SI "s") (DI "d")]) +;; Mode to one fourth individual element type mapping used in instruction DOT. +(define_mode_attr Vetype_fourth [(VNx4SI "b") (VNx2DI "h")]) + ;; Equivalent of "size" for a vector element. (define_mode_attr Vesize [(VNx16QI "b") (VNx8HI "h") (VNx8HF "h") @@ -1029,7 +1032,8 @@ (V4HF "v") (V8HF "v")]) (define_mode_attr vsi2qi [(V2SI "v8qi") (V4SI "v16qi")]) -(define_mode_attr VSI2QI [(V2SI "V8QI") (V4SI "V16QI")]) +(define_mode_attr VSI2QI [(V2SI "V8QI") (V4SI "V16QI") + (VNx4SI "VNx16QI") (VNx2DI "VNx8HI")]) ;; Register suffix for DOTPROD input types from the return type. diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C new file mode 100644 index 0000000..309c930 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_1.C @@ -0,0 +1,9 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-message "initializing argument 2" } */ + +svuint32_t +f1 (svuint32_t x, svint8_t y, svuint8_t z) +{ + return svdot_u32 (x, y, z); /* { dg-error "cannot convert 'svint8_t' to 'svuint8_t'" } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C new file mode 100644 index 0000000..984b45f --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/dot_2.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" +/* { dg-message {note: candidate: 'svuint32_t svdot\(svuint32_t, svuint8_t, svuint8_t\)'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *candidate expects 3 arguments, 2 provided} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 2 from 'svuint32_t' to 'svuint8_t'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 1 from 'int' to 'svuint32_t'} "" { target *-*-* } 3 } */ +/* { dg-message {note: *no known conversion for argument 2 from 'svint8_t' to 'svuint8_t'} "" { target *-*-* } 3 } */ + +void +f1 (svuint32_t x, svint8_t y, svuint8_t z) +{ + svdot (x, y); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svint8_t&\)'} } */ + svdot (x, x, x); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svuint32_t&, svuint32_t&\)'} } */ + svdot (1, z, z); /* { dg-error {no matching function for call to 'svdot\(int, svuint8_t&, svuint8_t&\)'} } */ + svdot (x, y, z); /* { dg-error {no matching function for call to 'svdot\(svuint32_t&, svint8_t&, svuint8_t&\)'} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c new file mode 100644 index 0000000..599a926 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s32.c @@ -0,0 +1,111 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** dot_s32_tied1: +** sdot z0\.s, z16\.b, z17\.b +** ret +*/ +TEST_DUAL_Z (dot_s32_tied1, svint32_t, svint8_t, + z0 = svdot_s32 (z0, z16, z17), + z0 = svdot (z0, z16, z17)) + +/* +** dot_s32_tied2: +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** sdot z16\.s, \1\.b, z17\.b +** ret +*/ +TEST_DUAL_Z (dot_s32_tied2, svint32_t, svint8_t, + z16_res = svdot_s32 (z0, z16, z17), + z16_res = svdot (z0, z16, z17)) + +/* +** dot_s32_tied3: +** mov (z[0-9]+)\.d, z17\.d +** movprfx z17, z0 +** sdot z17\.s, z16\.b, \1\.b +** ret +*/ +TEST_DUAL_Z (dot_s32_tied3, svint32_t, svint8_t, + z17_res = svdot_s32 (z0, z16, z17), + z17_res = svdot (z0, z16, z17)) + +/* +** dot_s32_untied: +** movprfx z0, z1 +** sdot z0\.s, z16\.b, z17\.b +** ret +*/ +TEST_DUAL_Z (dot_s32_untied, svint32_t, svint8_t, + z0 = svdot_s32 (z1, z16, z17), + z0 = svdot (z1, z16, z17)) + +/* +** dot_w0_s32_tied1: +** mov (z[0-9]+\.b), w0 +** sdot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_s32_tied1, svint32_t, svint8_t, int8_t, + z0 = svdot_n_s32 (z0, z16, x0), + z0 = svdot (z0, z16, x0)) + +/* +** dot_w0_s32_tied2: +** mov (z[0-9]+\.b), w0 +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** sdot z16\.s, \2\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_s32_tied2, svint32_t, svint8_t, int8_t, + z16_res = svdot_n_s32 (z0, z16, x0), + z16_res = svdot (z0, z16, x0)) + +/* +** dot_w0_s32_untied: +** mov (z[0-9]+\.b), w0 +** movprfx z0, z1 +** sdot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_s32_untied, svint32_t, svint8_t, int8_t, + z0 = svdot_n_s32 (z1, z16, x0), + z0 = svdot (z1, z16, x0)) + +/* +** dot_b0_s32_untied: +** mov (z[0-9]+\.b), b0 +** movprfx z1, z0 +** sdot z1\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_b0_s32_untied, svint32_t, svint8_t, int8_t, + z1 = svdot_n_s32 (z0, z16, d0), + z1 = svdot (z0, z16, d0)) + +/* +** dot_2_s32_untied: +** mov (z[0-9]+\.b), #2 +** movprfx z0, z1 +** sdot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_Z (dot_2_s32_untied, svint32_t, svint8_t, + z0 = svdot_n_s32 (z1, z16, 2), + z0 = svdot (z1, z16, 2)) + +/* +** dot_m1_s32: +** mov (z[0-9]+\.b), #-1 +** sdot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_Z (dot_m1_s32, svint32_t, svint8_t, + z0 = svdot_n_s32 (z0, z16, -1), + z0 = svdot (z0, z16, -1)) + diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c new file mode 100644 index 0000000..4bcdde9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_s64.c @@ -0,0 +1,111 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** dot_s64_tied1: +** sdot z0\.d, z16\.h, z17\.h +** ret +*/ +TEST_DUAL_Z (dot_s64_tied1, svint64_t, svint16_t, + z0 = svdot_s64 (z0, z16, z17), + z0 = svdot (z0, z16, z17)) + +/* +** dot_s64_tied2: +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** sdot z16\.d, \1\.h, z17\.h +** ret +*/ +TEST_DUAL_Z (dot_s64_tied2, svint64_t, svint16_t, + z16_res = svdot_s64 (z0, z16, z17), + z16_res = svdot (z0, z16, z17)) + +/* +** dot_s64_tied3: +** mov (z[0-9]+)\.d, z17\.d +** movprfx z17, z0 +** sdot z17\.d, z16\.h, \1\.h +** ret +*/ +TEST_DUAL_Z (dot_s64_tied3, svint64_t, svint16_t, + z17_res = svdot_s64 (z0, z16, z17), + z17_res = svdot (z0, z16, z17)) + +/* +** dot_s64_untied: +** movprfx z0, z1 +** sdot z0\.d, z16\.h, z17\.h +** ret +*/ +TEST_DUAL_Z (dot_s64_untied, svint64_t, svint16_t, + z0 = svdot_s64 (z1, z16, z17), + z0 = svdot (z1, z16, z17)) + +/* +** dot_w0_s64_tied1: +** mov (z[0-9]+\.h), w0 +** sdot z0\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_s64_tied1, svint64_t, svint16_t, int16_t, + z0 = svdot_n_s64 (z0, z16, x0), + z0 = svdot (z0, z16, x0)) + +/* +** dot_w0_s64_tied2: +** mov (z[0-9]+\.h), w0 +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** sdot z16\.d, \2\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_s64_tied2, svint64_t, svint16_t, int16_t, + z16_res = svdot_n_s64 (z0, z16, x0), + z16_res = svdot (z0, z16, x0)) + +/* +** dot_w0_s64_untied: +** mov (z[0-9]+\.h), w0 +** movprfx z0, z1 +** sdot z0\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_s64_untied, svint64_t, svint16_t, int16_t, + z0 = svdot_n_s64 (z1, z16, x0), + z0 = svdot (z1, z16, x0)) + +/* +** dot_h0_s64_untied: +** mov (z[0-9]+\.h), h0 +** movprfx z1, z0 +** sdot z1\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_h0_s64_untied, svint64_t, svint16_t, int16_t, + z1 = svdot_n_s64 (z0, z16, d0), + z1 = svdot (z0, z16, d0)) + +/* +** dot_2_s64_untied: +** mov (z[0-9]+\.h), #2 +** movprfx z0, z1 +** sdot z0\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_Z (dot_2_s64_untied, svint64_t, svint16_t, + z0 = svdot_n_s64 (z1, z16, 2), + z0 = svdot (z1, z16, 2)) + +/* +** dot_m1_s64: +** mov (z[0-9]+)\.b, #-1 +** sdot z0\.d, z16\.h, \1\.h +** ret +*/ +TEST_DUAL_Z (dot_m1_s64, svint64_t, svint16_t, + z0 = svdot_n_s64 (z0, z16, -1), + z0 = svdot (z0, z16, -1)) + diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c new file mode 100644 index 0000000..831b49d --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u32.c @@ -0,0 +1,111 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** dot_u32_tied1: +** udot z0\.s, z16\.b, z17\.b +** ret +*/ +TEST_DUAL_Z (dot_u32_tied1, svuint32_t, svuint8_t, + z0 = svdot_u32 (z0, z16, z17), + z0 = svdot (z0, z16, z17)) + +/* +** dot_u32_tied2: +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** udot z16\.s, \1\.b, z17\.b +** ret +*/ +TEST_DUAL_Z (dot_u32_tied2, svuint32_t, svuint8_t, + z16_res = svdot_u32 (z0, z16, z17), + z16_res = svdot (z0, z16, z17)) + +/* +** dot_u32_tied3: +** mov (z[0-9]+)\.d, z17\.d +** movprfx z17, z0 +** udot z17\.s, z16\.b, \1\.b +** ret +*/ +TEST_DUAL_Z (dot_u32_tied3, svuint32_t, svuint8_t, + z17_res = svdot_u32 (z0, z16, z17), + z17_res = svdot (z0, z16, z17)) + +/* +** dot_u32_untied: +** movprfx z0, z1 +** udot z0\.s, z16\.b, z17\.b +** ret +*/ +TEST_DUAL_Z (dot_u32_untied, svuint32_t, svuint8_t, + z0 = svdot_u32 (z1, z16, z17), + z0 = svdot (z1, z16, z17)) + +/* +** dot_w0_u32_tied1: +** mov (z[0-9]+\.b), w0 +** udot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_u32_tied1, svuint32_t, svuint8_t, uint8_t, + z0 = svdot_n_u32 (z0, z16, x0), + z0 = svdot (z0, z16, x0)) + +/* +** dot_w0_u32_tied2: +** mov (z[0-9]+\.b), w0 +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** udot z16\.s, \2\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_u32_tied2, svuint32_t, svuint8_t, uint8_t, + z16_res = svdot_n_u32 (z0, z16, x0), + z16_res = svdot (z0, z16, x0)) + +/* +** dot_w0_u32_untied: +** mov (z[0-9]+\.b), w0 +** movprfx z0, z1 +** udot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_u32_untied, svuint32_t, svuint8_t, uint8_t, + z0 = svdot_n_u32 (z1, z16, x0), + z0 = svdot (z1, z16, x0)) + +/* +** dot_b0_u32_untied: +** mov (z[0-9]+\.b), b0 +** movprfx z1, z0 +** udot z1\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_ZS (dot_b0_u32_untied, svuint32_t, svuint8_t, uint8_t, + z1 = svdot_n_u32 (z0, z16, d0), + z1 = svdot (z0, z16, d0)) + +/* +** dot_2_u32_untied: +** mov (z[0-9]+\.b), #2 +** movprfx z0, z1 +** udot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_Z (dot_2_u32_untied, svuint32_t, svuint8_t, + z0 = svdot_n_u32 (z1, z16, 2), + z0 = svdot (z1, z16, 2)) + +/* +** dot_m1_u32: +** mov (z[0-9]+\.b), #-1 +** udot z0\.s, z16\.b, \1 +** ret +*/ +TEST_DUAL_Z (dot_m1_u32, svuint32_t, svuint8_t, + z0 = svdot_n_u32 (z0, z16, -1), + z0 = svdot (z0, z16, -1)) + diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c new file mode 100644 index 0000000..8f22ad5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/dot_u64.c @@ -0,0 +1,111 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** dot_u64_tied1: +** udot z0\.d, z16\.h, z17\.h +** ret +*/ +TEST_DUAL_Z (dot_u64_tied1, svuint64_t, svuint16_t, + z0 = svdot_u64 (z0, z16, z17), + z0 = svdot (z0, z16, z17)) + +/* +** dot_u64_tied2: +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** udot z16\.d, \1\.h, z17\.h +** ret +*/ +TEST_DUAL_Z (dot_u64_tied2, svuint64_t, svuint16_t, + z16_res = svdot_u64 (z0, z16, z17), + z16_res = svdot (z0, z16, z17)) + +/* +** dot_u64_tied3: +** mov (z[0-9]+)\.d, z17\.d +** movprfx z17, z0 +** udot z17\.d, z16\.h, \1\.h +** ret +*/ +TEST_DUAL_Z (dot_u64_tied3, svuint64_t, svuint16_t, + z17_res = svdot_u64 (z0, z16, z17), + z17_res = svdot (z0, z16, z17)) + +/* +** dot_u64_untied: +** movprfx z0, z1 +** udot z0\.d, z16\.h, z17\.h +** ret +*/ +TEST_DUAL_Z (dot_u64_untied, svuint64_t, svuint16_t, + z0 = svdot_u64 (z1, z16, z17), + z0 = svdot (z1, z16, z17)) + +/* +** dot_w0_u64_tied1: +** mov (z[0-9]+\.h), w0 +** udot z0\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_u64_tied1, svuint64_t, svuint16_t, uint16_t, + z0 = svdot_n_u64 (z0, z16, x0), + z0 = svdot (z0, z16, x0)) + +/* +** dot_w0_u64_tied2: +** mov (z[0-9]+\.h), w0 +** mov (z[0-9]+)\.d, z16\.d +** movprfx z16, z0 +** udot z16\.d, \2\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_u64_tied2, svuint64_t, svuint16_t, uint16_t, + z16_res = svdot_n_u64 (z0, z16, x0), + z16_res = svdot (z0, z16, x0)) + +/* +** dot_w0_u64_untied: +** mov (z[0-9]+\.h), w0 +** movprfx z0, z1 +** udot z0\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_w0_u64_untied, svuint64_t, svuint16_t, uint16_t, + z0 = svdot_n_u64 (z1, z16, x0), + z0 = svdot (z1, z16, x0)) + +/* +** dot_h0_u64_untied: +** mov (z[0-9]+\.h), h0 +** movprfx z1, z0 +** udot z1\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_ZS (dot_h0_u64_untied, svuint64_t, svuint16_t, uint16_t, + z1 = svdot_n_u64 (z0, z16, d0), + z1 = svdot (z0, z16, d0)) + +/* +** dot_2_u64_untied: +** mov (z[0-9]+\.h), #2 +** movprfx z0, z1 +** udot z0\.d, z16\.h, \1 +** ret +*/ +TEST_DUAL_Z (dot_2_u64_untied, svuint64_t, svuint16_t, + z0 = svdot_n_u64 (z1, z16, 2), + z0 = svdot (z1, z16, 2)) + +/* +** dot_m1_u64: +** mov (z[0-9]+)\.b, #-1 +** udot z0\.d, z16\.h, \1\.h +** ret +*/ +TEST_DUAL_Z (dot_m1_u64, svuint64_t, svuint16_t, + z0 = svdot_n_u64 (z0, z16, -1), + z0 = svdot (z0, z16, -1)) + diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h index f91f26f..07b110c 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/test_sve_acle.h @@ -26,6 +26,8 @@ asm volatile ("" :: "r" (XN)) # define BIND_OUTPUT_D(DN) \ asm volatile ("" :: "w" (DN)) +# define DECLARE_RESULT(TYPE, ZN) \ + register TYPE ZN##_res asm (#ZN) #else # define BIND_INPUT_Z(TYPE, ZN) TYPE ZN # define BIND_INPUT_P(PN) svbool_t PN @@ -35,6 +37,7 @@ # define BIND_OUTPUT_P(PN) (void) PN # define BIND_OUTPUT_X(XN) (void) XN # define BIND_OUTPUT_D(DN) (void) DN +# define DECLARE_RESULT(TYPE, ZN) TYPE ZN##_res #endif #if defined (TEST_OVERLOADS) @@ -52,6 +55,16 @@ BIND_INPUT_Z (TYPE, z3); \ BIND_INPUT_Z (TYPE, z4) +#define BIND_INPUT_ZS_FROM_Z16(TYPE) \ + BIND_INPUT_Z (TYPE, z16); \ + BIND_INPUT_Z (TYPE, z17); \ + BIND_INPUT_Z (TYPE, z18) \ + +#define DECLARE_RESULT_ZS_FROM_Z16(TYPE) \ + DECLARE_RESULT (TYPE, z16); \ + DECLARE_RESULT (TYPE, z17); \ + DECLARE_RESULT (TYPE, z18) + #define BIND_OUTPUT_ZS \ BIND_OUTPUT_Z (z0); \ BIND_OUTPUT_Z (z1); \ @@ -73,6 +86,11 @@ BIND_OUTPUT_P (p3); \ BIND_OUTPUT_P (p4) +#define BIND_RESULT_ZS_FROM_Z16 \ + BIND_OUTPUT_Z (z16_res); \ + BIND_OUTPUT_Z (z17_res); \ + BIND_OUTPUT_Z (z18_res) + #ifdef __cplusplus #define START(NAME) extern "C" void NAME (void); void NAME (void) #else @@ -89,6 +107,19 @@ BIND_OUTPUT_P (p0); \ } +#define TEST_DUAL_Z(NAME, TYPE1, TYPE2, CODE1, CODE2) \ + START (NAME) \ + { \ + BIND_INPUT_ZS (TYPE1); \ + BIND_INPUT_ZS_FROM_Z16 (TYPE2); \ + DECLARE_RESULT_ZS_FROM_Z16 (TYPE1); \ + BIND_INPUT_P (p0); \ + INVOKE (CODE1, CODE2); \ + BIND_OUTPUT_ZS; \ + BIND_OUTPUT_P (p0); \ + BIND_RESULT_ZS_FROM_Z16; \ + } + #define TEST_UNIFORM_ZS(NAME, ZTYPE, STYPE, CODE1, CODE2) \ START (NAME) \ { \ @@ -103,6 +134,23 @@ BIND_OUTPUT_P (p0); \ } +#define TEST_DUAL_ZS(NAME, ZTYPE1, ZTYPE2, STYPE, CODE1, CODE2) \ + START (NAME) \ + { \ + BIND_INPUT_ZS (ZTYPE1); \ + BIND_INPUT_ZS_FROM_Z16 (ZTYPE2); \ + DECLARE_RESULT_ZS_FROM_Z16 (ZTYPE1); \ + BIND_INPUT_P (p0); \ + BIND_INPUT_X (STYPE, x0); \ + BIND_INPUT_D (STYPE, d0); \ + INVOKE (CODE1, CODE2); \ + BIND_OUTPUT_ZS; \ + BIND_OUTPUT_X (x0); \ + BIND_OUTPUT_D (d0); \ + BIND_OUTPUT_P (p0); \ + BIND_RESULT_ZS_FROM_Z16; \ + } + #define TEST_P(NAME, CODE1, CODE2) \ START (NAME) \ { \ diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c new file mode 100644 index 0000000..b25d6d9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_1.c @@ -0,0 +1,13 @@ + +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" /* { dg-message "note: expected 'svuint8_t' but argument is of type 'svuint32_t'" } */ + +svint32_t +f1 (svbool_t pg, svuint32_t x, svuint8_t y, svuint8_t z) +{ + svdot_u32 (x, y, x); /* { dg-error "incompatible type for argument 3 of 'svdot_u32'" } */ + svdot_u32 (x); /* { dg-error "too few arguments to function 'svdot_u32'" } */ + svdot_u32 (x, y, z, x); /* { dg-error "too many arguments to function 'svdot_u32'" } */ + return svdot_u32 (x, y, z); /* { dg-error "incompatible types when returning type 'svuint32_t' but 'svint32_t' was expected" } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c new file mode 100644 index 0000000..db1b41a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/dot_2.c @@ -0,0 +1,15 @@ + +/* { dg-do compile } */ + +#pragma GCC aarch64 "arm_sve.h" + +void +f1 (svuint32_t x, svuint8_t y, svint8_t z) +{ + svdot (x); /* { dg-error "too few arguments to function 'svdot'" } */ + svdot (x, y, y, y); /* { dg-error "too many arguments to function 'svdot'" } */ + svdot (x, y, z); /* { dg-error "passing 'svint8_t' to argument 3 of 'svdot', which expects 'svuint8_t'" } */ + svdot (x, x, x); /* { dg-error "passing 'svuint32_t' to argument 2 of 'svdot', which expects 'svuint8_t'" } */ + svdot (1, y, y); /* { dg-error "passing 'int' to argument 1 of 'svdot', which expects an SVE vector type" } */ + svdot (y, y, y); /* { dg-error "'svdot' has no form that takes 'svuint8_t' arguments" } */ +} -- 2.7.4