Commit 38e62001 by Richard Sandiford

aarch64: Add support for arm_sve_vector_bits

This patch implements the "arm_sve_vector_bits" attribute, which can be
used to create fixed-length versions of an SVE type while maintaining
their "SVEness".  For example, when __ARM_FEATURE_SVE_BITS==256:

typedef svint32_t vec __attribute__((arm_sve_vector_bits(256)));

creates a 256-bit version of svint32_t.

The attribute itself is quite simple.  However, it means that we now
need to implement the full PCS rules for scalable types, whereas
previously we only needed to handle scalable types that were built
directly into the compiler.  See:

  https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst

for more information about these rules.

2020-04-09  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* doc/sourcebuild.texi (aarch64_sve_hw, aarch64_sve128_hw)
	(aarch64_sve256_hw, aarch64_sve512_hw, aarch64_sve1024_hw)
	(aarch64_sve2048_hw): Document.
	* config/aarch64/aarch64-protos.h
	(aarch64_sve::handle_arm_sve_vector_bits_attribute): Declare.
	* config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins): Define
	__ARM_FEATURE_SVE_VECTOR_OPERATIONS when SVE is enabled.
	* config/aarch64/aarch64-sve-builtins.cc (matches_type_p): New
	function.
	(find_type_suffix_for_scalar_type): Use it instead of comparing
	TYPE_MAIN_VARIANTs.
	(function_resolver::infer_vector_or_tuple_type): Likewise.
	(function_resolver::require_vector_type): Likewise.
	(handle_arm_sve_vector_bits_attribute): New function.
	* config/aarch64/aarch64.c (pure_scalable_type_info): New class.
	(aarch64_attribute_table): Add arm_sve_vector_bits.
	(aarch64_return_in_memory_1):
	(pure_scalable_type_info::piece::get_rtx): New function.
	(pure_scalable_type_info::num_zr): Likewise.
	(pure_scalable_type_info::num_pr): Likewise.
	(pure_scalable_type_info::get_rtx): Likewise.
	(pure_scalable_type_info::analyze): Likewise.
	(pure_scalable_type_info::analyze_registers): Likewise.
	(pure_scalable_type_info::analyze_array): Likewise.
	(pure_scalable_type_info::analyze_record): Likewise.
	(pure_scalable_type_info::add_piece): Likewise.
	(aarch64_some_values_include_pst_objects_p): Likewise.
	(aarch64_returns_value_in_sve_regs_p): Use pure_scalable_type_info
	to analyze whether the type is returned in SVE registers.
	(aarch64_takes_arguments_in_sve_regs_p): Likwise whether the type
	is passed in SVE registers.
	(aarch64_pass_by_reference_1): New function, extracted from...
	(aarch64_pass_by_reference): ...here.  Use pure_scalable_type_info
	to analyze whether the type is a pure scalable type and, if so,
	whether it should be passed by reference.
	(aarch64_return_in_msb): Return false for pure scalable types.
	(aarch64_function_value_1): Fold back into...
	(aarch64_function_value): ...this function.  Use
	pure_scalable_type_info to analyze whether the type is a pure
	scalable type and, if so, which registers it should use.  Handle
	types that include pure scalable types but are not themselves
	pure scalable types.
	(aarch64_return_in_memory_1): New function, split out from...
	(aarch64_return_in_memory): ...here.  Use pure_scalable_type_info
	to analyze whether the type is a pure scalable type and, if so,
	whether it should be returned by reference.
	(aarch64_layout_arg): Remove orig_mode argument.  Use
	pure_scalable_type_info to analyze whether the type is a pure
	scalable type and, if so, which registers it should use.  Handle
	types that include pure scalable types but are not themselves
	pure scalable types.
	(aarch64_function_arg): Update call accordingly.
	(aarch64_function_arg_advance): Likewise.
	(aarch64_pad_reg_upward): On big-endian targets, return false for
	pure scalable types that are smaller than 16 bytes.
	(aarch64_member_type_forces_blk): New function.
	(aapcs_vfp_sub_candidate): Exit early for built-in SVE types.
	(aarch64_short_vector_p): Return false for VECTOR_TYPEs that
	correspond to built-in SVE types.  Do not rely on a vector mode
	if the type includes an pure scalable type.  When returning true,
	assert that the mode is not an SVE mode.
	(aarch64_vfp_is_call_or_return_candidate): Do not check for SVE
	built-in types here.  When returning true, assert that the type
	does not have an SVE mode.
	(aarch64_can_change_mode_class): Don't allow anything to change
	between a predicate mode and a non-predicate mode.  Also don't
	allow changes between SVE vector modes and other modes that
	might be bigger than 128 bits.
	(aarch64_invalid_binary_op): Reject binary operations that mix
	SVE and GNU vector types.
	(TARGET_MEMBER_TYPE_FORCES_BLK): Define.

