* [SVE ACLE] Add support for svasrd
@ 2018-08-31 13:58 Richard Sandiford
0 siblings, 0 replies; only message in thread
From: Richard Sandiford @ 2018-08-31 13:58 UTC (permalink / raw)
To: gcc-patches
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\]} } */
+}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2018-08-31 13:58 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-31 13:58 [SVE ACLE] Add support for svasrd Richard Sandiford
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).