These functions require the shift amount to be an integer constant expression in the range [1, N]. The patch adds a new hook so that targets can check this.
Also, the ACLE asm tests try many combinations per file, so I'd added code to parallelise them at single-file granularity. However, the code to do that was using variables that only exist when -j is used and so this patch makes it conditional. Tested on aarch64-linux-gnu and committed to aarch64/sve-acle-branch. Richard ------------------------------------------------------------------------ diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp b/gcc/testsuite/g++.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp index e4a65b809a4..88cf53396e5 100644 --- a/gcc/testsuite/g++.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp +++ b/gcc/testsuite/g++.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp @@ -48,8 +48,10 @@ if { ![string equal $sve_flags ""] || [aarch64_sve_bits] == 0 } { } global gcc_runtest_parallelize_limit_minor -set old_limit_minor $gcc_runtest_parallelize_limit_minor -set gcc_runtest_parallelize_limit_minor 1 +if { [info exists gcc_runtest_parallelize_limit_minor] } { + set old_limit_minor $gcc_runtest_parallelize_limit_minor + set gcc_runtest_parallelize_limit_minor 1 +} torture-init set-torture-options { @@ -76,7 +78,9 @@ gcc-dg-runtest [lsort $files] \ torture-finish -set gcc_runtest_parallelize_limit_minor $old_limit_minor +if { [info exists gcc_runtest_parallelize_limit_minor] } { + set gcc_runtest_parallelize_limit_minor $old_limit_minor +} # All done. dg-finish diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp b/gcc/testsuite/gcc.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp index 7dbdee2825e..b4fd451adea 100644 --- a/gcc/testsuite/gcc.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/aarch64-sve-acle-asm.exp @@ -48,8 +48,10 @@ if { ![string equal $sve_flags ""] || [aarch64_sve_bits] == 0 } { } global gcc_runtest_parallelize_limit_minor -set old_limit_minor $gcc_runtest_parallelize_limit_minor -set gcc_runtest_parallelize_limit_minor 1 +if { [info exists gcc_runtest_parallelize_limit_minor] } { + set old_limit_minor $gcc_runtest_parallelize_limit_minor + set gcc_runtest_parallelize_limit_minor 1 +} torture-init set-torture-options { @@ -72,7 +74,9 @@ gcc-dg-runtest [lsort $files] \ torture-finish -set gcc_runtest_parallelize_limit_minor $old_limit_minor +if { [info exists gcc_runtest_parallelize_limit_minor] } { + set gcc_runtest_parallelize_limit_minor $old_limit_minor +} # All done. dg-finish ------------------------------------------------------------------------ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index f5e1111a772..9bb3feedf03 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -5749,16 +5749,24 @@ builtin_function_validate_nargs (location_t loc, tree fndecl, int nargs, /* Verifies the NARGS arguments ARGS to the builtin function FNDECL. Returns false if there was an error, otherwise true. LOC is the location of the function; ARG_LOC is a vector of locations of the - arguments. */ + arguments. If FNDECL is the result of resolving an overloaded + target built-in, ORIG_FNDECL is the original function decl, + otherwise it is null. */ bool check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc, - tree fndecl, int nargs, tree *args) + tree fndecl, tree orig_fndecl, + int nargs, tree *args) { - if (!DECL_BUILT_IN (fndecl) - || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) + if (!DECL_BUILT_IN (fndecl)) return true; + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) + return (!targetm.check_builtin_call + || targetm.check_builtin_call (loc, arg_loc, fndecl, + orig_fndecl, nargs, args)); + + gcc_assert (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL); switch (DECL_FUNCTION_CODE (fndecl)) { case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX: diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index c266fee74c7..f14c2d8f84c 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -803,7 +803,7 @@ extern void check_function_arguments_recurse (void (*) void *, tree, unsigned HOST_WIDE_INT); extern bool check_builtin_function_arguments (location_t, vec<location_t>, - tree, int, tree *); + tree, tree, int, tree *); extern void check_function_format (tree, int, tree *, vec<location_t> *); extern bool attribute_fallthrough_p (tree); extern tree handle_format_attribute (tree *, tree, tree, int, bool *); @@ -979,7 +979,8 @@ extern bool c_switch_covers_all_cases_p (splay_tree, tree); extern tree build_function_call (location_t, tree, tree); extern tree build_function_call_vec (location_t, vec<location_t>, tree, - vec<tree, va_gc> *, vec<tree, va_gc> *); + vec<tree, va_gc> *, vec<tree, va_gc> *, + tree = NULL_TREE); extern tree resolve_overloaded_builtin (location_t, tree, vec<tree, va_gc> *); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 90ae306c99a..a6d114a3330 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -2995,6 +2995,8 @@ inform_declaration (tree decl) } /* Build a function call to function FUNCTION with parameters PARAMS. + If FUNCTION is the result of resolving an overloaded target built-in, + ORIG_FUNDECL is the original function decl, otherwise it is null. ORIGTYPES, if not NULL, is a vector of types; each element is either NULL or the original type of the corresponding element in PARAMS. The original type may differ from TREE_TYPE of the @@ -3005,7 +3007,7 @@ inform_declaration (tree decl) tree build_function_call_vec (location_t loc, vec<location_t> arg_loc, tree function, vec<tree, va_gc> *params, - vec<tree, va_gc> *origtypes) + vec<tree, va_gc> *origtypes, tree orig_fundecl) { tree fntype, fundecl = NULL_TREE; tree name = NULL_TREE, result; @@ -3025,6 +3027,8 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, if (flag_tm) tm_malloc_replacement (function); fundecl = function; + if (!orig_fundecl) + orig_fundecl = fundecl; /* Atomic functions have type checking/casting already done. They are often rewritten and don't match the original parameter list. */ if (name && !strncmp (IDENTIFIER_POINTER (name), "__atomic_", 9)) @@ -3104,9 +3108,8 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc, /* Check that arguments to builtin functions match the expectations. */ if (fundecl && DECL_BUILT_IN (fundecl) - && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL - && !check_builtin_function_arguments (loc, arg_loc, fundecl, nargs, - argarray)) + && !check_builtin_function_arguments (loc, arg_loc, fundecl, + orig_fundecl, nargs, argarray)) return error_mark_node; /* Check that the arguments to the function are valid. */ diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c index 84343baa239..959feca4a58 100644 --- a/gcc/config/aarch64/aarch64-c.c +++ b/gcc/config/aarch64/aarch64-c.c @@ -277,7 +277,28 @@ aarch64_resolve_overloaded_builtin (unsigned int uncast_location, return NULL_TREE; if (new_fndecl == error_mark_node) return error_mark_node; - return build_function_call_vec (location, vNULL, new_fndecl, arglist, NULL); + return build_function_call_vec (location, vNULL, new_fndecl, arglist, + NULL, fndecl); +} + +/* Implement TARGET_CHECK_BUILTIN_CALL. */ +static bool +aarch64_check_builtin_call (location_t loc, vec<location_t> arg_loc, + tree fndecl, tree orig_fndecl, + unsigned int nargs, tree *args) +{ + unsigned int code = DECL_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + switch (code & AARCH64_BUILTIN_CLASS) + { + case AARCH64_BUILTIN_GENERAL: + return true; + + case AARCH64_BUILTIN_SVE: + return aarch64_sve::check_builtin_call (loc, arg_loc, subcode, + orig_fndecl, nargs, args); + } + gcc_unreachable (); } /* Implement REGISTER_TARGET_PRAGMAS. */ @@ -289,6 +310,7 @@ aarch64_register_pragmas (void) targetm.target_option.pragma_parse = aarch64_pragma_target_parse; targetm.resolve_overloaded_builtin = aarch64_resolve_overloaded_builtin; + targetm.check_builtin_call = aarch64_check_builtin_call; c_register_pragma ("GCC", "aarch64", aarch64_pragma_aarch64); } diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 57e151af1a9..77c788cb97a 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -548,6 +548,8 @@ namespace aarch64_sve { const char *mangle_builtin_type (const_tree); tree resolve_overloaded_builtin (location_t, unsigned int, vec<tree, va_gc> *); + bool check_builtin_call (location_t, vec<location_t>, unsigned int, + tree, unsigned int, tree *); gimple *gimple_fold_builtin (unsigned int, gcall *); rtx expand_builtin (unsigned int, tree, rtx); } diff --git a/gcc/config/aarch64/aarch64-sve-builtins.c b/gcc/config/aarch64/aarch64-sve-builtins.c index 38f8f786e49..24fc2fc2f77 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.c +++ b/gcc/config/aarch64/aarch64-sve-builtins.c @@ -96,7 +96,13 @@ enum function_shape { /* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0>_t) sv<t0>_t svfoo[_n_t0](sv<t0>_t, <t0>_t). */ - SHAPE_binary_opt_n + SHAPE_binary_opt_n, + + /* sv<t0>_t svfoo[_n_t0])(sv<t0>_t, uint64_t) + + The final argument must be an integer constant expression in the + range [1, <t0>_BITS]. */ + SHAPE_shift_right_imm }; /* Classifies an operation into "modes"; for example, to distinguish @@ -258,6 +264,7 @@ private: void sig_inherent (const function_instance &, vec<tree> &); void sig_000 (const function_instance &, vec<tree> &); void sig_n_000 (const function_instance &, vec<tree> &); + void sig_n_00i (const function_instance &, vec<tree> &); void apply_predication (const function_instance &, vec<tree> &); @@ -290,17 +297,22 @@ private: class function_resolver { public: - function_resolver (location_t, registered_function &, vec<tree, va_gc> &); + function_resolver (location_t, const registered_function &, + vec<tree, va_gc> &); tree resolve (); private: tree resolve_uniform (unsigned int); + tree resolve_uniform_imm (unsigned int, unsigned int); + bool check_first_vector_argument (unsigned int, unsigned int &, + unsigned int &, vector_type &); bool check_num_arguments (unsigned int); bool check_argument (unsigned int, vector_type); vector_type require_vector_type (unsigned int); bool require_matching_type (unsigned int, vector_type); bool scalar_argument_p (unsigned int); + bool require_integer_immediate (unsigned int); tree require_n_form (type_suffix, type_suffix = NUM_TYPE_SUFFIXES); tree require_form (function_mode, type_suffix, type_suffix = NUM_TYPE_SUFFIXES); @@ -312,7 +324,7 @@ private: location_t m_location; /* The overloaded function. */ - registered_function &m_rfn; + const registered_function &m_rfn; /* The arguments to the overloaded function. */ vec<tree, va_gc> &m_arglist; @@ -321,6 +333,39 @@ private: const function_group &m_group; }; +/* A class for checking that the semantic constraints on a function call are + satisfied, such as arguments being integer constant expressions with + a particular range. */ +class function_checker +{ +public: + function_checker (location_t, const function_instance &, tree, + unsigned int, tree *); + bool check (); + +private: + bool check_shift_right_imm (); + + bool require_immediate_range (unsigned int, HOST_WIDE_INT, HOST_WIDE_INT); + + /* The location of the call. */ + location_t m_location; + + /* The non-overloaded function being called. */ + const function_instance &m_fi; + + /* The function that the user called (which might be an overloaded form + of M_FI). */ + tree m_decl; + + /* The arguments to the function. */ + unsigned int m_nargs; + tree *m_args; + + /* The static table entry for the function. */ + const function_group &m_group; +}; + /* A class for folding a gimple function call. */ class gimple_folder { @@ -350,6 +395,7 @@ public: private: rtx expand_add (unsigned int); + rtx expand_asrd (); rtx expand_max (); rtx expand_min (); rtx expand_ptrue (); @@ -360,6 +406,9 @@ private: rtx expand_via_pred_direct_optab (optab, unsigned int, unsigned int); rtx expand_via_pred_insn (insn_code, unsigned int, unsigned int); rtx expand_via_pred_x_insn (insn_code, unsigned int); + rtx expand_pred_shift_right_imm (insn_code); + + void require_immediate_range (unsigned int, HOST_WIDE_INT, HOST_WIDE_INT); bool try_negating_argument (unsigned int, machine_mode); @@ -372,11 +421,15 @@ private: rtx generate_insn (insn_code); /* The function being called. */ + const registered_function &m_rfn; const function_instance &m_fi; /* The function call expression. */ tree m_exp; + /* The location of the call. */ + location_t m_location; + /* Where the result should go, if convenient. */ rtx m_target; @@ -507,6 +560,28 @@ find_vector_type (const_tree type) return NUM_VECTOR_TYPES; } +/* Report that LOCATION has a call to DECL in which argument ARGNO + was not an integer constant expression. */ +static void +report_non_ice (location_t location, tree decl, unsigned int argno) +{ + error_at (location, "argument %d of %qE must be an integer constant" + " expression", argno + 1, decl); +} + +/* Report that LOCATION has a call to DECL in which argument ARGNO has + the value ACTUAL, whereas the function requires a value in the range + [MIN, MAX]. */ +static void +report_out_of_range (location_t location, tree decl, unsigned int argno, + HOST_WIDE_INT actual, HOST_WIDE_INT min, + HOST_WIDE_INT max) +{ + error_at (location, "passing %wd to argument %d of %qE, which expects" + " a value in the range [%wd, %wd]", actual, argno + 1, decl, + min, max); +} + inline function_instance::function_instance (function func_in, function_mode mode_in, @@ -613,6 +688,11 @@ arm_sve_h_builder::build (const function_group &group) /* No overloaded functions here. */ build_all (&arm_sve_h_builder::sig_inherent, group, MODE_none); break; + + case SHAPE_shift_right_imm: + add_overloaded_functions (group, MODE_n); + build_all (&arm_sve_h_builder::sig_n_00i, group, MODE_n); + break; } } @@ -668,6 +748,17 @@ arm_sve_h_builder::sig_n_000 (const function_instance &instance, types.quick_push (instance.scalar_type (0)); } +/* Describe the signature "sv<t0>_t svfoo[_n_t0](sv<t0>_t, uint64_t)" + for INSTANCE in TYPES. */ +void +arm_sve_h_builder::sig_n_00i (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 (scalar_types[VECTOR_TYPE_svuint64_t]); +} + /* If INSTANCE has a governing predicate, add it to the type signature in TYPES, where TYPES[0] is the return type, TYPES[1] is the first argument type, etc. */ @@ -807,6 +898,7 @@ arm_sve_h_builder::get_attributes (const function_instance &instance) switch (instance.func) { case FUNC_svadd: + case FUNC_svasrd: case FUNC_svmax: case FUNC_svmin: case FUNC_svsub: @@ -848,6 +940,7 @@ arm_sve_h_builder::get_explicit_types (function_shape shape) case SHAPE_inherent: return 1; case SHAPE_binary_opt_n: + case SHAPE_shift_right_imm: return 0; } gcc_unreachable (); @@ -898,7 +991,7 @@ arm_sve_h_builder::finish_name () } function_resolver::function_resolver (location_t location, - registered_function &rfn, + const registered_function &rfn, vec<tree, va_gc> &arglist) : m_location (location), m_rfn (rfn), m_arglist (arglist), m_group (function_groups[rfn.instance.func]) @@ -914,6 +1007,8 @@ function_resolver::resolve () { case SHAPE_binary_opt_n: return resolve_uniform (2); + case SHAPE_shift_right_imm: + return resolve_uniform_imm (2, 1); case SHAPE_inherent: break; } @@ -928,37 +1023,88 @@ tree function_resolver::resolve_uniform (unsigned int nops) { /* Check that we have the right number of arguments. */ - unsigned int full_nops = nops; - if (m_rfn.instance.pred != PRED_none) - full_nops += 1; - if (!check_num_arguments (full_nops)) + unsigned int i, nargs; + vector_type type; + if (!check_first_vector_argument (nops, i, nargs, type)) + return error_mark_node; + + /* Handle subsequent arguments. */ + for (; i < nargs; ++i) + { + /* Allow the final argument to be scalar, if an _n form exists. */ + if (i == nargs - 1 && scalar_argument_p (i)) + return require_n_form (get_type_suffix (type)); + if (!require_matching_type (i, 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 +function_resolver::resolve_uniform_imm (unsigned int nops, unsigned int nimm) +{ + /* Check that we have the right number of arguments. Also check the + first vector argument and governing predicate. */ + unsigned int i, nargs; + vector_type type; + if (!check_first_vector_argument (nops, i, nargs, type)) return error_mark_node; - unsigned int i = 0; + /* Handle subsequent vector arguments. */ + for (; i < nargs - nimm; ++i) + if (!require_matching_type (i, type)) + return error_mark_node; + + /* Handle the final immediate arguments. */ + for (; i < nargs; ++i) + if (!require_integer_immediate (i)) + return error_mark_node; + + return require_form (m_rfn.instance.mode, get_type_suffix (type)); +} + +/* Check that the function is passed NOPS arguments plus the governing + predicate (if applicable) and that the first argument besides the + governing predicate is a vector. Return true if so, otherwise + report a suitable error. + + When returning true: + - set I to the number of the first unchecked argument (past the first + vector and past any governing predicate). + - set NARGS to the number of arguments including any governing + predicate. + - set TYPE to the type of the vector argument. */ +bool +function_resolver::check_first_vector_argument (unsigned int nops, + unsigned int &i, + unsigned int &nargs, + vector_type &type) +{ + i = 0; + nargs = nops; + type = NUM_VECTOR_TYPES; + + if (m_rfn.instance.pred != PRED_none) + nargs += 1; + if (!check_num_arguments (nargs)) + return false; /* Check the predicate argument. */ if (m_rfn.instance.pred != PRED_none) { if (!check_argument (i, VECTOR_TYPE_svbool_t)) - return error_mark_node; + return false; i += 1; } /* The next argument is always a vector. */ - vector_type type = require_vector_type (i); + type = require_vector_type (i); if (type == NUM_VECTOR_TYPES) - return error_mark_node; + return false; - /* Handle subsequent arguments. */ - for (; i < full_nops; ++i) - { - /* Allow the final argument to be scalar, if an _n form exists. */ - if (i == full_nops - 1 && scalar_argument_p (i)) - return require_n_form (get_type_suffix (type)); - if (!require_matching_type (i, type)) - return error_mark_node; - } - return require_form (m_rfn.instance.mode, get_type_suffix (type)); + return true; } /* Require the function to have exactly EXPECTED arguments. Return true @@ -1035,6 +1181,20 @@ function_resolver::scalar_argument_p (unsigned int i) return INTEGRAL_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (type); } +/* Check that argument I has a suitable form for an integer constant + expression. function_checker checks whether the argument is + actually constant and has a suitable range. */ +bool +function_resolver::require_integer_immediate (unsigned int i) +{ + if (!scalar_argument_p (i)) + { + report_non_ice (m_location, m_rfn.decl, i); + return false; + } + return true; +} + /* Return the type of argument I, or error_mark_node if it isn't well-formed. */ tree @@ -1101,12 +1261,72 @@ function_resolver::lookup_form (function_mode mode, type_suffix type0, { type_suffix_pair types = { type0, type1 }; function_instance instance (m_rfn.instance.func, mode, types, - m_rfn.instance.pred); + m_rfn.instance.pred); registered_function *rfn = function_table->find_with_hash (instance, instance.hash ()); return rfn ? rfn->decl : NULL_TREE; } +function_checker::function_checker (location_t location, + const function_instance &fi, tree decl, + unsigned int nargs, tree *args) + : m_location (location), m_fi (fi), m_decl (decl), m_nargs (nargs), + m_args (args), m_group (function_groups[m_fi.func]) +{ +} + +/* Perform semantic checks on the call. Return true if the call is valid, + otherwise report a suitable error. */ +bool +function_checker::check () +{ + switch (m_group.shape) + { + case SHAPE_shift_right_imm: + return check_shift_right_imm (); + + case SHAPE_inherent: + case SHAPE_binary_opt_n: + return true; + } + gcc_unreachable (); +} + +/* Check a SHAPE_shift_right_imm call. */ +bool +function_checker::check_shift_right_imm () +{ + unsigned int bits = type_suffixes[m_fi.types[0]].elem_bits; + return require_immediate_range (2, 1, bits); +} + +/* Check that argument ARGNO is an integer constant expression in the + range [MIN, MAX]. */ +bool +function_checker::require_immediate_range (unsigned int argno, + HOST_WIDE_INT min, + HOST_WIDE_INT max) +{ + if (m_nargs <= argno) + return true; + + tree arg = m_args[argno]; + if (!tree_fits_shwi_p (arg)) + { + report_non_ice (m_location, m_decl, argno); + return false; + } + + HOST_WIDE_INT actual = tree_to_shwi (arg); + if (!IN_RANGE (actual, min, max)) + { + report_out_of_range (m_location, m_decl, argno, actual, min, max); + return false; + } + + return true; +} + /* Register the built-in SVE ABI types, such as __SVBool_t. */ static void register_builtin_types () @@ -1190,13 +1410,10 @@ builtin_decl (unsigned int code, bool) return (*registered_functions)[code]->decl; } -/* Check a call to the SVE function with subcode CODE. The call occurs - at location LOCATION and has the arguments given by ARGLIST. - - Perform any extra semantic checks, such as testing for integer constant - expressions. If we're implementing manual overloading and the - function is overloaded, attempt to determine the corresponding - non-overloaded function. +/* If we're implementing manual overloading, check whether the SVE + function with subcode CODE is overloaded, and if so attempt to + determine the corresponding non-overloaded function. The call + occurs at location LOCATION and has the arguments given by ARGLIST. If the call is erroneous, report an appropriate error and return error_mark_node. Otherwise, if the function is overloaded, return @@ -1215,6 +1432,23 @@ resolve_overloaded_builtin (location_t location, unsigned int code, return NULL_TREE; } +/* Perform any semantic checks needed for a call to the SVE function with + subcode CODE, such as testing for integer constant expressions. + The call occurs at location LOCATION and has NARGS arguments. + ARGS gives the value of each argument and ARG_LOCATION gives + their location. FNDECL is the original function decl, before + overload resolution. + + Return true if the call is valid, otherwise report a suitable error. */ +bool +check_builtin_call (location_t location, vec<location_t>, unsigned int code, + tree fndecl, unsigned int nargs, tree *args) +{ + registered_function &rfn = *(*registered_functions)[code]; + return function_checker (location, rfn.instance, fndecl, + nargs, args).check (); +} + /* Construct a folder for CALL, which calls the SVE function with subcode CODE. */ gimple_folder::gimple_folder (unsigned int code, gcall *call) @@ -1231,6 +1465,7 @@ gimple_folder::fold () switch (m_fi.func) { case FUNC_svadd: + case FUNC_svasrd: case FUNC_svmax: case FUNC_svmin: case FUNC_svsub: @@ -1274,8 +1509,9 @@ gimple_fold_builtin (unsigned int code, gcall *stmt) EXP is the call expression and TARGET is the preferred location for the result. */ function_expander::function_expander (unsigned int code, tree exp, rtx target) - : m_fi ((*registered_functions)[code]->instance), - m_exp (exp), m_target (target) + : m_rfn (*(*registered_functions)[code]), + m_fi (m_rfn.instance), + m_exp (exp), m_location (EXPR_LOCATION (exp)), m_target (target) { } @@ -1293,6 +1529,9 @@ function_expander::expand () case FUNC_svadd: return expand_add (1); + case FUNC_svasrd: + return expand_asrd (); + case FUNC_svmax: return expand_max (); @@ -1335,6 +1574,13 @@ function_expander::expand_add (unsigned int merge_argno) return expand_via_pred_direct_optab (cond_add_optab, 2, merge_argno); } +/* Expand a call to svasrd. */ +rtx +function_expander::expand_asrd () +{ + return expand_pred_shift_right_imm (code_for_cond_asrd (get_mode (0))); +} + /* Expand a call to svmax. */ rtx function_expander::expand_max () @@ -1428,7 +1674,7 @@ function_expander::expand_via_pred_direct_optab (optab op, unsigned int nops, Merging forms use argument MERGE_ARGNO as the fallback value. */ rtx function_expander::expand_via_pred_insn (insn_code icode, unsigned int nops, - unsigned int merge_argno) + unsigned int merge_argno) { machine_mode mode = get_mode (0); machine_mode pred_mode = get_pred_mode (0); @@ -1529,6 +1775,36 @@ function_expander::expand_signed_pred_op (rtx_code code_for_sint, } } +/* Expand a call to a SHAPE_shift_right_imm function using predicated + instruction ICODE, which has the same operand order as conditional + optabs like cond_add_optab. */ +rtx +function_expander::expand_pred_shift_right_imm (insn_code icode) +{ + require_immediate_range (2, 1, GET_MODE_UNIT_BITSIZE (get_mode (0))); + return expand_via_pred_insn (icode, 2, 1); +} + +/* Require that argument ARGNO is a constant integer in the range + [MIN, MAX]. Report an appropriate error if it isn't and set + the argument to a safe in-range value. */ +void +function_expander::require_immediate_range (unsigned int argno, + HOST_WIDE_INT min, + HOST_WIDE_INT max) +{ + if (!CONST_INT_P (m_args[argno])) + report_non_ice (m_location, m_rfn.decl, argno); + else + { + HOST_WIDE_INT actual = INTVAL (m_args[argno]); + if (IN_RANGE (actual, min, max)) + return; + report_out_of_range (m_location, m_rfn.decl, argno, actual, min, max); + } + m_args[argno] = GEN_INT (min); +} + /* Return true if argument I is a constant argument that can be negated at compile time, replacing it with the negated value if so. MODE is the associated vector mode, but the argument could be a single element. */ diff --git a/gcc/config/aarch64/aarch64-sve-builtins.def b/gcc/config/aarch64/aarch64-sve-builtins.def index ae53dc7f369..d53ae4b10d9 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.def +++ b/gcc/config/aarch64/aarch64-sve-builtins.def @@ -61,6 +61,7 @@ DEF_SVE_TYPE_SUFFIX (u64, svuint64_t, 64) /* List of functions, in alphabetical order. */ DEF_SVE_FUNCTION (svadd, binary_opt_n, all_data, mxz) +DEF_SVE_FUNCTION (svasrd, shift_right_imm, all_signed, mxz) DEF_SVE_FUNCTION (svmax, binary_opt_n, all_data, mxz) DEF_SVE_FUNCTION (svmin, binary_opt_n, all_data, mxz) DEF_SVE_FUNCTION (svptrue, inherent, all_pred, none) diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index d6f8a6f63d0..558c58e42c5 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -1995,6 +1995,52 @@ "#" ) +;; Predicated ASRD. +(define_expand "@cond_asrd<mode>" + [(set (match_operand:SVE_I 0 "register_operand") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand") + (match_operand:SVE_I 3 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD) + (match_operand:SVE_I 4 "aarch64_simd_reg_or_zero")] + UNSPEC_SEL))] + "TARGET_SVE" +) + +;; Predicated ASRD with select matching the first input. +(define_insn "*cond_asrd<mode>_2" + [(set (match_operand:SVE_I 0 "register_operand" "=w, ?&w") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand" "Upl, Upl") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand" "0, w") + (match_operand:SVE_I 3 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD) + (match_dup 2)] + UNSPEC_SEL))] + "TARGET_SVE" + "@ + asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3 + movprfx\t%0, %2\;asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3" + [(set_attr "movprfx" "*,yes")]) + +;; Predicated ASRD with select matching zero. +(define_insn "*cond_asrd<mode>_z" + [(set (match_operand:SVE_I 0 "register_operand" "=w") + (unspec:SVE_I + [(match_operand:<VPRED> 1 "register_operand" "Upl") + (unspec:SVE_I + [(match_operand:SVE_I 2 "register_operand" "w") + (match_operand:SVE_I 3 "aarch64_simd_rshift_imm")] + UNSPEC_ASRD) + (match_operand:SVE_I 4 "aarch64_simd_imm_zero")] + UNSPEC_SEL))] + "TARGET_SVE" + "movprfx\t%0.<Vetype>, %1/z, %2.<Vetype>\;asrd\t%0.<Vetype>, %1/m, %0.<Vetype>, #%3" + [(set_attr "movprfx" "yes")]) + (define_insn "*cond_<optab><mode>_any" [(set (match_operand:SVE_SDI 0 "register_operand" "=&w") (unspec:SVE_SDI diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index 9880f8f0fff..cfbe52b593b 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -195,6 +195,7 @@ UNSPEC_CLASTB UNSPEC_FADDA UNSPEC_REV_SUBREG + UNSPEC_ASRD ]) (define_c_enum "unspecv" [ diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 209c1fd2f0e..2bfe977513a 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8812,12 +8812,14 @@ maybe_warn_class_memaccess (location_t loc, tree fndecl, } /* Build and return a call to FN, using NARGS arguments in ARGARRAY. + If FN is the result of resolving an overloaded target built-in, + ORIG_FNDECL is the original function decl, otherwise it is null. This function performs no overload resolution, conversion, or other high-level operations. */ tree build_cxx_call (tree fn, int nargs, tree *argarray, - tsubst_flags_t complain) + tsubst_flags_t complain, tree orig_fndecl) { tree fndecl; @@ -8827,12 +8829,13 @@ build_cxx_call (tree fn, int nargs, tree *argarray, SET_EXPR_LOCATION (fn, loc); fndecl = get_callee_fndecl (fn); + if (!orig_fndecl) + orig_fndecl = fndecl; /* Check that arguments to builtin functions match the expectations. */ if (fndecl && !processing_template_decl - && DECL_BUILT_IN (fndecl) - && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + && DECL_BUILT_IN (fndecl)) { int i; @@ -8842,7 +8845,7 @@ build_cxx_call (tree fn, int nargs, tree *argarray, argarray[i] = maybe_constant_value (argarray[i]); if (!check_builtin_function_arguments (EXPR_LOCATION (fn), vNULL, fndecl, - nargs, argarray)) + orig_fndecl, nargs, argarray)) return error_mark_node; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 6c43a9656a8..c8ff82b14e7 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6094,7 +6094,8 @@ extern tree perform_direct_initialization_if_possible (tree, tree, bool, tsubst_flags_t); extern tree in_charge_arg_for_name (tree); extern tree build_cxx_call (tree, int, tree *, - tsubst_flags_t); + tsubst_flags_t, + tree = NULL_TREE); extern bool is_std_init_list (tree); extern bool is_list_ctor (tree); extern void validate_conversion_obstack (void); @@ -7215,7 +7216,8 @@ extern tree get_member_function_from_ptrfunc (tree *, tree, tsubst_flags_t); extern tree cp_build_function_call_nary (tree, tsubst_flags_t, ...) ATTRIBUTE_SENTINEL; extern tree cp_build_function_call_vec (tree, vec<tree, va_gc> **, - tsubst_flags_t); + tsubst_flags_t, + tree = NULL_TREE); extern tree build_x_binary_op (location_t, enum tree_code, tree, enum tree_code, tree, diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ea4ce9649cd..17be052b913 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3605,11 +3605,11 @@ build_function_call (location_t /*loc*/, tree build_function_call_vec (location_t /*loc*/, vec<location_t> /*arg_loc*/, tree function, vec<tree, va_gc> *params, - vec<tree, va_gc> * /*origtypes*/) + vec<tree, va_gc> * /*origtypes*/, tree orig_function) { vec<tree, va_gc> *orig_params = params; tree ret = cp_build_function_call_vec (function, ¶ms, - tf_warning_or_error); + tf_warning_or_error, orig_function); /* cp_build_function_call_vec can reallocate PARAMS by adding default arguments. That should never happen here. Verify @@ -3654,13 +3654,15 @@ cp_build_function_call_nary (tree function, tsubst_flags_t complain, ...) return ret; } -/* Build a function call using a vector of arguments. PARAMS may be - NULL if there are no parameters. This changes the contents of - PARAMS. */ +/* Build a function call using a vector of arguments. + If FUNCTION is the result of resolving an overloaded target built-in, + ORIG_FNDECL is the original function decl, otherwise it is null. + PARAMS may be NULL if there are no parameters. This changes the + contents of PARAMS. */ tree cp_build_function_call_vec (tree function, vec<tree, va_gc> **params, - tsubst_flags_t complain) + tsubst_flags_t complain, tree orig_fndecl) { tree fntype, fndecl; int is_method; @@ -3784,7 +3786,7 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params, bool warned_p = check_function_arguments (input_location, fndecl, fntype, nargs, argarray, NULL); - ret = build_cxx_call (function, nargs, argarray, complain); + ret = build_cxx_call (function, nargs, argarray, complain, orig_fndecl); if (warned_p) { diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index ff6d5146010..7f5c0f066aa 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -11446,6 +11446,21 @@ another @code{CALL_EXPR}. @var{arglist} really has type @samp{VEC(tree,gc)*} @end deftypefn +@deftypefn {Target Hook} bool TARGET_CHECK_BUILTIN_CALL (location_t @var{loc}, vec<location_t> @var{arg_loc}, tree @var{fndecl}, tree @var{orig_fndecl}, unsigned int @var{nargs}, tree *@var{args}) +Perform semantic checking on a call to a machine-specific built-in +function after its arguments have been constrained to the function +signature. Return true if the call is valid, otherwise report an error +and return false. + +This hook is called after @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}. +The call was originally to built-in function @var{orig_fndecl}, +but after the optional @code{TARGET_RESOLVE_OVERLOADED_BUILTIN} +step is now to built-in function @var{fndecl}. @var{loc} is the +location of the call and @var{args} is an array of function arguments, +of which there are @var{nargs}. @var{arg_loc} specifies the location +of each argument. +@end deftypefn + @deftypefn {Target Hook} tree TARGET_FOLD_BUILTIN (tree @var{fndecl}, int @var{n_args}, tree *@var{argp}, bool @var{ignore}) Fold a call to a machine specific built-in function that was set up by @samp{TARGET_INIT_BUILTINS}. @var{fndecl} is the declaration of the diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 2f97151f341..7df9d4d2af6 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -7869,6 +7869,8 @@ to by @var{ce_info}. @hook TARGET_RESOLVE_OVERLOADED_BUILTIN +@hook TARGET_CHECK_BUILTIN_CALL + @hook TARGET_FOLD_BUILTIN @hook TARGET_GIMPLE_FOLD_BUILTIN diff --git a/gcc/target.def b/gcc/target.def index ff89e72dd2b..ca6d5db98b7 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -2406,6 +2406,24 @@ another @code{CALL_EXPR}.\n\ @var{arglist} really has type @samp{VEC(tree,gc)*}", tree, (unsigned int /*location_t*/ loc, tree fndecl, void *arglist), NULL) +DEFHOOK +(check_builtin_call, + "Perform semantic checking on a call to a machine-specific built-in\n\ +function after its arguments have been constrained to the function\n\ +signature. Return true if the call is valid, otherwise report an error\n\ +and return false.\n\ +\n\ +This hook is called after @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}.\n\ +The call was originally to built-in function @var{orig_fndecl},\n\ +but after the optional @code{TARGET_RESOLVE_OVERLOADED_BUILTIN}\n\ +step is now to built-in function @var{fndecl}. @var{loc} is the\n\ +location of the call and @var{args} is an array of function arguments,\n\ +of which there are @var{nargs}. @var{arg_loc} specifies the location\n\ +of each argument.", + bool, (location_t loc, vec<location_t> arg_loc, tree fndecl, + tree orig_fndecl, unsigned int nargs, tree *args), + NULL) + /* Fold a target-specific builtin to a tree valid for both GIMPLE and GENERIC. */ DEFHOOK diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_1.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_1.C new file mode 100644 index 00000000000..a73934f5668 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_1.C @@ -0,0 +1,39 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_add (uint64_t a, uint64_t b) { return a + b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +void +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svint16_t s16, + svint32_t s32, svint64_t s64, int x) +{ + const int one = 1; + u8 = svasrd_x (pg, u8, 1); /* { dg-error {no matching function for call to 'svasrd_x\(svbool_t&, svuint8_t&, [^)]*\)'} } */ + s8 = svasrd_x (pg, s8, x); /* { dg-error "argument 3 of 'svasrd_x' must be an integer constant expression" } */ + s8 = svasrd_x (pg, s8, one); + s8 = svasrd_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1.0); + s8 = svasrd_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1); + s8 = svasrd_x (pg, s8, 1 + 1); + s8 = svasrd_x (pg, s8, const_add (1, 1)); + s8 = svasrd_x (pg, s8, add (1, 1)); /* { dg-error "argument 3 of 'svasrd_x' must be an integer constant expression" } */ + s8 = svasrd_x (pg, s8, 8); + s8 = svasrd_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, (uint64_t (1) << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_x (pg, s16, 1); + s16 = svasrd_x (pg, s16, 16); + s16 = svasrd_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_x (pg, s32, 1); + s32 = svasrd_x (pg, s32, 32); + s32 = svasrd_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_x (pg, s64, 1); + s64 = svasrd_x (pg, s64, 64); + s64 = svasrd_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_2.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_2.C new file mode 100644 index 00000000000..bbe7ba72bfa --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_2.C @@ -0,0 +1,38 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_add (uint64_t a, uint64_t b) { return a + b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +void +f1 (svbool_t pg, svint8_t s8, svint16_t s16, svint32_t s32, svint64_t s64, + int x) +{ + const int one = 1; + s8 = svasrd_n_s8_x (pg, s8, x); /* { dg-error "argument 3 of 'svasrd_n_s8_x' must be an integer constant expression" } */ + s8 = svasrd_n_s8_x (pg, s8, one); + s8 = svasrd_n_s8_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1.0); + s8 = svasrd_n_s8_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1); + s8 = svasrd_n_s8_x (pg, s8, 1 + 1); + s8 = svasrd_n_s8_x (pg, s8, const_add (1, 1)); + s8 = svasrd_n_s8_x (pg, s8, add (1, 1)); /* { dg-error "argument 3 of 'svasrd_n_s8_x' must be an integer constant expression" } */ + s8 = svasrd_n_s8_x (pg, s8, 8); + s8 = svasrd_n_s8_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, (uint64_t (1) << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 1); + s16 = svasrd_n_s16_x (pg, s16, 16); + s16 = svasrd_n_s16_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 1); + s32 = svasrd_n_s32_x (pg, s32, 32); + s32 = svasrd_n_s32_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 1); + s64 = svasrd_n_s64_x (pg, s64, 64); + s64 = svasrd_n_s64_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_3.C b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_3.C new file mode 100644 index 00000000000..5ebd770b272 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sve-acle/general-c++/asrd_3.C @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c++11 -Wall -Wextra" } */ + +#include <arm_sve.h> + +constexpr uint64_t const_add (uint64_t a, uint64_t b) { return a + b; } +uint64_t add (uint64_t a, uint64_t b) { return a + b; } + +template<uint64_t N, typename T> +T shift (svbool_t pg, T v) { return svasrd_x (pg, v, N); } +/* { dg-error {no matching function for call to 'svasrd_x\(svbool_t&,} "" { target *-*-* } .-1 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} "" { target *-*-* } .-2 } */ +/* { dg-error {passing 9 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} "" { target *-*-* } .-3 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} "" { target *-*-* } .-4 } */ +/* { dg-error {passing 17 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} "" { target *-*-* } .-5 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} "" { target *-*-* } .-6 } */ +/* { dg-error {passing 33 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} "" { target *-*-* } .-7 } */ +/* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} "" { target *-*-* } .-8 } */ +/* { dg-error {passing 65 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} "" { target *-*-* } .-9 } */ + +template<typename T> +T shift1 (svbool_t pg, T v, uint64_t n) { return svasrd_x (pg, v, n); } + +template<typename T> +T shift2 (svbool_t pg, T v, uint64_t n) { return svasrd_x (pg, v, n); } +/* { dg-error {argument 3 of 'svasrd_x' must be an integer constant expression} "" { target *-*-* } .-1 } */ + +void +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svint16_t s16, + svint32_t s32, svint64_t s64) +{ + u8 = shift <1> (pg, u8); + s8 = shift <0> (pg, s8); + s8 = shift <1> (pg, s8); + s8 = shift <8> (pg, s8); + s8 = shift <9> (pg, s8); + s16 = shift <0> (pg, s16); + s16 = shift <1> (pg, s16); + s16 = shift <16> (pg, s16); + s16 = shift <17> (pg, s16); + s32 = shift <0> (pg, s32); + s32 = shift <1> (pg, s32); + s32 = shift <32> (pg, s32); + s32 = shift <33> (pg, s32); + s64 = shift <0> (pg, s64); + s64 = shift <1> (pg, s64); + s64 = shift <64> (pg, s64); + s64 = shift <65> (pg, s64); + + s8 = shift2 (pg, s8, 1); +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s16.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s16.c new file mode 100644 index 00000000000..6cad5d98aa9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s16.c @@ -0,0 +1,178 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** asrd_1_s16_m_tied1: +** asrd z0\.h, p0/m, z0\.h, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s16_m_tied1, svint16_t, + z0 = svasrd_n_s16_m (p0, z0, 1), + z0 = svasrd_m (p0, z0, 1)) + +/* +** asrd_1_s16_m_untied: +** movprfx z1, z0 +** asrd z1\.h, p0/m, z1\.h, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s16_m_untied, svint16_t, + z1 = svasrd_n_s16_m (p0, z0, 1), + z1 = svasrd_m (p0, z0, 1)) + +/* +** asrd_2_s16_m_tied1: +** asrd z0\.h, p0/m, z0\.h, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s16_m_tied1, svint16_t, + z0 = svasrd_n_s16_m (p0, z0, 2), + z0 = svasrd_m (p0, z0, 2)) + +/* +** asrd_2_s16_m_untied: +** movprfx z1, z0 +** asrd z1\.h, p0/m, z1\.h, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s16_m_untied, svint16_t, + z1 = svasrd_n_s16_m (p0, z0, 2), + z1 = svasrd_m (p0, z0, 2)) + +/* +** asrd_16_s16_m_tied1: +** asrd z0\.h, p0/m, z0\.h, #16 +** ret +*/ +TEST_UNIFORM_Z (asrd_16_s16_m_tied1, svint16_t, + z0 = svasrd_n_s16_m (p0, z0, 16), + z0 = svasrd_m (p0, z0, 16)) + +/* +** asrd_16_s16_m_untied: +** movprfx z1, z0 +** asrd z1\.h, p0/m, z1\.h, #16 +** ret +*/ +TEST_UNIFORM_Z (asrd_16_s16_m_untied, svint16_t, + z1 = svasrd_n_s16_m (p0, z0, 16), + z1 = svasrd_m (p0, z0, 16)) + +/* +** asrd_1_s16_z_tied1: +** movprfx z0\.h, p0/z, z0\.h +** asrd z0\.h, p0/m, z0\.h, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s16_z_tied1, svint16_t, + z0 = svasrd_n_s16_z (p0, z0, 1), + z0 = svasrd_z (p0, z0, 1)) + +/* +** asrd_1_s16_z_untied: +** movprfx z1\.h, p0/z, z0\.h +** asrd z1\.h, p0/m, z1\.h, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s16_z_untied, svint16_t, + z1 = svasrd_n_s16_z (p0, z0, 1), + z1 = svasrd_z (p0, z0, 1)) + +/* +** asrd_2_s16_z_tied1: +** movprfx z0\.h, p0/z, z0\.h +** asrd z0\.h, p0/m, z0\.h, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s16_z_tied1, svint16_t, + z0 = svasrd_n_s16_z (p0, z0, 2), + z0 = svasrd_z (p0, z0, 2)) + +/* +** asrd_2_s16_z_untied: +** movprfx z1\.h, p0/z, z0\.h +** asrd z1\.h, p0/m, z1\.h, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s16_z_untied, svint16_t, + z1 = svasrd_n_s16_z (p0, z0, 2), + z1 = svasrd_z (p0, z0, 2)) + +/* +** asrd_16_s16_z_tied1: +** movprfx z0\.h, p0/z, z0\.h +** asrd z0\.h, p0/m, z0\.h, #16 +** ret +*/ +TEST_UNIFORM_Z (asrd_16_s16_z_tied1, svint16_t, + z0 = svasrd_n_s16_z (p0, z0, 16), + z0 = svasrd_z (p0, z0, 16)) + +/* +** asrd_16_s16_z_untied: +** movprfx z1\.h, p0/z, z0\.h +** asrd z1\.h, p0/m, z1\.h, #16 +** ret +*/ +TEST_UNIFORM_Z (asrd_16_s16_z_untied, svint16_t, + z1 = svasrd_n_s16_z (p0, z0, 16), + z1 = svasrd_z (p0, z0, 16)) + +/* +** asrd_1_s16_x_tied1: +** asrd z0\.h, p0/m, z0\.h, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s16_x_tied1, svint16_t, + z0 = svasrd_n_s16_x (p0, z0, 1), + z0 = svasrd_x (p0, z0, 1)) + +/* +** asrd_1_s16_x_untied: +** movprfx z1, z0 +** asrd z1\.h, p0/m, z1\.h, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s16_x_untied, svint16_t, + z1 = svasrd_n_s16_x (p0, z0, 1), + z1 = svasrd_x (p0, z0, 1)) + +/* +** asrd_2_s16_x_tied1: +** asrd z0\.h, p0/m, z0\.h, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s16_x_tied1, svint16_t, + z0 = svasrd_n_s16_x (p0, z0, 2), + z0 = svasrd_x (p0, z0, 2)) + +/* +** asrd_2_s16_x_untied: +** movprfx z1, z0 +** asrd z1\.h, p0/m, z1\.h, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s16_x_untied, svint16_t, + z1 = svasrd_n_s16_x (p0, z0, 2), + z1 = svasrd_x (p0, z0, 2)) + +/* +** asrd_16_s16_x_tied1: +** asrd z0\.h, p0/m, z0\.h, #16 +** ret +*/ +TEST_UNIFORM_Z (asrd_16_s16_x_tied1, svint16_t, + z0 = svasrd_n_s16_x (p0, z0, 16), + z0 = svasrd_x (p0, z0, 16)) + +/* +** asrd_16_s16_x_untied: +** movprfx z1, z0 +** asrd z1\.h, p0/m, z1\.h, #16 +** ret +*/ +TEST_UNIFORM_Z (asrd_16_s16_x_untied, svint16_t, + z1 = svasrd_n_s16_x (p0, z0, 16), + z1 = svasrd_x (p0, z0, 16)) diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s32.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s32.c new file mode 100644 index 00000000000..9187e554b4f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s32.c @@ -0,0 +1,178 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** asrd_1_s32_m_tied1: +** asrd z0\.s, p0/m, z0\.s, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s32_m_tied1, svint32_t, + z0 = svasrd_n_s32_m (p0, z0, 1), + z0 = svasrd_m (p0, z0, 1)) + +/* +** asrd_1_s32_m_untied: +** movprfx z1, z0 +** asrd z1\.s, p0/m, z1\.s, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s32_m_untied, svint32_t, + z1 = svasrd_n_s32_m (p0, z0, 1), + z1 = svasrd_m (p0, z0, 1)) + +/* +** asrd_2_s32_m_tied1: +** asrd z0\.s, p0/m, z0\.s, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s32_m_tied1, svint32_t, + z0 = svasrd_n_s32_m (p0, z0, 2), + z0 = svasrd_m (p0, z0, 2)) + +/* +** asrd_2_s32_m_untied: +** movprfx z1, z0 +** asrd z1\.s, p0/m, z1\.s, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s32_m_untied, svint32_t, + z1 = svasrd_n_s32_m (p0, z0, 2), + z1 = svasrd_m (p0, z0, 2)) + +/* +** asrd_32_s32_m_tied1: +** asrd z0\.s, p0/m, z0\.s, #32 +** ret +*/ +TEST_UNIFORM_Z (asrd_32_s32_m_tied1, svint32_t, + z0 = svasrd_n_s32_m (p0, z0, 32), + z0 = svasrd_m (p0, z0, 32)) + +/* +** asrd_32_s32_m_untied: +** movprfx z1, z0 +** asrd z1\.s, p0/m, z1\.s, #32 +** ret +*/ +TEST_UNIFORM_Z (asrd_32_s32_m_untied, svint32_t, + z1 = svasrd_n_s32_m (p0, z0, 32), + z1 = svasrd_m (p0, z0, 32)) + +/* +** asrd_1_s32_z_tied1: +** movprfx z0\.s, p0/z, z0\.s +** asrd z0\.s, p0/m, z0\.s, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s32_z_tied1, svint32_t, + z0 = svasrd_n_s32_z (p0, z0, 1), + z0 = svasrd_z (p0, z0, 1)) + +/* +** asrd_1_s32_z_untied: +** movprfx z1\.s, p0/z, z0\.s +** asrd z1\.s, p0/m, z1\.s, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s32_z_untied, svint32_t, + z1 = svasrd_n_s32_z (p0, z0, 1), + z1 = svasrd_z (p0, z0, 1)) + +/* +** asrd_2_s32_z_tied1: +** movprfx z0\.s, p0/z, z0\.s +** asrd z0\.s, p0/m, z0\.s, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s32_z_tied1, svint32_t, + z0 = svasrd_n_s32_z (p0, z0, 2), + z0 = svasrd_z (p0, z0, 2)) + +/* +** asrd_2_s32_z_untied: +** movprfx z1\.s, p0/z, z0\.s +** asrd z1\.s, p0/m, z1\.s, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s32_z_untied, svint32_t, + z1 = svasrd_n_s32_z (p0, z0, 2), + z1 = svasrd_z (p0, z0, 2)) + +/* +** asrd_32_s32_z_tied1: +** movprfx z0\.s, p0/z, z0\.s +** asrd z0\.s, p0/m, z0\.s, #32 +** ret +*/ +TEST_UNIFORM_Z (asrd_32_s32_z_tied1, svint32_t, + z0 = svasrd_n_s32_z (p0, z0, 32), + z0 = svasrd_z (p0, z0, 32)) + +/* +** asrd_32_s32_z_untied: +** movprfx z1\.s, p0/z, z0\.s +** asrd z1\.s, p0/m, z1\.s, #32 +** ret +*/ +TEST_UNIFORM_Z (asrd_32_s32_z_untied, svint32_t, + z1 = svasrd_n_s32_z (p0, z0, 32), + z1 = svasrd_z (p0, z0, 32)) + +/* +** asrd_1_s32_x_tied1: +** asrd z0\.s, p0/m, z0\.s, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s32_x_tied1, svint32_t, + z0 = svasrd_n_s32_x (p0, z0, 1), + z0 = svasrd_x (p0, z0, 1)) + +/* +** asrd_1_s32_x_untied: +** movprfx z1, z0 +** asrd z1\.s, p0/m, z1\.s, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s32_x_untied, svint32_t, + z1 = svasrd_n_s32_x (p0, z0, 1), + z1 = svasrd_x (p0, z0, 1)) + +/* +** asrd_2_s32_x_tied1: +** asrd z0\.s, p0/m, z0\.s, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s32_x_tied1, svint32_t, + z0 = svasrd_n_s32_x (p0, z0, 2), + z0 = svasrd_x (p0, z0, 2)) + +/* +** asrd_2_s32_x_untied: +** movprfx z1, z0 +** asrd z1\.s, p0/m, z1\.s, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s32_x_untied, svint32_t, + z1 = svasrd_n_s32_x (p0, z0, 2), + z1 = svasrd_x (p0, z0, 2)) + +/* +** asrd_32_s32_x_tied1: +** asrd z0\.s, p0/m, z0\.s, #32 +** ret +*/ +TEST_UNIFORM_Z (asrd_32_s32_x_tied1, svint32_t, + z0 = svasrd_n_s32_x (p0, z0, 32), + z0 = svasrd_x (p0, z0, 32)) + +/* +** asrd_32_s32_x_untied: +** movprfx z1, z0 +** asrd z1\.s, p0/m, z1\.s, #32 +** ret +*/ +TEST_UNIFORM_Z (asrd_32_s32_x_untied, svint32_t, + z1 = svasrd_n_s32_x (p0, z0, 32), + z1 = svasrd_x (p0, z0, 32)) diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s64.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s64.c new file mode 100644 index 00000000000..40e9c5c09a2 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s64.c @@ -0,0 +1,178 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** asrd_1_s64_m_tied1: +** asrd z0\.d, p0/m, z0\.d, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s64_m_tied1, svint64_t, + z0 = svasrd_n_s64_m (p0, z0, 1), + z0 = svasrd_m (p0, z0, 1)) + +/* +** asrd_1_s64_m_untied: +** movprfx z1, z0 +** asrd z1\.d, p0/m, z1\.d, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s64_m_untied, svint64_t, + z1 = svasrd_n_s64_m (p0, z0, 1), + z1 = svasrd_m (p0, z0, 1)) + +/* +** asrd_2_s64_m_tied1: +** asrd z0\.d, p0/m, z0\.d, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s64_m_tied1, svint64_t, + z0 = svasrd_n_s64_m (p0, z0, 2), + z0 = svasrd_m (p0, z0, 2)) + +/* +** asrd_2_s64_m_untied: +** movprfx z1, z0 +** asrd z1\.d, p0/m, z1\.d, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s64_m_untied, svint64_t, + z1 = svasrd_n_s64_m (p0, z0, 2), + z1 = svasrd_m (p0, z0, 2)) + +/* +** asrd_64_s64_m_tied1: +** asrd z0\.d, p0/m, z0\.d, #64 +** ret +*/ +TEST_UNIFORM_Z (asrd_64_s64_m_tied1, svint64_t, + z0 = svasrd_n_s64_m (p0, z0, 64), + z0 = svasrd_m (p0, z0, 64)) + +/* +** asrd_64_s64_m_untied: +** movprfx z1, z0 +** asrd z1\.d, p0/m, z1\.d, #64 +** ret +*/ +TEST_UNIFORM_Z (asrd_64_s64_m_untied, svint64_t, + z1 = svasrd_n_s64_m (p0, z0, 64), + z1 = svasrd_m (p0, z0, 64)) + +/* +** asrd_1_s64_z_tied1: +** movprfx z0\.d, p0/z, z0\.d +** asrd z0\.d, p0/m, z0\.d, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s64_z_tied1, svint64_t, + z0 = svasrd_n_s64_z (p0, z0, 1), + z0 = svasrd_z (p0, z0, 1)) + +/* +** asrd_1_s64_z_untied: +** movprfx z1\.d, p0/z, z0\.d +** asrd z1\.d, p0/m, z1\.d, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s64_z_untied, svint64_t, + z1 = svasrd_n_s64_z (p0, z0, 1), + z1 = svasrd_z (p0, z0, 1)) + +/* +** asrd_2_s64_z_tied1: +** movprfx z0\.d, p0/z, z0\.d +** asrd z0\.d, p0/m, z0\.d, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s64_z_tied1, svint64_t, + z0 = svasrd_n_s64_z (p0, z0, 2), + z0 = svasrd_z (p0, z0, 2)) + +/* +** asrd_2_s64_z_untied: +** movprfx z1\.d, p0/z, z0\.d +** asrd z1\.d, p0/m, z1\.d, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s64_z_untied, svint64_t, + z1 = svasrd_n_s64_z (p0, z0, 2), + z1 = svasrd_z (p0, z0, 2)) + +/* +** asrd_64_s64_z_tied1: +** movprfx z0\.d, p0/z, z0\.d +** asrd z0\.d, p0/m, z0\.d, #64 +** ret +*/ +TEST_UNIFORM_Z (asrd_64_s64_z_tied1, svint64_t, + z0 = svasrd_n_s64_z (p0, z0, 64), + z0 = svasrd_z (p0, z0, 64)) + +/* +** asrd_64_s64_z_untied: +** movprfx z1\.d, p0/z, z0\.d +** asrd z1\.d, p0/m, z1\.d, #64 +** ret +*/ +TEST_UNIFORM_Z (asrd_64_s64_z_untied, svint64_t, + z1 = svasrd_n_s64_z (p0, z0, 64), + z1 = svasrd_z (p0, z0, 64)) + +/* +** asrd_1_s64_x_tied1: +** asrd z0\.d, p0/m, z0\.d, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s64_x_tied1, svint64_t, + z0 = svasrd_n_s64_x (p0, z0, 1), + z0 = svasrd_x (p0, z0, 1)) + +/* +** asrd_1_s64_x_untied: +** movprfx z1, z0 +** asrd z1\.d, p0/m, z1\.d, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s64_x_untied, svint64_t, + z1 = svasrd_n_s64_x (p0, z0, 1), + z1 = svasrd_x (p0, z0, 1)) + +/* +** asrd_2_s64_x_tied1: +** asrd z0\.d, p0/m, z0\.d, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s64_x_tied1, svint64_t, + z0 = svasrd_n_s64_x (p0, z0, 2), + z0 = svasrd_x (p0, z0, 2)) + +/* +** asrd_2_s64_x_untied: +** movprfx z1, z0 +** asrd z1\.d, p0/m, z1\.d, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s64_x_untied, svint64_t, + z1 = svasrd_n_s64_x (p0, z0, 2), + z1 = svasrd_x (p0, z0, 2)) + +/* +** asrd_64_s64_x_tied1: +** asrd z0\.d, p0/m, z0\.d, #64 +** ret +*/ +TEST_UNIFORM_Z (asrd_64_s64_x_tied1, svint64_t, + z0 = svasrd_n_s64_x (p0, z0, 64), + z0 = svasrd_x (p0, z0, 64)) + +/* +** asrd_64_s64_x_untied: +** movprfx z1, z0 +** asrd z1\.d, p0/m, z1\.d, #64 +** ret +*/ +TEST_UNIFORM_Z (asrd_64_s64_x_untied, svint64_t, + z1 = svasrd_n_s64_x (p0, z0, 64), + z1 = svasrd_x (p0, z0, 64)) diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s8.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s8.c new file mode 100644 index 00000000000..ad6e372bde4 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/asm/asrd_s8.c @@ -0,0 +1,178 @@ +/* { dg-do compile } */ +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ + +#include "test_sve_acle.h" + +/* +** asrd_1_s8_m_tied1: +** asrd z0\.b, p0/m, z0\.b, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s8_m_tied1, svint8_t, + z0 = svasrd_n_s8_m (p0, z0, 1), + z0 = svasrd_m (p0, z0, 1)) + +/* +** asrd_1_s8_m_untied: +** movprfx z1, z0 +** asrd z1\.b, p0/m, z1\.b, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s8_m_untied, svint8_t, + z1 = svasrd_n_s8_m (p0, z0, 1), + z1 = svasrd_m (p0, z0, 1)) + +/* +** asrd_2_s8_m_tied1: +** asrd z0\.b, p0/m, z0\.b, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s8_m_tied1, svint8_t, + z0 = svasrd_n_s8_m (p0, z0, 2), + z0 = svasrd_m (p0, z0, 2)) + +/* +** asrd_2_s8_m_untied: +** movprfx z1, z0 +** asrd z1\.b, p0/m, z1\.b, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s8_m_untied, svint8_t, + z1 = svasrd_n_s8_m (p0, z0, 2), + z1 = svasrd_m (p0, z0, 2)) + +/* +** asrd_8_s8_m_tied1: +** asrd z0\.b, p0/m, z0\.b, #8 +** ret +*/ +TEST_UNIFORM_Z (asrd_8_s8_m_tied1, svint8_t, + z0 = svasrd_n_s8_m (p0, z0, 8), + z0 = svasrd_m (p0, z0, 8)) + +/* +** asrd_8_s8_m_untied: +** movprfx z1, z0 +** asrd z1\.b, p0/m, z1\.b, #8 +** ret +*/ +TEST_UNIFORM_Z (asrd_8_s8_m_untied, svint8_t, + z1 = svasrd_n_s8_m (p0, z0, 8), + z1 = svasrd_m (p0, z0, 8)) + +/* +** asrd_1_s8_z_tied1: +** movprfx z0\.b, p0/z, z0\.b +** asrd z0\.b, p0/m, z0\.b, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s8_z_tied1, svint8_t, + z0 = svasrd_n_s8_z (p0, z0, 1), + z0 = svasrd_z (p0, z0, 1)) + +/* +** asrd_1_s8_z_untied: +** movprfx z1\.b, p0/z, z0\.b +** asrd z1\.b, p0/m, z1\.b, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s8_z_untied, svint8_t, + z1 = svasrd_n_s8_z (p0, z0, 1), + z1 = svasrd_z (p0, z0, 1)) + +/* +** asrd_2_s8_z_tied1: +** movprfx z0\.b, p0/z, z0\.b +** asrd z0\.b, p0/m, z0\.b, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s8_z_tied1, svint8_t, + z0 = svasrd_n_s8_z (p0, z0, 2), + z0 = svasrd_z (p0, z0, 2)) + +/* +** asrd_2_s8_z_untied: +** movprfx z1\.b, p0/z, z0\.b +** asrd z1\.b, p0/m, z1\.b, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s8_z_untied, svint8_t, + z1 = svasrd_n_s8_z (p0, z0, 2), + z1 = svasrd_z (p0, z0, 2)) + +/* +** asrd_8_s8_z_tied1: +** movprfx z0\.b, p0/z, z0\.b +** asrd z0\.b, p0/m, z0\.b, #8 +** ret +*/ +TEST_UNIFORM_Z (asrd_8_s8_z_tied1, svint8_t, + z0 = svasrd_n_s8_z (p0, z0, 8), + z0 = svasrd_z (p0, z0, 8)) + +/* +** asrd_8_s8_z_untied: +** movprfx z1\.b, p0/z, z0\.b +** asrd z1\.b, p0/m, z1\.b, #8 +** ret +*/ +TEST_UNIFORM_Z (asrd_8_s8_z_untied, svint8_t, + z1 = svasrd_n_s8_z (p0, z0, 8), + z1 = svasrd_z (p0, z0, 8)) + +/* +** asrd_1_s8_x_tied1: +** asrd z0\.b, p0/m, z0\.b, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s8_x_tied1, svint8_t, + z0 = svasrd_n_s8_x (p0, z0, 1), + z0 = svasrd_x (p0, z0, 1)) + +/* +** asrd_1_s8_x_untied: +** movprfx z1, z0 +** asrd z1\.b, p0/m, z1\.b, #1 +** ret +*/ +TEST_UNIFORM_Z (asrd_1_s8_x_untied, svint8_t, + z1 = svasrd_n_s8_x (p0, z0, 1), + z1 = svasrd_x (p0, z0, 1)) + +/* +** asrd_2_s8_x_tied1: +** asrd z0\.b, p0/m, z0\.b, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s8_x_tied1, svint8_t, + z0 = svasrd_n_s8_x (p0, z0, 2), + z0 = svasrd_x (p0, z0, 2)) + +/* +** asrd_2_s8_x_untied: +** movprfx z1, z0 +** asrd z1\.b, p0/m, z1\.b, #2 +** ret +*/ +TEST_UNIFORM_Z (asrd_2_s8_x_untied, svint8_t, + z1 = svasrd_n_s8_x (p0, z0, 2), + z1 = svasrd_x (p0, z0, 2)) + +/* +** asrd_8_s8_x_tied1: +** asrd z0\.b, p0/m, z0\.b, #8 +** ret +*/ +TEST_UNIFORM_Z (asrd_8_s8_x_tied1, svint8_t, + z0 = svasrd_n_s8_x (p0, z0, 8), + z0 = svasrd_x (p0, z0, 8)) + +/* +** asrd_8_s8_x_untied: +** movprfx z1, z0 +** asrd z1\.b, p0/m, z1\.b, #8 +** ret +*/ +TEST_UNIFORM_Z (asrd_8_s8_x_untied, svint8_t, + z1 = svasrd_n_s8_x (p0, z0, 8), + z1 = svasrd_x (p0, z0, 8)) diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/asrd_1.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/asrd_1.c new file mode 100644 index 00000000000..c2c655ae499 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/asrd_1.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svuint8_t u8, svint8_t s8, svint16_t s16, + svint32_t s32, svint64_t s64, int x) +{ + const int one = 1; + u8 = svasrd_x (pg, u8, 1); /* { dg-error "'svasrd_x' has no form that takes 'svuint8_t' arguments" } */ + s8 = svasrd_x (pg, s8, x); /* { dg-error "argument 3 of 'svasrd_x' must be an integer constant expression" } */ + s8 = svasrd_x (pg, s8, one); /* { dg-error "argument 3 of 'svasrd_x' must be an integer constant expression" } */ + s8 = svasrd_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1.0); + s8 = svasrd_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, 1); + s8 = svasrd_x (pg, s8, 1 + 1); + s8 = svasrd_x (pg, s8, 8); + s8 = svasrd_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_x (pg, s8, (1ULL << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_x (pg, s16, 1); + s16 = svasrd_x (pg, s16, 16); + s16 = svasrd_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_x (pg, s32, 1); + s32 = svasrd_x (pg, s32, 32); + s32 = svasrd_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_x (pg, s64, 1); + s64 = svasrd_x (pg, s64, 64); + s64 = svasrd_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_x', which expects a value in the range \[1, 64\]} } */ +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/asrd_2.c b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/asrd_2.c new file mode 100644 index 00000000000..b0738450b1b --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve-acle/general-c/asrd_2.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-std=c99 -Wall -Wextra" } */ + +#include <arm_sve.h> + +void +f1 (svbool_t pg, svint8_t s8, svint16_t s16, svint32_t s32, svint64_t s64, + int x) +{ + const int one = 1; + s8 = svasrd_n_s8_x (pg, s8, x); /* { dg-error "argument 3 of 'svasrd_n_s8_x' must be an integer constant expression" } */ + s8 = svasrd_n_s8_x (pg, s8, one); /* { dg-error "argument 3 of 'svasrd_n_s8_x' must be an integer constant expression" } */ + s8 = svasrd_n_s8_x (pg, s8, 0.4); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1.0); + s8 = svasrd_n_s8_x (pg, s8, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, 1); + s8 = svasrd_n_s8_x (pg, s8, 1 + 1); + s8 = svasrd_n_s8_x (pg, s8, 8); + s8 = svasrd_n_s8_x (pg, s8, 9); /* { dg-error {passing 9 to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s8 = svasrd_n_s8_x (pg, s8, (1ULL << 62) + 1); /* { dg-error {passing [^ ]* to argument 3 of 'svasrd_n_s8_x', which expects a value in the range \[1, 8\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s16 = svasrd_n_s16_x (pg, s16, 1); + s16 = svasrd_n_s16_x (pg, s16, 16); + s16 = svasrd_n_s16_x (pg, s16, 17); /* { dg-error {passing 17 to argument 3 of 'svasrd_n_s16_x', which expects a value in the range \[1, 16\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s32 = svasrd_n_s32_x (pg, s32, 1); + s32 = svasrd_n_s32_x (pg, s32, 32); + s32 = svasrd_n_s32_x (pg, s32, 33); /* { dg-error {passing 33 to argument 3 of 'svasrd_n_s32_x', which expects a value in the range \[1, 32\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 0); /* { dg-error {passing 0 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ + s64 = svasrd_n_s64_x (pg, s64, 1); + s64 = svasrd_n_s64_x (pg, s64, 64); + s64 = svasrd_n_s64_x (pg, s64, 65); /* { dg-error {passing 65 to argument 3 of 'svasrd_n_s64_x', which expects a value in the range \[1, 64\]} } */ +}