gcc/testsuite/
	* gcc.target/aarch64/sve/acle/general/attributes_1.c: New test.
	* gcc.target/aarch64/sve/acle/general/attributes_2.c: Likewise.
	* gcc.target/aarch64/sve/acle/general/attributes_3.c: Likewise.
	* gcc.target/aarch64/sve/acle/general/attributes_4.c: Likewise.
	* gcc.target/aarch64/sve/acle/general/attributes_5.c: Likewise.
	* gcc.target/aarch64/sve/acle/general/attributes_6.c: Likewise.
	* gcc.target/aarch64/sve/acle/general/attributes_7.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct.h: New file.
	* gcc.target/aarch64/sve/pcs/struct_1_128.c: New test.
	* gcc.target/aarch64/sve/pcs/struct_1_256.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_1_512.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_1_1024.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_1_2048.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_2_128.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_2_256.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_2_512.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_2_1024.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_2_2048.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_3_128.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_3_256.c: Likewise.
	* gcc.target/aarch64/sve/pcs/struct_3_512.c: Likewise.
	* lib/target-supports.exp (check_effective_target_aarch64_sve128_hw)
	(check_effective_target_aarch64_sve512_hw)
	(check_effective_target_aarch64_sve1024_hw)
	(check_effective_target_aarch64_sve2048_hw): New procedures.
parent 5002dae3
2020-04-09 Richard Sandiford <richard.sandiford@arm.com>
* doc/sourcebuild.texi (aarch64_sve_hw, aarch64_sve128_hw)
(aarch64_sve256_hw, aarch64_sve512_hw, aarch64_sve1024_hw)
(aarch64_sve2048_hw): Document.
* config/aarch64/aarch64-protos.h
(aarch64_sve::handle_arm_sve_vector_bits_attribute): Declare.
* config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins): Define
__ARM_FEATURE_SVE_VECTOR_OPERATIONS when SVE is enabled.
* config/aarch64/aarch64-sve-builtins.cc (matches_type_p): New
function.
(find_type_suffix_for_scalar_type): Use it instead of comparing
TYPE_MAIN_VARIANTs.
(function_resolver::infer_vector_or_tuple_type): Likewise.
(function_resolver::require_vector_type): Likewise.
(handle_arm_sve_vector_bits_attribute): New function.
* config/aarch64/aarch64.c (pure_scalable_type_info): New class.
(aarch64_attribute_table): Add arm_sve_vector_bits.
(aarch64_return_in_memory_1):
(pure_scalable_type_info::piece::get_rtx): New function.
(pure_scalable_type_info::num_zr): Likewise.
(pure_scalable_type_info::num_pr): Likewise.
(pure_scalable_type_info::get_rtx): Likewise.
(pure_scalable_type_info::analyze): Likewise.
(pure_scalable_type_info::analyze_registers): Likewise.
(pure_scalable_type_info::analyze_array): Likewise.
(pure_scalable_type_info::analyze_record): Likewise.
(pure_scalable_type_info::add_piece): Likewise.
(aarch64_some_values_include_pst_objects_p): Likewise.
(aarch64_returns_value_in_sve_regs_p): Use pure_scalable_type_info
to analyze whether the type is returned in SVE registers.
(aarch64_takes_arguments_in_sve_regs_p): Likwise whether the type
is passed in SVE registers.
(aarch64_pass_by_reference_1): New function, extracted from...
(aarch64_pass_by_reference): ...here. Use pure_scalable_type_info
to analyze whether the type is a pure scalable type and, if so,
whether it should be passed by reference.
(aarch64_return_in_msb): Return false for pure scalable types.
(aarch64_function_value_1): Fold back into...
(aarch64_function_value): ...this function. Use
pure_scalable_type_info to analyze whether the type is a pure
scalable type and, if so, which registers it should use. Handle
types that include pure scalable types but are not themselves
pure scalable types.
(aarch64_return_in_memory_1): New function, split out from...
(aarch64_return_in_memory): ...here. Use pure_scalable_type_info
to analyze whether the type is a pure scalable type and, if so,
whether it should be returned by reference.
(aarch64_layout_arg): Remove orig_mode argument. Use
pure_scalable_type_info to analyze whether the type is a pure
scalable type and, if so, which registers it should use. Handle
types that include pure scalable types but are not themselves
pure scalable types.
(aarch64_function_arg): Update call accordingly.
(aarch64_function_arg_advance): Likewise.
(aarch64_pad_reg_upward): On big-endian targets, return false for
pure scalable types that are smaller than 16 bytes.
(aarch64_member_type_forces_blk): New function.
(aapcs_vfp_sub_candidate): Exit early for built-in SVE types.
(aarch64_short_vector_p): Return false for VECTOR_TYPEs that
correspond to built-in SVE types. Do not rely on a vector mode
if the type includes an pure scalable type. When returning true,
assert that the mode is not an SVE mode.
(aarch64_vfp_is_call_or_return_candidate): Do not check for SVE
built-in types here. When returning true, assert that the type
does not have an SVE mode.
(aarch64_can_change_mode_class): Don't allow anything to change
between a predicate mode and a non-predicate mode. Also don't
allow changes between SVE vector modes and other modes that
might be bigger than 128 bits.
(aarch64_invalid_binary_op): Reject binary operations that mix
SVE and GNU vector types.
(TARGET_MEMBER_TYPE_FORCES_BLK): Define.
2020-04-09 Richard Sandiford <richard.sandiford@arm.com>
* config/aarch64/aarch64.c (aarch64_attribute_table): Add
"SVE sizeless type".
* config/aarch64/aarch64-sve-builtins.cc (make_type_sizeless)
......
......@@ -149,6 +149,8 @@ aarch64_update_cpp_builtins (cpp_reader *pfile)
bits = 0;
builtin_define_with_int_value ("__ARM_FEATURE_SVE_BITS", bits);
}
aarch64_def_or_undef (TARGET_SVE, "__ARM_FEATURE_SVE_VECTOR_OPERATIONS",
pfile);
aarch64_def_or_undef (TARGET_SVE_I8MM,
"__ARM_FEATURE_SVE_MATMUL_INT8", pfile);
aarch64_def_or_undef (TARGET_SVE_F32MM,
......
......@@ -716,6 +716,7 @@ namespace aarch64_sve {
tree, unsigned int, tree *);
gimple *gimple_fold_builtin (unsigned int, gimple_stmt_iterator *, gcall *);
rtx expand_builtin (unsigned int, tree, rtx);
tree handle_arm_sve_vector_bits_attribute (tree *, tree, tree, int, bool *);
#ifdef GCC_TARGET_H
bool verify_type_context (location_t, type_context_kind, const_tree, bool);
#endif
......
......@@ -602,6 +602,26 @@ sizeless_type_p (const_tree type)
return lookup_attribute ("SVE sizeless type", TYPE_ATTRIBUTES (type));
}
/* Return true if CANDIDATE is equivalent to MODEL_TYPE for overloading
purposes. */
static bool
matches_type_p (const_tree model_type, const_tree candidate)
{
if (VECTOR_TYPE_P (model_type))
{
if (!VECTOR_TYPE_P (candidate)
|| maybe_ne (TYPE_VECTOR_SUBPARTS (model_type),
TYPE_VECTOR_SUBPARTS (candidate))
|| TYPE_MODE (model_type) != TYPE_MODE (candidate))
return false;
model_type = TREE_TYPE (model_type);
candidate = TREE_TYPE (candidate);
}
return (candidate != error_mark_node
&& TYPE_MAIN_VARIANT (model_type) == TYPE_MAIN_VARIANT (candidate));
}
/* If TYPE is a valid SVE element type, return the corresponding type
suffix, otherwise return NUM_TYPE_SUFFIXES. */
static type_suffix_index
......@@ -609,12 +629,11 @@ find_type_suffix_for_scalar_type (const_tree type)
{
/* A linear search should be OK here, since the code isn't hot and
the number of types is only small. */
type = TYPE_MAIN_VARIANT (type);
for (unsigned int suffix_i = 0; suffix_i < NUM_TYPE_SUFFIXES; ++suffix_i)
if (!type_suffixes[suffix_i].bool_p)
{
vector_type_index vector_i = type_suffixes[suffix_i].vector_type;
if (type == TYPE_MAIN_VARIANT (scalar_types[vector_i]))
if (matches_type_p (scalar_types[vector_i], type))
return type_suffix_index (suffix_i);
}
return NUM_TYPE_SUFFIXES;
......@@ -1273,7 +1292,7 @@ function_resolver::infer_vector_or_tuple_type (unsigned int argno,
{
vector_type_index type_i = type_suffixes[suffix_i].vector_type;
tree type = acle_vector_types[size_i][type_i];
if (type && TYPE_MAIN_VARIANT (actual) == TYPE_MAIN_VARIANT (type))
if (type && matches_type_p (type, actual))
{
if (size_i + 1 == num_vectors)
return type_suffix_index (suffix_i);
......@@ -1411,8 +1430,7 @@ function_resolver::require_vector_type (unsigned int argno,
{
tree expected = acle_vector_types[0][type];
tree actual = get_argument_type (argno);
if (actual != error_mark_node
&& TYPE_MAIN_VARIANT (expected) != TYPE_MAIN_VARIANT (actual))
if (!matches_type_p (expected, actual))
{
error_at (location, "passing %qT to argument %d of %qE, which"
" expects %qT", actual, argno + 1, fndecl, expected);
......@@ -3592,6 +3610,61 @@ builtin_type_p (const_tree type, unsigned int *num_zr, unsigned int *num_pr)
return false;
}
/* An attribute callback for the "arm_sve_vector_bits" attribute. */
tree
handle_arm_sve_vector_bits_attribute (tree *node, tree, tree args, int,
bool *no_add_attrs)
{
*no_add_attrs = true;
tree type = *node;
if (!VECTOR_TYPE_P (type) || !builtin_type_p (type))
{
error ("%qs applied to non-SVE type %qT", "arm_sve_vector_bits", type);
return NULL_TREE;
}
tree size = TREE_VALUE (args);
if (TREE_CODE (size) != INTEGER_CST)
{
error ("%qs requires an integer constant expression",
"arm_sve_vector_bits");
return NULL_TREE;
}
unsigned HOST_WIDE_INT value = tree_to_uhwi (size);
if (maybe_ne (value, BITS_PER_SVE_VECTOR))
{
warning (OPT_Wattributes, "unsupported SVE vector size");
return NULL_TREE;
}
/* FIXME: The type ought to be a distinct copy in all cases, but
currently that makes the C frontend reject conversions between
svbool_t and its fixed-length variants. Using a type variant
avoids that but means that we treat some ambiguous combinations
as valid. */
if (lang_GNU_C () && VECTOR_BOOLEAN_TYPE_P (type))
type = build_variant_type_copy (type);
else
type = build_distinct_type_copy (type);
/* The new type is a normal sized type; it doesn't have the same
restrictions as sizeless types. */
TYPE_ATTRIBUTES (type)
= remove_attribute ("SVE sizeless type",
copy_list (TYPE_ATTRIBUTES (type)));
/* Allow the GNU vector extensions to be applied to vectors.
The extensions aren't yet defined for packed predicates,
so continue to treat them as abstract entities for now. */
if (!VECTOR_BOOLEAN_TYPE_P (type))
TYPE_INDIVISIBLE_P (type) = 0;
*node = type;
return NULL_TREE;
}
/* Implement TARGET_VERIFY_TYPE_CONTEXT for SVE types. */
bool
verify_type_context (location_t loc, type_context_kind context,
......
......@@ -1992,6 +1992,15 @@ AArch64 target which generates instruction sequences for big endian.
@item aarch64_small_fpic
Binutils installed on test system supports relocation types required by -fpic
for AArch64 small memory model.
@item aarch64_sve_hw
AArch64 target that is able to generate and execute SVE code (regardless of
whether it does so by default).
@item aarch64_sve128_hw
@itemx aarch64_sve256_hw
@itemx aarch64_sve512_hw
@itemx aarch64_sve1024_hw
@itemx aarch64_sve2048_hw
Like @code{aarch64_sve_hw}, but also test for an exact hardware vector length.
@end table
......
2020-04-09 Richard Sandiford <richard.sandiford@arm.com>
* gcc.target/aarch64/sve/acle/general/attributes_1.c: New test.
* gcc.target/aarch64/sve/acle/general/attributes_2.c: Likewise.
* gcc.target/aarch64/sve/acle/general/attributes_3.c: Likewise.
* gcc.target/aarch64/sve/acle/general/attributes_4.c: Likewise.
* gcc.target/aarch64/sve/acle/general/attributes_5.c: Likewise.
* gcc.target/aarch64/sve/acle/general/attributes_6.c: Likewise.
* gcc.target/aarch64/sve/acle/general/attributes_7.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct.h: New file.
* gcc.target/aarch64/sve/pcs/struct_1_128.c: New test.
* gcc.target/aarch64/sve/pcs/struct_1_256.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_1_512.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_1_1024.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_1_2048.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_2_128.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_2_256.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_2_512.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_2_1024.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_2_2048.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_3_128.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_3_256.c: Likewise.
* gcc.target/aarch64/sve/pcs/struct_3_512.c: Likewise.
* lib/target-supports.exp (check_effective_target_aarch64_sve128_hw)
(check_effective_target_aarch64_sve512_hw)
(check_effective_target_aarch64_sve1024_hw)
(check_effective_target_aarch64_sve2048_hw): New procedures.
2020-04-09 Matthew Malcomson <matthew.malcomson@arm.com>
* g++.target/arm/cde_mve.C: New test.
......
/* { dg-options "-msve-vector-bits=256" } */
#include <arm_sve.h>
#ifndef __ARM_FEATURE_SVE_BITS
#error "__ARM_FEATURE_SVE_BITS is not defined but should be"
#endif
#if __ARM_FEATURE_SVE_VECTOR_OPERATIONS != 1
#error "__ARM_FEATURE_SVE_VECTOR_OPERATIONS should be equal to 1"
#endif
#ifndef __cplusplus
#define alignof _Alignof
#endif
#define N __ARM_FEATURE_SVE_BITS
#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
#define GNU_ATTR __attribute__ ((vector_size (N / 8)))
typedef svint8_t fixed_int8_t FIXED_ATTR;
typedef svint16_t fixed_int16_t FIXED_ATTR;
typedef svint32_t fixed_int32_t FIXED_ATTR;
typedef svint64_t fixed_int64_t FIXED_ATTR;
typedef svuint8_t fixed_uint8_t FIXED_ATTR;
typedef svuint16_t fixed_uint16_t FIXED_ATTR;
typedef svuint32_t fixed_uint32_t FIXED_ATTR;
typedef svuint64_t fixed_uint64_t FIXED_ATTR;
typedef svbfloat16_t fixed_bfloat16_t FIXED_ATTR;
typedef svfloat16_t fixed_float16_t FIXED_ATTR;
typedef svfloat32_t fixed_float32_t FIXED_ATTR;
typedef svfloat64_t fixed_float64_t FIXED_ATTR;
typedef svbool_t fixed_bool_t FIXED_ATTR;
typedef int8_t gnu_int8_t GNU_ATTR;
typedef int16_t gnu_int16_t GNU_ATTR;
typedef int32_t gnu_int32_t GNU_ATTR;
typedef int64_t gnu_int64_t GNU_ATTR;
typedef uint8_t gnu_uint8_t GNU_ATTR;
typedef uint16_t gnu_uint16_t GNU_ATTR;
typedef uint32_t gnu_uint32_t GNU_ATTR;
typedef uint64_t gnu_uint64_t GNU_ATTR;
typedef bfloat16_t gnu_bfloat16_t GNU_ATTR;
typedef float16_t gnu_float16_t GNU_ATTR;
typedef float32_t gnu_float32_t GNU_ATTR;
typedef float64_t gnu_float64_t GNU_ATTR;
void f() {
#define TEST_VECTOR(TYPE) \
do \
{ \
int assert_sizeof[sizeof (TYPE) == N / 8 ? 1 : -1]; \
int assert_alignof[alignof (TYPE) == 16 ? 1 : -1]; \
} \
while (0)
TEST_VECTOR (fixed_int8_t);
TEST_VECTOR (fixed_int16_t);
TEST_VECTOR (fixed_int32_t);
TEST_VECTOR (fixed_int64_t);
TEST_VECTOR (fixed_uint8_t);
TEST_VECTOR (fixed_uint16_t);
TEST_VECTOR (fixed_uint32_t);
TEST_VECTOR (fixed_uint64_t);
TEST_VECTOR (fixed_bfloat16_t);
TEST_VECTOR (fixed_float16_t);
TEST_VECTOR (fixed_float32_t);
TEST_VECTOR (fixed_float64_t);
#undef TEST_VECTOR
{
int assert_sizeof[sizeof(fixed_bool_t) == N / 64 ? 1 : -1];
int assert_alignof[alignof(fixed_bool_t) == 2 ? 1 : -1];
}
}
#define TEST_GLOBAL(TYPE) \
extern fixed_##TYPE extern_##TYPE; \
fixed_##TYPE global_##TYPE;
#define TEST_STRUCT(TYPE) \
struct struct_##TYPE \
{ \
fixed_##TYPE a, b, c[3]; \
}; \
\
union union_##TYPE \
{ \
fixed_##TYPE a, b, c[3]; \
};
#define TEST_CONVERT(TYPE, PREFIX) \
PREFIX##TYPE \
to_##PREFIX##TYPE (fixed_##TYPE x) \
{ \
return x; \
} \
\
fixed_##TYPE \
from_##PREFIX##TYPE (PREFIX##TYPE x) \
{ \
return x; \
}
#define TEST_UNARY(TYPE, NAME, OP) \
fixed_##TYPE \
NAME##_##TYPE (fixed_##TYPE x) \
{ \
return OP x; \
}
#define TEST_BINARY(TYPE, NAME, OP) \
fixed_##TYPE \
NAME##_##TYPE (fixed_##TYPE x, fixed_##TYPE y) \
{ \
return x OP y; \
} \
\
fixed_##TYPE \
NAME##_##TYPE##_eq (fixed_##TYPE x, fixed_##TYPE y) \
{ \
x OP##= y; return x; \
}
#define TEST_COMPARISON(TYPE, NAME, OP) \
fixed_##TYPE \
NAME##_##TYPE (fixed_##TYPE x, fixed_##TYPE y) \
{ \
return x OP y; \
}
#define TEST_CALL(TYPE) \
fixed_##TYPE \
call_##TYPE##_ff (svbool_t pg, fixed_##TYPE x, fixed_##TYPE y) \
{ \
return svsel (pg, x, y); \
} \
\
fixed_##TYPE \
call_##TYPE##_sf (svbool_t pg, sv##TYPE x, fixed_##TYPE y) \
{ \
return svsel (pg, x, y); \
} \
\
fixed_##TYPE \
call_##TYPE##_fs (svbool_t pg, fixed_##TYPE x, sv##TYPE y) \
{ \
return svsel (pg, x, y); \
}
#define TEST_COMMON(TYPE) \
TEST_GLOBAL (TYPE) \
TEST_STRUCT (TYPE) \
TEST_CONVERT (TYPE, sv) \
TEST_CALL (TYPE)
#define TEST_VECTOR(TYPE) \
TEST_COMMON (TYPE) \
TEST_CONVERT (TYPE, gnu_) \
TEST_UNARY (TYPE, nop, +) \
TEST_UNARY (TYPE, neg, -) \
TEST_BINARY (TYPE, add, +) \
TEST_BINARY (TYPE, sub, -) \
TEST_BINARY (TYPE, mul, *) \
TEST_BINARY (TYPE, div, /) \
#define TEST_INT_VECTOR(TYPE) \
TEST_VECTOR (TYPE) \
TEST_UNARY (TYPE, inv, ~) \
TEST_BINARY (TYPE, mod, %) \
TEST_BINARY (TYPE, shl, <<) \
TEST_BINARY (TYPE, shr, >>) \
TEST_BINARY (TYPE, and, &) \
TEST_BINARY (TYPE, ior, |) \
TEST_BINARY (TYPE, xor, ^) \
TEST_COMPARISON (TYPE, eq, =) \
TEST_COMPARISON (TYPE, ne, !=) \
TEST_COMPARISON (TYPE, lt, <) \
TEST_COMPARISON (TYPE, le, <=) \
TEST_COMPARISON (TYPE, ge, >=) \
TEST_COMPARISON (TYPE, gt, >)
TEST_INT_VECTOR (int8_t);
TEST_INT_VECTOR (int16_t);
TEST_INT_VECTOR (int32_t);
TEST_INT_VECTOR (int64_t);
TEST_INT_VECTOR (uint8_t);
TEST_INT_VECTOR (uint16_t);
TEST_INT_VECTOR (uint32_t);
TEST_INT_VECTOR (uint64_t);
TEST_VECTOR (float16_t);
TEST_VECTOR (float32_t);
TEST_VECTOR (float64_t);
TEST_COMMON (bool_t)
/* { dg-options "-msve-vector-bits=512" } */
#include "attributes_1.c"
/* { dg-options "-msve-vector-bits=1024" } */
#include "attributes_1.c"
/* { dg-options "-msve-vector-bits=2048" } */
#include "attributes_1.c"
/* { dg-options "-msve-vector-bits=128" } */
#if __ARM_BIG_ENDIAN && !__ARM_FEATURE_SVE_BITS
int pass = 1;
#else
#include "attributes_1.c"
#endif
/* { dg-options "-O2 -msve-vector-bits=256" } */
/* { dg-final { check-function-bodies "**" "" } } */
#include <arm_sve.h>
#define N __ARM_FEATURE_SVE_BITS
#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
#define GNU_ATTR __attribute__ ((vector_size (N / 8)))
typedef svint8_t fixed_int8_t FIXED_ATTR;
typedef svbool_t fixed_bool_t FIXED_ATTR;
typedef int8_t gnu_int8_t GNU_ATTR;
#ifdef __cplusplus
extern "C" {
#endif
/*
** test_add:
** add z0\.b, (?:z0\.b, z1\.b|z1\.b, z0\.b)
** ret
*/
fixed_int8_t
test_add (fixed_int8_t x, fixed_int8_t y)
{
return x + y;
}
/*
** test_add_gnu:
** (
** add (z[0-9]+\.b), (?:z0\.b, z1\.b|z1\.b, z0\.b)
** ptrue (p[0-7])\.b, vl32
** st1b \1, \2, \[x8\]
** |
** ptrue (p[0-7]\.b), vl32
** add (z[0-9]+)\.b, (?:z0\.b, z1\.b|z1\.b, z0\.b)
** st1b \4, \3, \[x8\]
** )
** ret
*/
gnu_int8_t
test_add_gnu (fixed_int8_t x, fixed_int8_t y)
{
return x + y;
}
/*
** test_load: { target lp64 }
** ld1b z0\.b, p0/z, \[x0\]
** ret
*/
/*
** test_load: { target ilp32 }
** uxtw x0, w0
** ld1b z0\.b, p0/z, \[x0\]
** ret
*/
fixed_int8_t
test_load (fixed_bool_t pg, int8_t *ptr)
{
return svld1 (pg, ptr);
}
/*
** test_store: { target lp64 }
** st1b z0\.b, p0, \[x0\]
** ret
*/
/*
** test_store: { target ilp32 }
** uxtw x0, w0
** st1b z0\.b, p0, \[x0\]
** ret
*/
void
test_store (fixed_bool_t pg, int8_t *ptr, fixed_int8_t data)
{
svst1 (pg, ptr, data);
}
/*
** test_and_z:
** and p0\.b, p0/z, p1\.b, p2\.b
** ret
*/
fixed_bool_t
test_and_z (fixed_bool_t pg, svbool_t p1, fixed_bool_t p2)
{
return svand_z (pg, p1, p2);
}
#ifdef __cplusplus
}
#endif
/* { dg-options "-msve-vector-bits=256 -W -Wall" } */
#include <arm_sve.h>
#define N __ARM_FEATURE_SVE_BITS
#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
#define GNU_ATTR __attribute__ ((vector_size (N / 8)))
typedef svint8_t fixed_int8_t FIXED_ATTR;
typedef svint16_t fixed_int16_t FIXED_ATTR;
typedef svuint8_t fixed_uint8_t FIXED_ATTR;
typedef svbool_t fixed_bool_t FIXED_ATTR;
typedef int8_t gnu_int8_t GNU_ATTR;
typedef int16_t gnu_int16_t GNU_ATTR;
typedef uint8_t gnu_uint8_t GNU_ATTR;
typedef int bad_type_1 __attribute__ ((arm_sve_vector_bits (N))); // { dg-error {'arm_sve_vector_bits' applied to non-SVE type 'int'} }
typedef svbool_t bad_type_2 __attribute__ ((arm_sve_vector_bits)); // { dg-error {wrong number of arguments specified for 'arm_sve_vector_bits' attribute} }
typedef svbool_t bad_type_3 __attribute__ ((arm_sve_vector_bits (N, N))); // { dg-error {wrong number of arguments specified for 'arm_sve_vector_bits' attribute} }
typedef svbool_t bad_type_4 __attribute__ ((arm_sve_vector_bits ("256"))); // { dg-error {'arm_sve_vector_bits' requires an integer constant expression} }
typedef svbool_t bad_type_5 __attribute__ ((arm_sve_vector_bits (100))); // { dg-warning {unsupported SVE vector size} }
void
f (int c)
{
svint8_t ss8;
fixed_int8_t fs8;
gnu_int8_t gs8;
svuint8_t su8;
fixed_uint8_t fu8;
gnu_uint8_t gu8;
svint16_t ss16;
fixed_int16_t fs16;
gnu_int16_t gs16;
svbool_t sb;
fixed_bool_t fb;
ss8 = ss8 + ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
ss8 = ss8 + fs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
ss8 = ss8 + gs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
ss8 += ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
ss8 += fs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
ss8 += gs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
fs8 = fs8 + ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
fs8 = fs8 + fs8;
fs8 = fs8 + gs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
fs8 += ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
fs8 += fs8;
fs8 += gs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
gs8 = gs8 + ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
gs8 = gs8 + fs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
gs8 = gs8 + gs8;
gs8 += ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
gs8 += fs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
gs8 += gs8;
fs8 = ss8;
fs8 = fs8;
fs8 = gs8;
fs8 = su8; // { dg-error {cannot convert|incompatible types} }
fs8 = fu8; // { dg-error {cannot convert|incompatible types} }
fs8 = gu8; // { dg-error {cannot convert|incompatible types} }
fs8 = ss16; // { dg-error {cannot convert|incompatible types} }
fs8 = fs16; // { dg-error {cannot convert|incompatible types} }
fs8 = gs16; // { dg-error {cannot convert|incompatible types} }
(void) (c ? ss8 : ss8);
(void) (c ? ss8 : fs8); // { dg-error {type mismatch|different types} }
(void) (c ? ss8 : gs8); // { dg-error {type mismatch|different types} }
(void) (c ? fs8 : ss8); // { dg-error {type mismatch|different types} }
(void) (c ? fs8 : fs8);
(void) (c ? fs8 : gs8); // { dg-error {type mismatch|different types} "" { xfail c++ } }
(void) (c ? gs8 : ss8); // { dg-error {type mismatch|different types} }
(void) (c ? gs8 : fs8); // { dg-error {type mismatch|different types} "" { xfail c++ } }
(void) (c ? gs8 : gs8);
sb = fb;
fb = sb;
(void) (c ? sb : sb);
(void) (c ? sb : fb); // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
(void) (c ? fb : sb); // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
(void) (c ? fb : fb);
}
void
g (int c)
{
svint8_t *ss8;
fixed_int8_t *fs8;
gnu_int8_t *gs8;
svuint8_t *su8;
fixed_uint8_t *fu8;
gnu_uint8_t *gu8;
svint16_t *ss16;
fixed_int16_t *fs16;
gnu_int16_t *gs16;
svbool_t *sb;
fixed_bool_t *fb;
__PTRDIFF_TYPE__ diff __attribute__((unused));
void *select __attribute__((unused));
diff = ss8 - ss8; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
diff = ss8 - fs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
// { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
diff = ss8 - gs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
// { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
diff = fs8 - ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
// { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
diff = fs8 - fs8;
diff = fs8 - gs8;
diff = gs8 - ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
// { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
diff = gs8 - fs8;
diff = gs8 - gs8;
fs8 = ss8; // { dg-error {invalid conversion} "" { xfail c } }
fs8 = fs8;
fs8 = gs8;
fs8 = su8; // { dg-error {cannot convert} "c++" { target c++ } }
// { dg-warning {incompatible pointer type} "c" { target c } .-1 }
fs8 = fu8; // { dg-error {cannot convert} "c++" { target c++ } }
// { dg-warning {incompatible pointer type} "c" { target c } .-1 }
fs8 = gu8; // { dg-error {cannot convert} "c++" { target c++ } }
// { dg-warning {incompatible pointer type} "c" { target c } .-1 }
fs8 = ss16; // { dg-error {cannot convert} "c++" { target c++ } }
// { dg-warning {incompatible pointer type} "c" { target c } .-1 }
fs8 = fs16; // { dg-error {cannot convert} "c++" { target c++ } }
// { dg-warning {incompatible pointer type} "c" { target c } .-1 }
fs8 = gs16; // { dg-error {cannot convert} "c++" { target c++ } }
// { dg-warning {incompatible pointer type} "c" { target c } .-1 }
select = c ? ss8 : ss8;
select = c ? ss8 : fs8; // { dg-error {distinct pointer types} "" { xfail c } }
select = c ? ss8 : gs8; // { dg-error {distinct pointer types} "" { xfail c } }
select = c ? fs8 : ss8; // { dg-error {distinct pointer types} "" { xfail c } }
select = c ? fs8 : fs8;
select = c ? fs8 : gs8; // { dg-error {distinct pointer types} "" { xfail *-*-* } }
select = c ? gs8 : ss8; // { dg-error {distinct pointer types} "" { xfail c } }
select = c ? gs8 : fs8; // { dg-error {distinct pointer types} "" { xfail *-*-* } }
select = c ? gs8 : gs8;
diff = sb - sb; // { dg-error {arithmetic on pointer to SVE type 'svbool_t'} }
diff = sb - fb; // { dg-error {arithmetic on pointer to SVE type 'svbool_t'} }
diff = fb - sb; // { dg-error {arithmetic on pointer to SVE type 'svbool_t'} }
diff = fb - fb;
sb = fb;
fb = sb;
select = c ? sb : sb;
select = c ? sb : fb; // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
select = c ? fb : sb; // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
select = c ? fb : fb;
}
#ifndef STRUCT_H
#define STRUCT_H 1
#include <arm_sve.h>
#ifndef __ARM_FEATURE_SVE_BITS
#error "__ARM_FEATURE_SVE_BITS should be defined"
#endif
#define FIXED_ATTR \
__attribute__ ((arm_sve_vector_bits (__ARM_FEATURE_SVE_BITS)))
#define SVE_BYTES (__ARM_FEATURE_SVE_BITS / 8)
typedef __SVInt8_t fixed_int8_t FIXED_ATTR;
typedef __SVInt16_t fixed_int16_t FIXED_ATTR;
typedef __SVInt32_t fixed_int32_t FIXED_ATTR;
typedef __SVInt64_t fixed_int64_t FIXED_ATTR;
typedef __SVUint8_t fixed_uint8_t FIXED_ATTR;
typedef __SVUint16_t fixed_uint16_t FIXED_ATTR;
typedef __SVUint32_t fixed_uint32_t FIXED_ATTR;
typedef __SVUint64_t fixed_uint64_t FIXED_ATTR;
typedef __SVBfloat16_t fixed_bfloat16_t FIXED_ATTR;
typedef __SVFloat16_t fixed_float16_t FIXED_ATTR;
typedef __SVFloat32_t fixed_float32_t FIXED_ATTR;
typedef __SVFloat64_t fixed_float64_t FIXED_ATTR;
typedef __SVBool_t fixed_bool_t FIXED_ATTR;
/* Define an asm function called NAME with return type RET_TYPE and
argument list ARG_TYPES. INSNS contains the body of the function,
except for the final "ret".
Conservatively mark the function as a variant PCS function,
since many uses are. */
#define ASM_FUNCTION(NAME, RET_TYPE, ARG_TYPES, INSNS) \
extern RET_TYPE NAME ARG_TYPES; \
asm( \
" .type " #NAME ", %function\n" \
#NAME ":\n" \
" " INSNS "\n" \
" ret\n" \
" .size " #NAME ", .-" #NAME "\n" \
" .variant_pcs " #NAME "\n" \
)
/* Set the argument registers to fixed values. */
#define CLEANSE \
asm volatile ("mov\tx0, #-1\n\t" \
"mov\tx1, #-1\n\t" \
"mov\tx2, #-1\n\t" \
"mov\tx3, #-1\n\t" \
"mov\tx4, #-1\n\t" \
"mov\tx5, #-1\n\t" \
"mov\tx6, #-1\n\t" \
"mov\tx7, #-1\n\t" \
"mov\tx8, #-1\n\t" \
"mov\tz0.b, #0xaf\n\t" \
"mov\tz1.b, #0xaf\n\t" \
"mov\tz2.b, #0xaf\n\t" \
"mov\tz3.b, #0xaf\n\t" \
"mov\tz4.b, #0xaf\n\t" \
"mov\tz5.b, #0xaf\n\t" \
"mov\tz6.b, #0xaf\n\t" \
"mov\tz7.b, #0xaf\n\t" \
"pfalse\tp0.b\n\t" \
"pfalse\tp1.b\n\t" \
"pfalse\tp2.b\n\t" \
"pfalse\tp3.b" \
::: \
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", \
"z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", \
"p0", "p1", "p2", "p3")
#endif
/* { dg-do run { target { aarch64_sve1024_hw } } } */
/* { dg-options "-msve-vector-bits=1024" } */
#include "struct_1_128.c"
/* { dg-do run { target { aarch64_sve2048_hw } } } */
/* { dg-options "-msve-vector-bits=2048" } */
#include "struct_1_128.c"
/* { dg-do run { target { aarch64_sve256_hw } } } */
/* { dg-options "-msve-vector-bits=256" } */
#include "struct_1_128.c"
/* { dg-do run { target { aarch64_sve512_hw } } } */
/* { dg-options "-msve-vector-bits=512" } */
#include "struct_1_128.c"
/* { dg-do run { target { aarch64_sve1024_hw } } } */
/* { dg-options "-msve-vector-bits=1024" } */
#include "struct_2_128.c"
/* { dg-do run { target { aarch64_sve2048_hw } } } */
/* { dg-options "-msve-vector-bits=2048" } */
#include "struct_2_128.c"
/* { dg-do run { target { aarch64_sve256_hw } } } */
/* { dg-options "-msve-vector-bits=256" } */
#include "struct_2_128.c"
/* { dg-do run { target { aarch64_sve512_hw } } } */
/* { dg-options "-msve-vector-bits=512" } */
#include "struct_2_128.c"
......@@ -4695,8 +4695,12 @@ proc aarch64_sve_hw_bits { bits } {
# Return true if this is an AArch64 target that can run SVE code and
# if its SVE vectors have exactly 256 bits.
proc check_effective_target_aarch64_sve256_hw { } {
return [aarch64_sve_hw_bits 256]
foreach N { 128 256 512 1024 2048 } {
eval [string map [list N $N] {
proc check_effective_target_aarch64_sveN_hw { } {
return [aarch64_sve_hw_bits N]
}
}]
}
proc check_effective_target_arm_neonv2_hw { } {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment