From: Richard Sandiford Date: Sat, 7 Mar 2020 11:52:33 +0000 (+0000) Subject: aarch64: Add support for arm_sve_vector_bits X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=38e62001c576b8c6ba2e08eb4673d69ec4c5b0f9;p=gcc.git 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 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. --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0ee6c7dc574..1066146b2e5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,77 @@ +2020-04-09 Richard Sandiford + + * 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 * config/aarch64/aarch64.c (aarch64_attribute_table): Add diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c index e7b4ed7baed..e1c1cd415dc 100644 --- a/gcc/config/aarch64/aarch64-c.c +++ b/gcc/config/aarch64/aarch64-c.c @@ -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, diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index d6d668ea920..9e43adb7db0 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -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 diff --git a/gcc/config/aarch64/aarch64-sve-builtins.cc b/gcc/config/aarch64/aarch64-sve-builtins.cc index bcd60e9f838..ca4a0ebdd0c 100644 --- a/gcc/config/aarch64/aarch64-sve-builtins.cc +++ b/gcc/config/aarch64/aarch64-sve-builtins.cc @@ -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, diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 0a467176fd9..4af562a81ea 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -174,6 +174,102 @@ inline simd_immediate_info u.pattern = pattern_in; } +namespace { + +/* Describes types that map to Pure Scalable Types (PSTs) in the AAPCS64. */ +class pure_scalable_type_info +{ +public: + /* Represents the result of analyzing a type. All values are nonzero, + in the possibly forlorn hope that accidental conversions to bool + trigger a warning. */ + enum analysis_result + { + /* The type does not have an ABI identity; i.e. it doesn't contain + at least one object whose type is a Fundamental Data Type. */ + NO_ABI_IDENTITY = 1, + + /* The type is definitely a Pure Scalable Type. */ + IS_PST, + + /* The type is definitely not a Pure Scalable Type. */ + ISNT_PST, + + /* It doesn't matter for PCS purposes whether the type is a Pure + Scalable Type or not, since the type will be handled the same + way regardless. + + Specifically, this means that if the type is a Pure Scalable Type, + there aren't enough argument registers to hold it, and so it will + need to be passed or returned in memory. If the type isn't a + Pure Scalable Type, it's too big to be passed or returned in core + or SIMD&FP registers, and so again will need to go in memory. */ + DOESNT_MATTER + }; + + /* Aggregates of 17 bytes or more are normally passed and returned + in memory, so aggregates of that size can safely be analyzed as + DOESNT_MATTER. We need to be able to collect enough pieces to + represent a PST that is smaller than that. Since predicates are + 2 bytes in size for -msve-vector-bits=128, that means we need to be + able to store at least 8 pieces. + + We also need to be able to store enough pieces to represent + a single vector in each vector argument register and a single + predicate in each predicate argument register. This means that + we need at least 12 pieces. */ + static const unsigned int MAX_PIECES = NUM_FP_ARG_REGS + NUM_PR_ARG_REGS; +#if __cplusplus >= 201103L + static_assert (MAX_PIECES >= 8, "Need to store at least 8 predicates"); +#endif + + /* Describes one piece of a PST. Each piece is one of: + + - a single Scalable Vector Type (SVT) + - a single Scalable Predicate Type (SPT) + - a PST containing 2, 3 or 4 SVTs, with no padding + + It either represents a single built-in type or a PST formed from + multiple homogeneous built-in types. */ + struct piece + { + rtx get_rtx (unsigned int, unsigned int) const; + + /* The number of vector and predicate registers that the piece + occupies. One of the two is always zero. */ + unsigned int num_zr; + unsigned int num_pr; + + /* The mode of the registers described above. */ + machine_mode mode; + + /* If this piece is formed from multiple homogeneous built-in types, + this is the mode of the built-in types, otherwise it is MODE. */ + machine_mode orig_mode; + + /* The offset in bytes of the piece from the start of the type. */ + poly_uint64_pod offset; + }; + + /* Divides types analyzed as IS_PST into individual pieces. The pieces + are in memory order. */ + auto_vec pieces; + + unsigned int num_zr () const; + unsigned int num_pr () const; + + rtx get_rtx (machine_mode mode, unsigned int, unsigned int) const; + + analysis_result analyze (const_tree); + bool analyze_registers (const_tree); + +private: + analysis_result analyze_array (const_tree); + analysis_result analyze_record (const_tree); + void add_piece (const piece &); +}; +} + /* The current code model. */ enum aarch64_code_model aarch64_cmodel; @@ -186,6 +282,7 @@ poly_uint16 aarch64_sve_vg; #endif static bool aarch64_composite_type_p (const_tree, machine_mode); +static bool aarch64_return_in_memory_1 (const_tree); static bool aarch64_vfp_is_call_or_return_candidate (machine_mode, const_tree, machine_mode *, int *, @@ -1246,6 +1343,9 @@ static const struct attribute_spec aarch64_attribute_table[] = affects_type_identity, handler, exclude } */ { "aarch64_vector_pcs", 0, 0, false, true, true, true, handle_aarch64_vector_pcs_attribute, NULL }, + { "arm_sve_vector_bits", 1, 1, false, true, false, true, + aarch64_sve::handle_arm_sve_vector_bits_attribute, + NULL }, { "SVE type", 3, 3, false, true, false, true, NULL, NULL }, { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } @@ -1396,6 +1496,287 @@ svpattern_token (enum aarch64_svpattern pattern) gcc_unreachable (); } +/* Return the location of a piece that is known to be passed or returned + in registers. FIRST_ZR is the first unused vector argument register + and FIRST_PR is the first unused predicate argument register. */ + +rtx +pure_scalable_type_info::piece::get_rtx (unsigned int first_zr, + unsigned int first_pr) const +{ + gcc_assert (VECTOR_MODE_P (mode) + && first_zr + num_zr <= V0_REGNUM + NUM_FP_ARG_REGS + && first_pr + num_pr <= P0_REGNUM + NUM_PR_ARG_REGS); + + if (num_zr > 0 && num_pr == 0) + return gen_rtx_REG (mode, first_zr); + + if (num_zr == 0 && num_pr == 1) + return gen_rtx_REG (mode, first_pr); + + gcc_unreachable (); +} + +/* Return the total number of vector registers required by the PST. */ + +unsigned int +pure_scalable_type_info::num_zr () const +{ + unsigned int res = 0; + for (unsigned int i = 0; i < pieces.length (); ++i) + res += pieces[i].num_zr; + return res; +} + +/* Return the total number of predicate registers required by the PST. */ + +unsigned int +pure_scalable_type_info::num_pr () const +{ + unsigned int res = 0; + for (unsigned int i = 0; i < pieces.length (); ++i) + res += pieces[i].num_pr; + return res; +} + +/* Return the location of a PST that is known to be passed or returned + in registers. FIRST_ZR is the first unused vector argument register + and FIRST_PR is the first unused predicate argument register. */ + +rtx +pure_scalable_type_info::get_rtx (machine_mode mode, + unsigned int first_zr, + unsigned int first_pr) const +{ + /* Try to return a single REG if possible. This leads to better + code generation; it isn't required for correctness. */ + if (mode == pieces[0].mode) + { + gcc_assert (pieces.length () == 1); + return pieces[0].get_rtx (first_zr, first_pr); + } + + /* Build up a PARALLEL that contains the individual pieces. */ + rtvec rtxes = rtvec_alloc (pieces.length ()); + for (unsigned int i = 0; i < pieces.length (); ++i) + { + rtx reg = pieces[i].get_rtx (first_zr, first_pr); + rtx offset = gen_int_mode (pieces[i].offset, Pmode); + RTVEC_ELT (rtxes, i) = gen_rtx_EXPR_LIST (VOIDmode, reg, offset); + first_zr += pieces[i].num_zr; + first_pr += pieces[i].num_pr; + } + return gen_rtx_PARALLEL (mode, rtxes); +} + +/* Analyze whether TYPE is a Pure Scalable Type according to the rules + in the AAPCS64. */ + +pure_scalable_type_info::analysis_result +pure_scalable_type_info::analyze (const_tree type) +{ + /* Prevent accidental reuse. */ + gcc_assert (pieces.is_empty ()); + + /* No code will be generated for erroneous types, so we won't establish + an ABI mapping. */ + if (type == error_mark_node) + return NO_ABI_IDENTITY; + + /* Zero-sized types disappear in the language->ABI mapping. */ + if (TYPE_SIZE (type) && integer_zerop (TYPE_SIZE (type))) + return NO_ABI_IDENTITY; + + /* Check for SVTs, SPTs, and built-in tuple types that map to PSTs. */ + piece p = {}; + if (aarch64_sve::builtin_type_p (type, &p.num_zr, &p.num_pr)) + { + machine_mode mode = TYPE_MODE_RAW (type); + gcc_assert (VECTOR_MODE_P (mode) + && (!TARGET_SVE || aarch64_sve_mode_p (mode))); + + p.mode = p.orig_mode = mode; + add_piece (p); + return IS_PST; + } + + /* Check for user-defined PSTs. */ + if (TREE_CODE (type) == ARRAY_TYPE) + return analyze_array (type); + if (TREE_CODE (type) == RECORD_TYPE) + return analyze_record (type); + + return ISNT_PST; +} + +/* Analyze a type that is known not to be passed or returned in memory. + Return true if it has an ABI identity and is a Pure Scalable Type. */ + +bool +pure_scalable_type_info::analyze_registers (const_tree type) +{ + analysis_result result = analyze (type); + gcc_assert (result != DOESNT_MATTER); + return result == IS_PST; +} + +/* Subroutine of analyze for handling ARRAY_TYPEs. */ + +pure_scalable_type_info::analysis_result +pure_scalable_type_info::analyze_array (const_tree type) +{ + /* Analyze the element type. */ + pure_scalable_type_info element_info; + analysis_result result = element_info.analyze (TREE_TYPE (type)); + if (result != IS_PST) + return result; + + /* An array of unknown, flexible or variable length will be passed and + returned by reference whatever we do. */ + tree nelts_minus_one = array_type_nelts (type); + if (!tree_fits_uhwi_p (nelts_minus_one)) + return DOESNT_MATTER; + + /* Likewise if the array is constant-sized but too big to be interesting. + The double checks against MAX_PIECES are to protect against overflow. */ + unsigned HOST_WIDE_INT count = tree_to_uhwi (nelts_minus_one); + if (count > MAX_PIECES) + return DOESNT_MATTER; + count += 1; + if (count * element_info.pieces.length () > MAX_PIECES) + return DOESNT_MATTER; + + /* The above checks should have weeded out elements of unknown size. */ + poly_uint64 element_bytes; + if (!poly_int_tree_p (TYPE_SIZE_UNIT (TREE_TYPE (type)), &element_bytes)) + gcc_unreachable (); + + /* Build up the list of individual vectors and predicates. */ + gcc_assert (!element_info.pieces.is_empty ()); + for (unsigned int i = 0; i < count; ++i) + for (unsigned int j = 0; j < element_info.pieces.length (); ++j) + { + piece p = element_info.pieces[j]; + p.offset += i * element_bytes; + add_piece (p); + } + return IS_PST; +} + +/* Subroutine of analyze for handling RECORD_TYPEs. */ + +pure_scalable_type_info::analysis_result +pure_scalable_type_info::analyze_record (const_tree type) +{ + for (tree field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + { + if (TREE_CODE (field) != FIELD_DECL) + continue; + + /* Zero-sized fields disappear in the language->ABI mapping. */ + if (DECL_SIZE (field) && integer_zerop (DECL_SIZE (field))) + continue; + + /* All fields with an ABI identity must be PSTs for the record as + a whole to be a PST. If any individual field is too big to be + interesting then the record is too. */ + pure_scalable_type_info field_info; + analysis_result subresult = field_info.analyze (TREE_TYPE (field)); + if (subresult == NO_ABI_IDENTITY) + continue; + if (subresult != IS_PST) + return subresult; + + /* Since all previous fields are PSTs, we ought to be able to track + the field offset using poly_ints. */ + tree bitpos = bit_position (field); + gcc_assert (poly_int_tree_p (bitpos)); + + /* For the same reason, it shouldn't be possible to create a PST field + whose offset isn't byte-aligned. */ + poly_widest_int wide_bytepos = exact_div (wi::to_poly_widest (bitpos), + BITS_PER_UNIT); + + /* Punt if the record is too big to be interesting. */ + poly_uint64 bytepos; + if (!wide_bytepos.to_uhwi (&bytepos) + || pieces.length () + field_info.pieces.length () > MAX_PIECES) + return DOESNT_MATTER; + + /* Add the individual vectors and predicates in the field to the + record's list. */ + gcc_assert (!field_info.pieces.is_empty ()); + for (unsigned int i = 0; i < field_info.pieces.length (); ++i) + { + piece p = field_info.pieces[i]; + p.offset += bytepos; + add_piece (p); + } + } + /* Empty structures disappear in the language->ABI mapping. */ + return pieces.is_empty () ? NO_ABI_IDENTITY : IS_PST; +} + +/* Add P to the list of pieces in the type. */ + +void +pure_scalable_type_info::add_piece (const piece &p) +{ + /* Try to fold the new piece into the previous one to form a + single-mode PST. For example, if we see three consecutive vectors + of the same mode, we can represent them using the corresponding + 3-tuple mode. + + This is purely an optimization. */ + if (!pieces.is_empty ()) + { + piece &prev = pieces.last (); + gcc_assert (VECTOR_MODE_P (p.mode) && VECTOR_MODE_P (prev.mode)); + unsigned int nelems1, nelems2; + if (prev.orig_mode == p.orig_mode + && known_eq (prev.offset + GET_MODE_SIZE (prev.mode), p.offset) + && constant_multiple_p (GET_MODE_NUNITS (prev.mode), + GET_MODE_NUNITS (p.orig_mode), &nelems1) + && constant_multiple_p (GET_MODE_NUNITS (p.mode), + GET_MODE_NUNITS (p.orig_mode), &nelems2) + && targetm.array_mode (p.orig_mode, + nelems1 + nelems2).exists (&prev.mode)) + { + prev.num_zr += p.num_zr; + prev.num_pr += p.num_pr; + return; + } + } + pieces.quick_push (p); +} + +/* Return true if at least one possible value of type TYPE includes at + least one object of Pure Scalable Type, in the sense of the AAPCS64. + + This is a relatively expensive test for some types, so it should + generally be made as late as possible. */ + +static bool +aarch64_some_values_include_pst_objects_p (const_tree type) +{ + if (TYPE_SIZE (type) && integer_zerop (TYPE_SIZE (type))) + return false; + + if (aarch64_sve::builtin_type_p (type)) + return true; + + if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == COMPLEX_TYPE) + return aarch64_some_values_include_pst_objects_p (TREE_TYPE (type)); + + if (RECORD_OR_UNION_TYPE_P (type)) + for (tree field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && aarch64_some_values_include_pst_objects_p (TREE_TYPE (field))) + return true; + + return false; +} + /* Return the descriptor of the SIMD ABI. */ static const predefined_function_abi & @@ -2045,11 +2426,6 @@ aarch64_hard_regno_mode_ok (unsigned regno, machine_mode mode) return false; } -/* Return true if TYPE is a type that should be passed or returned in - SVE registers, assuming enough registers are available. When returning - true, set *NUM_ZR and *NUM_PR to the number of required Z and P registers - respectively. */ - /* Return true if a function with type FNTYPE returns its value in SVE vector or predicate registers. */ @@ -2057,8 +2433,23 @@ static bool aarch64_returns_value_in_sve_regs_p (const_tree fntype) { tree return_type = TREE_TYPE (fntype); - return (return_type != error_mark_node - && aarch64_sve::builtin_type_p (return_type)); + + pure_scalable_type_info pst_info; + switch (pst_info.analyze (return_type)) + { + case pure_scalable_type_info::IS_PST: + return (pst_info.num_zr () <= NUM_FP_ARG_REGS + && pst_info.num_pr () <= NUM_PR_ARG_REGS); + + case pure_scalable_type_info::DOESNT_MATTER: + gcc_assert (aarch64_return_in_memory_1 (return_type)); + return false; + + case pure_scalable_type_info::NO_ABI_IDENTITY: + case pure_scalable_type_info::ISNT_PST: + return false; + } + gcc_unreachable (); } /* Return true if a function with type FNTYPE takes arguments in @@ -2082,8 +2473,14 @@ aarch64_takes_arguments_in_sve_regs_p (const_tree fntype) function_arg_info arg (arg_type, /*named=*/true); apply_pass_by_reference_rules (&args_so_far_v, arg); - if (aarch64_sve::builtin_type_p (arg.type)) - return true; + pure_scalable_type_info pst_info; + if (pst_info.analyze_registers (arg.type)) + { + unsigned int end_zr = args_so_far_v.aapcs_nvrn + pst_info.num_zr (); + unsigned int end_pr = args_so_far_v.aapcs_nprn + pst_info.num_pr (); + gcc_assert (end_zr <= NUM_FP_ARG_REGS && end_pr <= NUM_PR_ARG_REGS); + return true; + } targetm.calls.function_arg_advance (args_so_far, arg); } @@ -4884,33 +5281,16 @@ aarch64_function_ok_for_sibcall (tree, tree exp) return true; } -/* Implement TARGET_PASS_BY_REFERENCE. */ +/* Subroutine of aarch64_pass_by_reference for arguments that are not + passed in SVE registers. */ static bool -aarch64_pass_by_reference (cumulative_args_t pcum_v, - const function_arg_info &arg) +aarch64_pass_by_reference_1 (const function_arg_info &arg) { - CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); HOST_WIDE_INT size; machine_mode dummymode; int nregs; - unsigned int num_zr, num_pr; - if (arg.type && aarch64_sve::builtin_type_p (arg.type, &num_zr, &num_pr)) - { - if (pcum && !pcum->silent_p && !TARGET_SVE) - /* We can't gracefully recover at this point, so make this a - fatal error. */ - fatal_error (input_location, "arguments of type %qT require" - " the SVE ISA extension", arg.type); - - /* Variadic SVE types are passed by reference. Normal non-variadic - arguments are too if we've run out of registers. */ - return (!arg.named - || pcum->aapcs_nvrn + num_zr > NUM_FP_ARG_REGS - || pcum->aapcs_nprn + num_pr > NUM_PR_ARG_REGS); - } - /* GET_MODE_SIZE (BLKmode) is useless since it is 0. */ if (arg.mode == BLKmode && arg.type) size = int_size_in_bytes (arg.type); @@ -4939,6 +5319,44 @@ aarch64_pass_by_reference (cumulative_args_t pcum_v, return size > 2 * UNITS_PER_WORD; } +/* Implement TARGET_PASS_BY_REFERENCE. */ + +static bool +aarch64_pass_by_reference (cumulative_args_t pcum_v, + const function_arg_info &arg) +{ + CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); + + if (!arg.type) + return aarch64_pass_by_reference_1 (arg); + + pure_scalable_type_info pst_info; + switch (pst_info.analyze (arg.type)) + { + case pure_scalable_type_info::IS_PST: + if (pcum && !pcum->silent_p && !TARGET_SVE) + /* We can't gracefully recover at this point, so make this a + fatal error. */ + fatal_error (input_location, "arguments of type %qT require" + " the SVE ISA extension", arg.type); + + /* Variadic SVE types are passed by reference. Normal non-variadic + arguments are too if we've run out of registers. */ + return (!arg.named + || pcum->aapcs_nvrn + pst_info.num_zr () > NUM_FP_ARG_REGS + || pcum->aapcs_nprn + pst_info.num_pr () > NUM_PR_ARG_REGS); + + case pure_scalable_type_info::DOESNT_MATTER: + gcc_assert (aarch64_pass_by_reference_1 (arg)); + return true; + + case pure_scalable_type_info::NO_ABI_IDENTITY: + case pure_scalable_type_info::ISNT_PST: + return aarch64_pass_by_reference_1 (arg); + } + gcc_unreachable (); +} + /* Return TRUE if VALTYPE is padded to its least significant bits. */ static bool aarch64_return_in_msb (const_tree valtype) @@ -4965,37 +5383,36 @@ aarch64_return_in_msb (const_tree valtype) &dummy_mode, &dummy_int, NULL)) return false; + /* Likewise pure scalable types for SVE vector and predicate registers. */ + pure_scalable_type_info pst_info; + if (pst_info.analyze_registers (valtype)) + return false; + return true; } -/* Subroutine of aarch64_function_value. MODE is the mode of the argument - after promotion, and after partial SVE types have been replaced by - their integer equivalents. */ +/* Implement TARGET_FUNCTION_VALUE. + Define how to find the value returned by a function. */ + static rtx -aarch64_function_value_1 (const_tree type, machine_mode mode) +aarch64_function_value (const_tree type, const_tree func, + bool outgoing ATTRIBUTE_UNUSED) { - unsigned int num_zr, num_pr; - if (type && aarch64_sve::builtin_type_p (type, &num_zr, &num_pr)) - { - /* Don't raise an error here if we're called when SVE is disabled, - since this is really just a query function. Other code must - do that where appropriate. */ - mode = TYPE_MODE_RAW (type); - gcc_assert (VECTOR_MODE_P (mode) - && (!TARGET_SVE || aarch64_sve_mode_p (mode))); - - if (num_zr > 0 && num_pr == 0) - return gen_rtx_REG (mode, V0_REGNUM); + machine_mode mode; + int unsignedp; - if (num_zr == 0 && num_pr == 1) - return gen_rtx_REG (mode, P0_REGNUM); + mode = TYPE_MODE (type); + if (INTEGRAL_TYPE_P (type)) + mode = promote_function_mode (type, mode, &unsignedp, func, 1); - gcc_unreachable (); - } + pure_scalable_type_info pst_info; + if (type && pst_info.analyze_registers (type)) + return pst_info.get_rtx (mode, V0_REGNUM, P0_REGNUM); - /* Generic vectors that map to SVE modes with -msve-vector-bits=N are - returned in memory, not by value. */ - gcc_assert (!aarch64_sve_mode_p (mode)); + /* Generic vectors that map to full SVE modes with -msve-vector-bits=N + are returned in memory, not by value. */ + unsigned int vec_flags = aarch64_classify_vector_mode (mode); + bool sve_p = (vec_flags & VEC_ANY_SVE); if (aarch64_return_in_msb (type)) { @@ -5013,6 +5430,7 @@ aarch64_function_value_1 (const_tree type, machine_mode mode) if (aarch64_vfp_is_call_or_return_candidate (mode, type, &ag_mode, &count, NULL)) { + gcc_assert (!sve_p); if (!aarch64_composite_type_p (type, mode)) { gcc_assert (count == 1 && mode == ag_mode); @@ -5035,43 +5453,29 @@ aarch64_function_value_1 (const_tree type, machine_mode mode) } } else - return gen_rtx_REG (mode, R0_REGNUM); -} - -/* Implement TARGET_FUNCTION_VALUE. - Define how to find the value returned by a function. */ - -static rtx -aarch64_function_value (const_tree type, const_tree func, - bool outgoing ATTRIBUTE_UNUSED) -{ - machine_mode mode; - int unsignedp; - - mode = TYPE_MODE (type); - if (INTEGRAL_TYPE_P (type)) - mode = promote_function_mode (type, mode, &unsignedp, func, 1); - - /* Vector types can acquire a partial SVE mode using things like - __attribute__((vector_size(N))), and this is potentially useful. - However, the choice of mode doesn't affect the type's ABI identity, - so we should treat the types as though they had the associated - integer mode, just like they did before SVE was introduced. - - We know that the vector must be 128 bits or smaller, otherwise we'd - have returned it in memory instead. */ - unsigned int vec_flags = aarch64_classify_vector_mode (mode); - if ((vec_flags & VEC_ANY_SVE) && (vec_flags & VEC_PARTIAL)) { - scalar_int_mode int_mode = int_mode_for_mode (mode).require (); - rtx reg = aarch64_function_value_1 (type, int_mode); - /* Vector types are never returned in the MSB and are never split. */ - gcc_assert (REG_P (reg) && GET_MODE (reg) == int_mode); - rtx pair = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); - return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, pair)); + if (sve_p) + { + /* Vector types can acquire a partial SVE mode using things like + __attribute__((vector_size(N))), and this is potentially useful. + However, the choice of mode doesn't affect the type's ABI + identity, so we should treat the types as though they had + the associated integer mode, just like they did before SVE + was introduced. + + We know that the vector must be 128 bits or smaller, + otherwise we'd have returned it in memory instead. */ + gcc_assert (type + && (aarch64_some_values_include_pst_objects_p (type) + || (vec_flags & VEC_PARTIAL))); + + scalar_int_mode int_mode = int_mode_for_mode (mode).require (); + rtx reg = gen_rtx_REG (int_mode, R0_REGNUM); + rtx pair = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); + return gen_rtx_PARALLEL (mode, gen_rtvec (1, pair)); + } + return gen_rtx_REG (mode, R0_REGNUM); } - - return aarch64_function_value_1 (type, mode); } /* Implements TARGET_FUNCTION_VALUE_REGNO_P. @@ -5095,17 +5499,11 @@ aarch64_function_value_regno_p (const unsigned int regno) return false; } -/* Implement TARGET_RETURN_IN_MEMORY. - - If the type T of the result of a function is such that - void func (T arg) - would require that arg be passed as a value in a register (or set of - registers) according to the parameter passing rules, then the result - is returned in the same registers as would be used for such an - argument. */ +/* Subroutine for aarch64_return_in_memory for types that are not returned + in SVE registers. */ static bool -aarch64_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) +aarch64_return_in_memory_1 (const_tree type) { HOST_WIDE_INT size; machine_mode ag_mode; @@ -5117,16 +5515,6 @@ aarch64_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) /* Simple scalar types always returned in registers. */ return false; - unsigned int num_zr, num_pr; - if (type && aarch64_sve::builtin_type_p (type, &num_zr, &num_pr)) - { - /* All SVE types we support fit in registers. For example, it isn't - yet possible to define an aggregate of 9+ SVE vectors or 5+ SVE - predicates. */ - gcc_assert (num_zr <= NUM_FP_ARG_REGS && num_pr <= NUM_PR_ARG_REGS); - return false; - } - if (aarch64_vfp_is_call_or_return_candidate (TYPE_MODE (type), type, &ag_mode, @@ -5139,6 +5527,36 @@ aarch64_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) return (size < 0 || size > 2 * UNITS_PER_WORD); } +/* Implement TARGET_RETURN_IN_MEMORY. + + If the type T of the result of a function is such that + void func (T arg) + would require that arg be passed as a value in a register (or set of + registers) according to the parameter passing rules, then the result + is returned in the same registers as would be used for such an + argument. */ + +static bool +aarch64_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) +{ + pure_scalable_type_info pst_info; + switch (pst_info.analyze (type)) + { + case pure_scalable_type_info::IS_PST: + return (pst_info.num_zr () > NUM_FP_ARG_REGS + || pst_info.num_pr () > NUM_PR_ARG_REGS); + + case pure_scalable_type_info::DOESNT_MATTER: + gcc_assert (aarch64_return_in_memory_1 (type)); + return true; + + case pure_scalable_type_info::NO_ABI_IDENTITY: + case pure_scalable_type_info::ISNT_PST: + return aarch64_return_in_memory_1 (type); + } + gcc_unreachable (); +} + static bool aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, const_tree type, int *nregs) @@ -5205,8 +5623,7 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type, the equivalent integer mode. */ static void -aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, - machine_mode orig_mode) +aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) { CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); tree type = arg.type; @@ -5220,33 +5637,10 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, if (pcum->aapcs_arg_processed) return; - /* Vector types can acquire a partial SVE mode using things like - __attribute__((vector_size(N))), and this is potentially useful. - However, the choice of mode doesn't affect the type's ABI identity, - so we should treat the types as though they had the associated - integer mode, just like they did before SVE was introduced. - - We know that the vector must be 128 bits or smaller, otherwise we'd - have passed it by reference instead. */ - unsigned int vec_flags = aarch64_classify_vector_mode (mode); - if ((vec_flags & VEC_ANY_SVE) && (vec_flags & VEC_PARTIAL)) - { - function_arg_info tmp_arg = arg; - tmp_arg.mode = int_mode_for_mode (mode).require (); - aarch64_layout_arg (pcum_v, tmp_arg, orig_mode); - if (rtx reg = pcum->aapcs_reg) - { - gcc_assert (REG_P (reg) && GET_MODE (reg) == tmp_arg.mode); - rtx pair = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx); - pcum->aapcs_reg = gen_rtx_PARALLEL (mode, gen_rtvec (1, pair)); - } - return; - } - pcum->aapcs_arg_processed = true; - unsigned int num_zr, num_pr; - if (type && aarch64_sve::builtin_type_p (type, &num_zr, &num_pr)) + pure_scalable_type_info pst_info; + if (type && pst_info.analyze_registers (type)) { /* The PCS says that it is invalid to pass an SVE value to an unprototyped function. There is no ABI-defined location we @@ -5264,26 +5658,34 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, /* We would have converted the argument into pass-by-reference form if it didn't fit in registers. */ - pcum->aapcs_nextnvrn = pcum->aapcs_nvrn + num_zr; - pcum->aapcs_nextnprn = pcum->aapcs_nprn + num_pr; + pcum->aapcs_nextnvrn = pcum->aapcs_nvrn + pst_info.num_zr (); + pcum->aapcs_nextnprn = pcum->aapcs_nprn + pst_info.num_pr (); gcc_assert (arg.named && pcum->pcs_variant == ARM_PCS_SVE - && aarch64_sve_mode_p (mode) && pcum->aapcs_nextnvrn <= NUM_FP_ARG_REGS && pcum->aapcs_nextnprn <= NUM_PR_ARG_REGS); - - if (num_zr > 0 && num_pr == 0) - pcum->aapcs_reg = gen_rtx_REG (mode, V0_REGNUM + pcum->aapcs_nvrn); - else if (num_zr == 0 && num_pr == 1) - pcum->aapcs_reg = gen_rtx_REG (mode, P0_REGNUM + pcum->aapcs_nprn); - else - gcc_unreachable (); + pcum->aapcs_reg = pst_info.get_rtx (mode, V0_REGNUM + pcum->aapcs_nvrn, + P0_REGNUM + pcum->aapcs_nprn); return; } - /* Generic vectors that map to SVE modes with -msve-vector-bits=N are - passed by reference, not by value. */ - gcc_assert (!aarch64_sve_mode_p (mode)); + /* Generic vectors that map to full SVE modes with -msve-vector-bits=N + are passed by reference, not by value. */ + unsigned int vec_flags = aarch64_classify_vector_mode (mode); + bool sve_p = (vec_flags & VEC_ANY_SVE); + if (sve_p) + /* Vector types can acquire a partial SVE mode using things like + __attribute__((vector_size(N))), and this is potentially useful. + However, the choice of mode doesn't affect the type's ABI + identity, so we should treat the types as though they had + the associated integer mode, just like they did before SVE + was introduced. + + We know that the vector must be 128 bits or smaller, + otherwise we'd have passed it in memory instead. */ + gcc_assert (type + && (aarch64_some_values_include_pst_objects_p (type) + || (vec_flags & VEC_PARTIAL))); /* Size in bytes, rounded to the nearest multiple of 8 bytes. */ if (type) @@ -5299,6 +5701,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, mode, type, &nregs); + gcc_assert (!sve_p || !allocate_nvrn); /* allocate_ncrn may be false-positive, but allocate_nvrn is quite reliable. The following code thus handles passing by SIMD/FP registers first. */ @@ -5364,7 +5767,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, comparison is there because for > 16 * BITS_PER_UNIT alignment nregs should be > 2 and therefore it should be passed by reference rather than value. */ - && (aarch64_function_arg_alignment (orig_mode, type, &abi_break) + && (aarch64_function_arg_alignment (mode, type, &abi_break) == 16 * BITS_PER_UNIT)) { if (abi_break && warn_psabi && currently_expanding_gimple_stmt) @@ -5374,10 +5777,24 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, gcc_assert (ncrn + nregs <= NUM_ARG_REGS); } + /* If an argument with an SVE mode needs to be shifted up to the + high part of the register, treat it as though it had an integer mode. + Using the normal (parallel [...]) would suppress the shifting. */ + if (sve_p + && BYTES_BIG_ENDIAN + && maybe_ne (GET_MODE_SIZE (mode), nregs * UNITS_PER_WORD) + && aarch64_pad_reg_upward (mode, type, false)) + { + mode = int_mode_for_mode (mode).require (); + sve_p = false; + } + /* NREGS can be 0 when e.g. an empty structure is to be passed. A reg is still generated for it, but the caller should be smart enough not to use it. */ - if (nregs == 0 || nregs == 1 || GET_MODE_CLASS (mode) == MODE_INT) + if (nregs == 0 + || (nregs == 1 && !sve_p) + || GET_MODE_CLASS (mode) == MODE_INT) pcum->aapcs_reg = gen_rtx_REG (mode, R0_REGNUM + ncrn); else { @@ -5387,7 +5804,10 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, par = gen_rtx_PARALLEL (mode, rtvec_alloc (nregs)); for (i = 0; i < nregs; i++) { - rtx tmp = gen_rtx_REG (word_mode, R0_REGNUM + ncrn + i); + scalar_int_mode reg_mode = word_mode; + if (nregs == 1) + reg_mode = int_mode_for_mode (mode).require (); + rtx tmp = gen_rtx_REG (reg_mode, R0_REGNUM + ncrn + i); tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, GEN_INT (i * UNITS_PER_WORD)); XVECEXP (par, 0, i) = tmp; @@ -5407,7 +5827,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg, on_stack: pcum->aapcs_stack_words = size / UNITS_PER_WORD; - if (aarch64_function_arg_alignment (orig_mode, type, &abi_break) + if (aarch64_function_arg_alignment (mode, type, &abi_break) == 16 * BITS_PER_UNIT) { int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); @@ -5435,7 +5855,7 @@ aarch64_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg) if (arg.end_marker_p ()) return gen_int_mode (pcum->pcs_variant, DImode); - aarch64_layout_arg (pcum_v, arg, arg.mode); + aarch64_layout_arg (pcum_v, arg); return pcum->aapcs_reg; } @@ -5500,7 +5920,7 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, || pcum->pcs_variant == ARM_PCS_SIMD || pcum->pcs_variant == ARM_PCS_SVE) { - aarch64_layout_arg (pcum_v, arg, arg.mode); + aarch64_layout_arg (pcum_v, arg); gcc_assert ((pcum->aapcs_reg != NULL_RTX) != (pcum->aapcs_stack_words != 0)); pcum->aapcs_arg_processed = false; @@ -5609,7 +6029,8 @@ aarch64_pad_reg_upward (machine_mode mode, const_tree type, bool first ATTRIBUTE_UNUSED) { - /* Small composite types are always padded upward. */ + /* Aside from pure scalable types, small composite types are always + padded upward. */ if (BYTES_BIG_ENDIAN && aarch64_composite_type_p (type, mode)) { HOST_WIDE_INT size; @@ -5620,7 +6041,12 @@ aarch64_pad_reg_upward (machine_mode mode, const_tree type, shouldn't be asked to pass or return them. */ size = GET_MODE_SIZE (mode).to_constant (); if (size < 2 * UNITS_PER_WORD) - return true; + { + pure_scalable_type_info pst_info; + if (pst_info.analyze_registers (type)) + return false; + return true; + } } /* Otherwise, use the default padding. */ @@ -15913,6 +16339,30 @@ aarch64_conditional_register_usage (void) } } +/* Implement TARGET_MEMBER_TYPE_FORCES_BLK. */ + +bool +aarch64_member_type_forces_blk (const_tree field_or_array, machine_mode mode) +{ + /* For records we're passed a FIELD_DECL, for arrays we're passed + an ARRAY_TYPE. In both cases we're interested in the TREE_TYPE. */ + const_tree type = TREE_TYPE (field_or_array); + + /* Assign BLKmode to anything that contains multiple SVE predicates. + For structures, the "multiple" case is indicated by MODE being + VOIDmode. */ + unsigned int num_zr, num_pr; + if (aarch64_sve::builtin_type_p (type, &num_zr, &num_pr) && num_pr != 0) + { + if (TREE_CODE (field_or_array) == ARRAY_TYPE) + return !simple_cst_equal (TYPE_SIZE (field_or_array), + TYPE_SIZE (type)); + return mode == VOIDmode; + } + + return default_member_type_forces_blk (field_or_array, mode); +} + /* Walk down the type tree of TYPE counting consecutive base elements. If *MODEP is VOIDmode, then set it to the first valid floating point type. If a non-floating point type is found, or if a floating point @@ -15924,9 +16374,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep) machine_mode mode; HOST_WIDE_INT size; - /* SVE types (and types containing SVE types) must be handled - before calling this function. */ - gcc_assert (!aarch64_sve::builtin_type_p (type)); + if (aarch64_sve::builtin_type_p (type)) + return -1; switch (TREE_CODE (type)) { @@ -16099,16 +16548,29 @@ aarch64_short_vector_p (const_tree type, { poly_int64 size = -1; - if (type && aarch64_sve::builtin_type_p (type)) - return false; - if (type && TREE_CODE (type) == VECTOR_TYPE) - size = int_size_in_bytes (type); + { + if (aarch64_sve::builtin_type_p (type)) + return false; + size = int_size_in_bytes (type); + } else if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT - || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) - size = GET_MODE_SIZE (mode); - - return known_eq (size, 8) || known_eq (size, 16); + || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT) + { + /* Rely only on the type, not the mode, when processing SVE types. */ + if (type && aarch64_some_values_include_pst_objects_p (type)) + gcc_assert (aarch64_sve_mode_p (mode)); + else + size = GET_MODE_SIZE (mode); + } + if (known_eq (size, 8) || known_eq (size, 16)) + { + /* 64-bit and 128-bit vectors should only acquire an SVE mode if + they are being treated as scalable AAPCS64 types. */ + gcc_assert (!aarch64_sve_mode_p (mode)); + return true; + } + return false; } /* Return TRUE if the type, as described by TYPE and MODE, is a composite @@ -16164,9 +16626,6 @@ aarch64_vfp_is_call_or_return_candidate (machine_mode mode, { if (is_ha != NULL) *is_ha = false; - if (type && aarch64_sve::builtin_type_p (type)) - return false; - machine_mode new_mode = VOIDmode; bool composite_p = aarch64_composite_type_p (type, mode); @@ -16197,6 +16656,7 @@ aarch64_vfp_is_call_or_return_candidate (machine_mode mode, else return false; + gcc_assert (!aarch64_sve_mode_p (new_mode)); *base_mode = new_mode; return true; } @@ -21695,6 +22155,16 @@ aarch64_can_change_mode_class (machine_mode from, bool from_partial_sve_p = from_sve_p && (from_flags & VEC_PARTIAL); bool to_partial_sve_p = to_sve_p && (to_flags & VEC_PARTIAL); + bool from_pred_p = (from_flags & VEC_SVE_PRED); + bool to_pred_p = (to_flags & VEC_SVE_PRED); + + /* Don't allow changes between predicate modes and other modes. + Only predicate registers can hold predicate modes and only + non-predicate registers can hold non-predicate modes, so any + attempt to mix them would require a round trip through memory. */ + if (from_pred_p != to_pred_p) + return false; + /* Don't allow changes between partial SVE modes and other modes. The contents of partial SVE modes are distributed evenly across the register, whereas GCC expects them to be clustered together. */ @@ -21708,6 +22178,18 @@ aarch64_can_change_mode_class (machine_mode from, || GET_MODE_UNIT_SIZE (from) != GET_MODE_UNIT_SIZE (to))) return false; + if (maybe_ne (BITS_PER_SVE_VECTOR, 128u)) + { + /* Don't allow changes between SVE modes and other modes that might + be bigger than 128 bits. In particular, OImode, CImode and XImode + divide into 128-bit quantities while SVE modes divide into + BITS_PER_SVE_VECTOR quantities. */ + if (from_sve_p && !to_sve_p && maybe_gt (GET_MODE_BITSIZE (to), 128)) + return false; + if (to_sve_p && !from_sve_p && maybe_gt (GET_MODE_BITSIZE (from), 128)) + return false; + } + if (BYTES_BIG_ENDIAN) { /* Don't allow changes between SVE data modes and non-SVE modes. @@ -22003,6 +22485,14 @@ aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1, || element_mode (type2) == BFmode) return N_("operation not permitted on type %"); + if (VECTOR_TYPE_P (type1) + && VECTOR_TYPE_P (type2) + && !TYPE_INDIVISIBLE_P (type1) + && !TYPE_INDIVISIBLE_P (type2) + && (aarch64_sve::builtin_type_p (type1) + != aarch64_sve::builtin_type_p (type2))) + return N_("cannot combine GNU and SVE vectors in a binary operation"); + /* Operation allowed. */ return NULL; } @@ -22167,6 +22657,9 @@ aarch64_run_selftests (void) #undef TARGET_CONDITIONAL_REGISTER_USAGE #define TARGET_CONDITIONAL_REGISTER_USAGE aarch64_conditional_register_usage +#undef TARGET_MEMBER_TYPE_FORCES_BLK +#define TARGET_MEMBER_TYPE_FORCES_BLK aarch64_member_type_forces_blk + /* Only the least significant bit is used for initialization guard variables. */ #undef TARGET_CXX_GUARD_MASK_BIT diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 0bccae8eeee..de28227236a 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d79c4db1aee..8c4425338b3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,31 @@ +2020-04-09 Richard Sandiford + + * 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 * g++.target/arm/cde_mve.C: New test. diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c new file mode 100644 index 00000000000..6cd4f99911e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_1.c @@ -0,0 +1,205 @@ +/* { dg-options "-msve-vector-bits=256" } */ + +#include + +#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) diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_2.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_2.c new file mode 100644 index 00000000000..798491b2128 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_2.c @@ -0,0 +1,3 @@ +/* { dg-options "-msve-vector-bits=512" } */ + +#include "attributes_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_3.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_3.c new file mode 100644 index 00000000000..c3ba5628ceb --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_3.c @@ -0,0 +1,3 @@ +/* { dg-options "-msve-vector-bits=1024" } */ + +#include "attributes_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_4.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_4.c new file mode 100644 index 00000000000..487dba6f748 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_4.c @@ -0,0 +1,3 @@ +/* { dg-options "-msve-vector-bits=2048" } */ + +#include "attributes_1.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_5.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_5.c new file mode 100644 index 00000000000..c7951c92848 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_5.c @@ -0,0 +1,7 @@ +/* { dg-options "-msve-vector-bits=128" } */ + +#if __ARM_BIG_ENDIAN && !__ARM_FEATURE_SVE_BITS +int pass = 1; +#else +#include "attributes_1.c" +#endif diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_6.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_6.c new file mode 100644 index 00000000000..907637f06f9 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_6.c @@ -0,0 +1,97 @@ +/* { dg-options "-O2 -msve-vector-bits=256" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include + +#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 diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c new file mode 100644 index 00000000000..55d9deace0c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/attributes_7.c @@ -0,0 +1,181 @@ +/* { dg-options "-msve-vector-bits=256 -W -Wall" } */ + +#include + +#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; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct.h b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct.h new file mode 100644 index 00000000000..45fa3306beb --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct.h @@ -0,0 +1,77 @@ +#ifndef STRUCT_H +#define STRUCT_H 1 + +#include + +#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 diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_1024.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_1024.c new file mode 100644 index 00000000000..3a4b1b2fdaf --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_1024.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve1024_hw } } } */ +/* { dg-options "-msve-vector-bits=1024" } */ + +#include "struct_1_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_128.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_128.c new file mode 100644 index 00000000000..a7e470047f6 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_128.c @@ -0,0 +1,405 @@ +/* { dg-do run { target { aarch64_sve128_hw } } } */ +/* { dg-require-effective-target aarch64_little_endian } */ +/* { dg-options "-msve-vector-bits=128" } */ + +#include "struct.h" + +struct pst1 +{ + fixed_int8_t v[8]; + fixed_bool_t p[4]; +}; + +ASM_FUNCTION (make_pst1_asm, struct pst1, (), + "mov z0.b, #1\n\t" + "mov z1.b, #4\n\t" + "mov z2.b, #5\n\t" + "mov z3.b, #9\n\t" + "mov z4.b, #14\n\t" + "mov z5.b, #23\n\t" + "mov z6.b, #37\n\t" + "mov z7.b, #60\n\t" + "ptrue p0.b, vl1\n\t" + "ptrue p1.b, vl2\n\t" + "ptrue p2.b, vl3\n\t" + "ptrue p3.b, vl4"); + +#define LOAD_PST1(PTR) \ + "ld1b z0.b, p0/z, [" PTR ", #0, mul vl]\n\t" \ + "ld1b z1.b, p0/z, [" PTR ", #1, mul vl]\n\t" \ + "ld1b z2.b, p0/z, [" PTR ", #2, mul vl]\n\t" \ + "ld1b z3.b, p0/z, [" PTR ", #3, mul vl]\n\t" \ + "ld1b z4.b, p0/z, [" PTR ", #4, mul vl]\n\t" \ + "ld1b z5.b, p0/z, [" PTR ", #5, mul vl]\n\t" \ + "ld1b z6.b, p0/z, [" PTR ", #6, mul vl]\n\t" \ + "ld1b z7.b, p0/z, [" PTR ", #7, mul vl]\n\t" \ + "incb " PTR ", all, mul #8\n\t" \ + "ldr p0, [" PTR ", #0, mul vl]\n\t" \ + "ldr p1, [" PTR ", #1, mul vl]\n\t" \ + "ldr p2, [" PTR ", #2, mul vl]\n\t" \ + "ldr p3, [" PTR ", #3, mul vl]" + +ASM_FUNCTION (passthru_pst1_x0_a, + struct pst1, (svbool_t, struct pst1), + "incp x0, p0.b\n\t" + "sub x0, x0, #11\n\t" + "ptrue p0.b\n\t" + LOAD_PST1 ("x0")); + +ASM_FUNCTION (passthru_pst1_x0_b, + struct pst1, (svbool_t, struct pst1, uint64_t), + "incp x0, p0.b\n\t" + "add x0, x0, x1\n\t" + "sub x0, x0, #52\n\t" + "ptrue p0.b\n\t" + LOAD_PST1 ("x0")); + +ASM_FUNCTION (passthru_pst1_x0_c, + struct pst1, (svbool_t, struct pst1, svbool_t, + svbool_t, svbool_t, svbool_t), + "incp x0, p0.b\n\t" + "ldr p0, [x1]\n\t" + "incp x0, p1.b\n\t" + "incp x0, p2.b\n\t" + "incp x0, p3.b\n\t" + "incp x0, p0.b\n\t" + "sub x0, x0, #27\n\t" + "ptrue p0.b\n\t" + LOAD_PST1 ("x0")); + +ASM_FUNCTION (passthru_pst1_x0_d, + struct pst1, (svfloat32_t, struct pst1), + "ptrue p0.b\n\t" + "fmov z1.s, #1.0\n\t" + "fcmeq p0.s, p0/z, z0.s, z1.s\n\t" + "uzp1 p0.b, p0.b, p0.b\n\t" + "uzp1 p0.b, p0.b, p0.b\n\t" + LOAD_PST1 ("x0")); + +ASM_FUNCTION (passthru_pst1_x0_e, + struct pst1, (svfloat32_t, struct pst1, svint32_t, + svint32_t, svint32_t, svint32_t, + svint32_t, svint32_t, svint32_t), + "ptrue p0.b\n\t" + "fmov z24.s, #4.0\n\t" + "fcmeq p0.s, p0/z, z0.s, z24.s\n\t" + "cmpeq p0.s, p0/z, z1.s, #-4\n\t" + "cmpeq p0.s, p0/z, z2.s, #-9\n\t" + "cmpeq p0.s, p0/z, z3.s, #-14\n\t" + "cmpeq p0.s, p0/z, z4.s, #11\n\t" + "cmpeq p0.s, p0/z, z5.s, #10\n\t" + "cmpeq p0.s, p0/z, z6.s, #8\n\t" + "cmpeq p0.s, p0/z, z7.s, #-1\n\t" + "uzp1 p0.b, p0.b, p0.b\n\t" + "uzp1 p0.b, p0.b, p0.b\n\t" + LOAD_PST1 ("x0")); + +ASM_FUNCTION (passthru_pst1_x7_a, + struct pst1, (svbool_t, + uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t, uint64_t, struct pst1), + "add x0, x0, x1\n\t" + "add x2, x2, x3\n\t" + "add x4, x4, x5\n\t" + "add x0, x0, x2\n\t" + "add x4, x4, x6\n\t" + "add x0, x0, x4\n\t" + "add x7, x7, x0\n\t" + "sub x7, x7, #127\n\t" + "ptrue p0.b\n\t" + LOAD_PST1 ("x7")); + +ASM_FUNCTION (passthru_pst1_x7_b, + struct pst1, (svbool_t, svbool_t, svbool_t, svbool_t, + svbool_t, svbool_t, svbool_t, svbool_t, + svbool_t, svbool_t, svbool_t, + struct pst1), + "and p0.b, p1/z, p0.b, p2.b\n\t" + "ldr p2, [x0]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + "ldr p2, [x1]\n\t" + "ldr p3, [x2]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + "ldr p2, [x3]\n\t" + "ldr p3, [x4]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + "ldr p2, [x5]\n\t" + "ldr p3, [x6]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + LOAD_PST1 ("x7")); + +ASM_FUNCTION (passthru_pst1_sp_a, + struct pst1, (svbool_t, svbool_t, svbool_t, svbool_t, + svbool_t, svbool_t, svbool_t, svbool_t, + svbool_t, svbool_t, svbool_t, svbool_t, + struct pst1), + "and p0.b, p1/z, p0.b, p2.b\n\t" + "ldr p2, [x0]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + "ldr p2, [x1]\n\t" + "ldr p3, [x2]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + "ldr p2, [x3]\n\t" + "ldr p3, [x4]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + "ldr p2, [x5]\n\t" + "ldr p3, [x6]\n\t" + "and p0.b, p2/z, p0.b, p3.b\n\t" + "ldr p2, [x7]\n\t" + "and p0.b, p2/z, p0.b, p0.b\n\t" + "ldr x5, [sp]\n\t" +#if __ILP32__ + "uxtw x5, w5\n\t" +#endif + LOAD_PST1 ("x5")); + +void +test_vl (svbool_t p0, unsigned int vl) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, sveor_z (pg, p0, svwhilelt_b8 (0U, vl)))) + __builtin_abort (); +} + +void +test_pst1 (struct pst1 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, svcmpne (pg, x->v[0], 1)) + || svptest_any (pg, svcmpne (pg, x->v[1], 4)) + || svptest_any (pg, svcmpne (pg, x->v[2], 5)) + || svptest_any (pg, svcmpne (pg, x->v[3], 9)) + || svptest_any (pg, svcmpne (pg, x->v[4], 14)) + || svptest_any (pg, svcmpne (pg, x->v[5], 23)) + || svptest_any (pg, svcmpne (pg, x->v[6], 37)) + || svptest_any (pg, svcmpne (pg, x->v[7], 60)) + || svptest_any (pg, sveor_z (pg, x->p[0], svptrue_pat_b8 (SV_VL1))) + || svptest_any (pg, sveor_z (pg, x->p[1], svptrue_pat_b8 (SV_VL2))) + || svptest_any (pg, sveor_z (pg, x->p[2], svptrue_pat_b8 (SV_VL3))) + || svptest_any (pg, sveor_z (pg, x->p[3], svptrue_pat_b8 (SV_VL4)))) + __builtin_abort (); +} + +struct pst1 +make_pst1 (void) +{ + struct pst1 res; + res.v[0] = svdup_s8 (1); + res.v[1] = svdup_s8 (4); + res.v[2] = svdup_s8 (5); + res.v[3] = svdup_s8 (9); + res.v[4] = svdup_s8 (14); + res.v[5] = svdup_s8 (23); + res.v[6] = svdup_s8 (37); + res.v[7] = svdup_s8 (60); + res.p[0] = svptrue_pat_b8 (SV_VL1); + res.p[1] = svptrue_pat_b8 (SV_VL2); + res.p[2] = svptrue_pat_b8 (SV_VL3); + res.p[3] = svptrue_pat_b8 (SV_VL4); + return res; +} + +struct pst1 +deref_pst1 (struct pst1 *ptr) +{ + return *ptr; +} + +void +consume_pst1 (struct pst1 x) +{ + test_pst1 (&x); +} + +void +consume_pst1_x0_a (svbool_t p0, struct pst1 x0) +{ + test_vl (p0, 11); + test_pst1 (&x0); +} + +void +consume_pst1_x0_b (svbool_t p0, struct pst1 x0, uint64_t x1) +{ + test_vl (p0, 10); + test_pst1 (&x0); + if (x1 != 42) + __builtin_abort (); +} + +void +consume_pst1_x0_c (svbool_t p0, struct pst1 x0, svbool_t p1, + svbool_t p2, svbool_t p3, svbool_t x1) +{ + test_vl (p0, 9); + test_pst1 (&x0); + test_vl (p1, 7); + test_vl (p2, 6); + test_vl (p3, 3); + test_vl (x1, 2); +} + +void +consume_pst1_x0_d (svfloat32_t z0, struct pst1 x0) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, svcmpne (pg, z0, 1.0))) + __builtin_abort (); + test_pst1 (&x0); +} + +void +consume_pst1_x0_e (svfloat32_t z0, struct pst1 x0, + svint32_t z1, svint32_t z2, svint32_t z3, svint32_t z4, + svint32_t z5, svint32_t z6, svint32_t z7) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, svcmpne (pg, z0, 4.0)) + || svptest_any (pg, svcmpne (pg, z1, -4)) + || svptest_any (pg, svcmpne (pg, z2, -9)) + || svptest_any (pg, svcmpne (pg, z3, -14)) + || svptest_any (pg, svcmpne (pg, z4, 11)) + || svptest_any (pg, svcmpne (pg, z5, 10)) + || svptest_any (pg, svcmpne (pg, z6, 8)) + || svptest_any (pg, svcmpne (pg, z7, -1))) + __builtin_abort (); + test_pst1 (&x0); +} + +void +consume_pst1_x7_a (svbool_t p0, uint64_t x0, uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6, + struct pst1 x7) +{ + test_vl (p0, __ARM_FEATURE_SVE_BITS); + if (x0 != 1 + || x1 != 2 + || x2 != 4 + || x3 != 8 + || x4 != 16 + || x5 != 32 + || x6 != 64) + __builtin_abort (); + test_pst1 (&x7); +} + +void +consume_pst1_x7_b (svbool_t p0, svbool_t p1, svbool_t p2, svbool_t p3, + svbool_t x0, svbool_t x1, svbool_t x2, svbool_t x3, + svbool_t x4, svbool_t x5, svbool_t x6, struct pst1 x7) +{ + test_vl (p0, __ARM_FEATURE_SVE_BITS); + test_vl (p1, __ARM_FEATURE_SVE_BITS); + test_vl (p2, __ARM_FEATURE_SVE_BITS); + test_vl (p3, __ARM_FEATURE_SVE_BITS); + test_vl (x0, __ARM_FEATURE_SVE_BITS); + test_vl (x1, __ARM_FEATURE_SVE_BITS); + test_vl (x2, __ARM_FEATURE_SVE_BITS); + test_vl (x3, __ARM_FEATURE_SVE_BITS); + test_vl (x4, __ARM_FEATURE_SVE_BITS); + test_vl (x5, __ARM_FEATURE_SVE_BITS); + test_vl (x6, __ARM_FEATURE_SVE_BITS); + test_pst1 (&x7); +} + +void +consume_pst1_sp_a (svbool_t p0, svbool_t p1, svbool_t p2, svbool_t p3, + svbool_t x0, svbool_t x1, svbool_t x2, svbool_t x3, + svbool_t x4, svbool_t x5, svbool_t x6, svbool_t x7, + struct pst1 sp) +{ + test_vl (p0, __ARM_FEATURE_SVE_BITS); + test_vl (p1, __ARM_FEATURE_SVE_BITS); + test_vl (p2, __ARM_FEATURE_SVE_BITS); + test_vl (p3, __ARM_FEATURE_SVE_BITS); + test_vl (x0, __ARM_FEATURE_SVE_BITS); + test_vl (x1, __ARM_FEATURE_SVE_BITS); + test_vl (x2, __ARM_FEATURE_SVE_BITS); + test_vl (x3, __ARM_FEATURE_SVE_BITS); + test_vl (x4, __ARM_FEATURE_SVE_BITS); + test_vl (x5, __ARM_FEATURE_SVE_BITS); + test_vl (x6, __ARM_FEATURE_SVE_BITS); + test_vl (x7, __ARM_FEATURE_SVE_BITS); + test_pst1 (&sp); +} + +int +main (void) +{ + svbool_t pg = svptrue_b8 (); + svbool_t vl2 = svptrue_pat_b8 (SV_VL2); + svbool_t vl3 = svptrue_pat_b8 (SV_VL3); + svbool_t vl6 = svptrue_pat_b8 (SV_VL6); + svbool_t vl7 = svptrue_pat_b8 (SV_VL7); + svbool_t vl9 = svwhilelt_b8 (0, 9); + svbool_t vl10 = svwhilelt_b8 (0, 10); + svbool_t vl11 = svwhilelt_b8 (0, 11); + + CLEANSE; struct pst1 res1 = make_pst1_asm (); + CLEANSE; test_pst1 (&res1); + CLEANSE; consume_pst1 (make_pst1 ()); + + CLEANSE; struct pst1 res2 = deref_pst1 (&res1); + CLEANSE; test_pst1 (&res2); + CLEANSE; consume_pst1 (res2); + + CLEANSE; struct pst1 res3 = passthru_pst1_x0_a (vl11, res1); + CLEANSE; test_pst1 (&res3); + CLEANSE; consume_pst1_x0_a (vl11, res3); + + CLEANSE; struct pst1 res4 = passthru_pst1_x0_b (vl10, res1, 42); + CLEANSE; test_pst1 (&res4); + CLEANSE; consume_pst1_x0_b (vl10, res4, 42); + + CLEANSE; struct pst1 res5 = passthru_pst1_x0_c (vl9, res1, vl7, + vl6, vl3, vl2); + CLEANSE; test_pst1 (&res5); + CLEANSE; consume_pst1_x0_c (vl9, res5, vl7, + vl6, vl3, vl2); + + CLEANSE; struct pst1 res6 = passthru_pst1_x0_d (svdup_f32 (1.0), res1); + CLEANSE; test_pst1 (&res6); + CLEANSE; consume_pst1_x0_d (svdup_f32 (1.0), res6); + + CLEANSE; struct pst1 res7 = passthru_pst1_x0_e (svdup_f32 (4.0), res1, + svdup_s32 (-4), + svdup_s32 (-9), + svdup_s32 (-14), + svdup_s32 (11), + svdup_s32 (10), + svdup_s32 (8), + svdup_s32 (-1)); + CLEANSE; test_pst1 (&res7); + CLEANSE; consume_pst1_x0_e (svdup_f32 (4.0), res1, + svdup_s32 (-4), + svdup_s32 (-9), + svdup_s32 (-14), + svdup_s32 (11), + svdup_s32 (10), + svdup_s32 (8), + svdup_s32 (-1)); + + CLEANSE; struct pst1 res8 = passthru_pst1_x7_a (pg, 1, 2, 4, 8, + 16, 32, 64, res1); + CLEANSE; test_pst1 (&res8); + CLEANSE; consume_pst1_x7_a (pg, 1, 2, 4, 8, + 16, 32, 64, res8); + + CLEANSE; struct pst1 res9 = passthru_pst1_x7_b (pg, pg, pg, pg, + pg, pg, pg, pg, + pg, pg, pg, res1); + CLEANSE; test_pst1 (&res9); + CLEANSE; consume_pst1_x7_b (pg, pg, pg, pg, + pg, pg, pg, pg, + pg, pg, pg, res9); + + CLEANSE; struct pst1 res10 = passthru_pst1_sp_a (pg, pg, pg, pg, + pg, pg, pg, pg, + pg, pg, pg, pg, res1); + CLEANSE; test_pst1 (&res10); + CLEANSE; consume_pst1_sp_a (pg, pg, pg, pg, + pg, pg, pg, pg, + pg, pg, pg, pg, res10); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_2048.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_2048.c new file mode 100644 index 00000000000..b7721dbb4a8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_2048.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve2048_hw } } } */ +/* { dg-options "-msve-vector-bits=2048" } */ + +#include "struct_1_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_256.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_256.c new file mode 100644 index 00000000000..4cdc62840e7 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_256.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve256_hw } } } */ +/* { dg-options "-msve-vector-bits=256" } */ + +#include "struct_1_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_512.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_512.c new file mode 100644 index 00000000000..07be8c9d434 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_1_512.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve512_hw } } } */ +/* { dg-options "-msve-vector-bits=512" } */ + +#include "struct_1_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_1024.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_1024.c new file mode 100644 index 00000000000..9899c4e81c3 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_1024.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve1024_hw } } } */ +/* { dg-options "-msve-vector-bits=1024" } */ + +#include "struct_2_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_128.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_128.c new file mode 100644 index 00000000000..4a608b969ff --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_128.c @@ -0,0 +1,701 @@ +/* { dg-do run { target { aarch64_sve128_hw } } } */ +/* { dg-require-effective-target aarch64_little_endian } */ +/* { dg-options "-msve-vector-bits=128" } */ + +#include "struct.h" + +struct pst1 +{ + fixed_uint32_t u32; + fixed_uint64_t u64; +}; + +ASM_FUNCTION (make_pst1_asm, struct pst1, (), + "mov z0.s, #0x1ffffe00\n\t" + "mov z1.d, #0x7f80"); + +ASM_FUNCTION (passthru_pst1_asm, struct pst1, (struct pst1), ""); + +ASM_FUNCTION (passthru_pst1_z6_asm, + struct pst1, (svint32_t, svint32_t, svint32_t, svint32_t, + svint32_t, svint32_t, struct pst1), + "mov z0.d, z6.d\n\t" + "mov z1.d, z7.d"); + +ASM_FUNCTION (passthru_pst1_x0_asm, + struct pst1, (svint32_t, svint32_t, svint32_t, svint32_t, + svint32_t, svint32_t, svint32_t, struct pst1), + "ptrue p0.b\n\t" + "ld1w z0.s, p0/z, [x0]\n\t" + "ld1d z1.d, p0/z, [x0, #1, mul vl]"); + +void +test_pst1 (struct pst1 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, svcmpne (pg, x->u32, 0x1ffffe00)) + || svptest_any (pg, svcmpne (pg, x->u64, 0x7f80))) + __builtin_abort (); +} + +struct pst1 deref_pst1 (struct pst1 *ptr) { return *ptr; } +struct pst1 passthru_pst1 (struct pst1 x) { return x; } + +struct pst1 +passthru_pst1_z6 (svint32_t z0, svint32_t z1, svint32_t z2, svint32_t z3, + svint32_t z4, svint32_t z5, struct pst1 z6) +{ + return z6; +} + +struct pst1 +passthru_pst1_x0 (svint32_t z0, svint32_t z1, svint32_t z2, svint32_t z3, + svint32_t z4, svint32_t z5, svint32_t z6, struct pst1 x0) +{ + return x0; +} + +void consume_pst1 (struct pst1 x) { test_pst1 (&x); } + +static void +run_pst1_tests (void) +{ + svint32_t s32 = svdup_s32 (0); + svbool_t pg = svptrue_b8 (); + + CLEANSE; struct pst1 res = make_pst1_asm (); + CLEANSE; test_pst1 (&res); + CLEANSE; consume_pst1 (deref_pst1 (&res)); + CLEANSE; consume_pst1 (passthru_pst1_asm (res)); + CLEANSE; consume_pst1 (passthru_pst1 (res)); + CLEANSE; consume_pst1 (passthru_pst1_z6_asm (s32, s32, s32, s32, + s32, s32, res)); + CLEANSE; consume_pst1 (passthru_pst1_z6 (s32, s32, s32, s32, + s32, s32, res)); + CLEANSE; consume_pst1 (passthru_pst1_x0_asm (s32, s32, s32, s32, + s32, s32, s32, res)); + CLEANSE; consume_pst1 (passthru_pst1_x0 (s32, s32, s32, s32, + s32, s32, s32, res)); +} + +//-------------------------------------------------------------------------- + +struct pst2 +{ + fixed_uint8_t u8; + fixed_uint16_t u16; + struct { + fixed_float64_t f64; + fixed_bool_t pg; + } a[4]; + struct pst1 sub; +}; + +ASM_FUNCTION (make_pst2_asm, struct pst2, (), + "mov z0.b, #100\n\t" + "mov z1.h, #99\n\t" + "fmov z2.d, #1.0\n\t" + "fmov z3.d, #2.0\n\t" + "fmov z4.d, #3.0\n\t" + "fmov z5.d, #4.0\n\t" + "mov z6.s, #98\n\t" + "mov z7.d, #97\n\t" + "ptrue p0.b, vl5\n\t" + "ptrue p1.b, vl6\n\t" + "ptrue p2.b, vl7\n\t" + "ptrue p3.b, vl8"); + +ASM_FUNCTION (passthru_pst2_asm, struct pst2, (struct pst2), ""); + +ASM_FUNCTION (passthru_pst2_x0_asm, struct pst2, (svbool_t, struct pst2), + "cntd x2, all, mul #9\n\t" + "add x2, x2, #15\n\t" + "and x2, x2, #-16\n\t" + "ptrue p0.b\n\t" + "ld1b z0.b, p0/z, [x0, #0, mul vl]\n\t" + "ld1h z1.h, p0/z, [x0, #1, mul vl]\n\t" + "ld1d z2.d, p0/z, [x0, #2, mul vl]\n\t" + "add x1, x0, x2\n\t" + "ld1d z3.d, p0/z, [x1, #2, mul vl]\n\t" + "ldr p1, [x1, #24, mul vl]\n\t" + "add x1, x1, x2\n\t" + "ld1d z4.d, p0/z, [x1, #2, mul vl]\n\t" + "ldr p2, [x1, #24, mul vl]\n\t" + "add x1, x1, x2\n\t" + "ld1d z5.d, p0/z, [x1, #2, mul vl]\n\t" + "ldr p3, [x1, #24, mul vl]\n\t" + "add x1, x1, x2\n\t" + "ld1w z6.s, p0/z, [x1, #2, mul vl]\n\t" + "ld1d z7.d, p0/z, [x1, #3, mul vl]\n\t" + "ldr p0, [x0, #24, mul vl]"); + +void +test_pst2 (struct pst2 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, svcmpne (pg, x->u8, 100)) + || svptest_any (pg, svcmpne (pg, x->u16, 99)) + || svptest_any (pg, svcmpne (pg, x->a[0].f64, 1.0)) + || svptest_any (pg, sveor_z (pg, x->a[0].pg, svptrue_pat_b8 (SV_VL5))) + || svptest_any (pg, svcmpne (pg, x->a[1].f64, 2.0)) + || svptest_any (pg, sveor_z (pg, x->a[1].pg, svptrue_pat_b8 (SV_VL6))) + || svptest_any (pg, svcmpne (pg, x->a[2].f64, 3.0)) + || svptest_any (pg, sveor_z (pg, x->a[2].pg, svptrue_pat_b8 (SV_VL7))) + || svptest_any (pg, svcmpne (pg, x->a[3].f64, 4.0)) + || svptest_any (pg, sveor_z (pg, x->a[3].pg, svptrue_pat_b8 (SV_VL8))) + || svptest_any (pg, svcmpne (pg, x->sub.u32, 98)) + || svptest_any (pg, svcmpne (pg, x->sub.u64, 97))) + __builtin_abort (); +} + +struct pst2 deref_pst2 (struct pst2 *ptr) { return *ptr; } +struct pst2 passthru_pst2 (struct pst2 x) { return x; } + +struct pst2 +passthru_pst2_x0 (svbool_t pg, struct pst2 x0) +{ + return x0; +} + +void +consume_pst2 (struct pst2 x) +{ + test_pst2 (&x); +} + +static void +run_pst2_tests (void) +{ + CLEANSE; struct pst2 res = make_pst2_asm (); + CLEANSE; test_pst2 (&res); + CLEANSE; consume_pst2 (deref_pst2 (&res)); + CLEANSE; consume_pst2 (passthru_pst2_asm (res)); + CLEANSE; consume_pst2 (passthru_pst2 (res)); + CLEANSE; consume_pst2 (passthru_pst2_x0_asm (svptrue_b8 (), res)); + CLEANSE; consume_pst2 (passthru_pst2_x0 (svptrue_b8 (), res)); +} + +//-------------------------------------------------------------------------- + +struct __attribute__((packed, aligned (2))) pst3 +{ + fixed_bool_t p; + fixed_float16_t v; +}; + +ASM_FUNCTION (make_pst3_asm, struct pst3, (), + "ptrue p0.h, vl3\n\t" + "fmov z0.h, #5.0"); + +ASM_FUNCTION (passthru_pst3_asm, struct pst3, (struct pst3), ""); + +ASM_FUNCTION (passthru_pst3_p3_z7_asm, + struct pst3, (svbool_t, svbool_t, svbool_t, + svint32_t, svint32_t, svint32_t, svint32_t, + svint32_t, svint32_t, svint32_t, struct pst3), + "mov z0.d, z7.d\n\t" + "mov p0.b, p3.b"); + +ASM_FUNCTION (passthru_pst3_x0_asm, + struct pst3, (svbool_t, svbool_t, svbool_t, svbool_t, + struct pst3), + "addpl x1, x0, #1\n\t" + "ld1h z0.h, p1/z, [x1]\n\t" + "ldr p0, [x0]"); + +void +test_pst3 (struct pst3 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, sveor_z (pg, x->p, svptrue_pat_b16 (SV_VL3))) + || svptest_any (pg, svcmpne (pg, x->v, 5.0))) + __builtin_abort (); +} + +struct pst3 deref_pst3 (struct pst3 *ptr) { return *ptr; } +struct pst3 passthru_pst3 (struct pst3 x) { return x; } + +struct pst3 +passthru_pst3_p3_z7 (svbool_t p0, svbool_t p1, svbool_t p2, + svint32_t z0, svint32_t z1, svint32_t z2, svint32_t z3, + svint32_t z4, svint32_t z5, svint32_t z6, + struct pst3 p3_z7) +{ + return p3_z7; +} + +struct pst3 +passthru_pst3_x0 (svbool_t p0, svbool_t p1, svbool_t p2, svbool_t p3, + struct pst3 x0) +{ + return x0; +} + +void consume_pst3 (struct pst3 x) { test_pst3 (&x); } + +static void +run_pst3_tests (void) +{ + svint32_t s32 = svdup_s32 (0); + svbool_t pg = svptrue_b8 (); + + CLEANSE; struct pst3 res = make_pst3_asm (); + CLEANSE; test_pst3 (&res); + CLEANSE; consume_pst3 (deref_pst3 (&res)); + CLEANSE; consume_pst3 (passthru_pst3_asm (res)); + CLEANSE; consume_pst3 (passthru_pst3 (res)); + CLEANSE; consume_pst3 (passthru_pst3_p3_z7_asm (pg, pg, pg, + s32, s32, s32, s32, + s32, s32, s32, res)); + CLEANSE; consume_pst3 (passthru_pst3_p3_z7 (pg, pg, pg, + s32, s32, s32, s32, + s32, s32, s32, res)); + CLEANSE; consume_pst3 (passthru_pst3_x0_asm (pg, pg, pg, pg, res)); + CLEANSE; consume_pst3 (passthru_pst3_x0 (pg, pg, pg, pg, res)); +} + +//-------------------------------------------------------------------------- + +struct pst4 +{ + fixed_bool_t p1; + fixed_bool_t p2 __attribute__((aligned (256))); + fixed_bool_t p3 __attribute__((aligned (2048))); +}; + +ASM_FUNCTION (make_pst4_asm, struct pst4, (), + "ptrue p0.h, vl7\n\t" + "ptrue p1.h, mul3\n\t" + "ptrue p2.h, vl5"); + +ASM_FUNCTION (passthru_pst4_asm, struct pst4, (struct pst4), ""); + +ASM_FUNCTION (passthru_pst4_p1_asm, + struct pst4, (svbool_t, struct pst4), + "mov p0.b, p1.b\n\t" + "mov p1.b, p2.b\n\t" + "mov p2.b, p3.b"); + +ASM_FUNCTION (passthru_pst4_x0_asm, + struct pst4, (svbool_t, svbool_t, struct pst4), + "ldr p0, [x0]\n\t" + "add x0, x0, #256\n\t" + "ldr p1, [x0]\n\t" + "add x0, x0, #2048 - 256\n\t" + "ldr p2, [x0]"); + +void +test_pst4 (struct pst4 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, sveor_z (pg, x->p1, svptrue_pat_b16 (SV_VL7))) + || svptest_any (pg, sveor_z (pg, x->p2, svptrue_pat_b16 (SV_MUL3))) + || svptest_any (pg, sveor_z (pg, x->p3, svptrue_pat_b16 (SV_VL5)))) + __builtin_abort (); +} + +struct pst4 deref_pst4 (struct pst4 *ptr) { return *ptr; } +struct pst4 passthru_pst4 (struct pst4 x) { return x; } + +struct pst4 +passthru_pst4_p1 (svbool_t p0, struct pst4 p1) +{ + return p1; +} + +struct pst4 +passthru_pst4_x0 (svbool_t p0, svbool_t p1, struct pst4 x0) +{ + return x0; +} + +void consume_pst4 (struct pst4 x) { test_pst4 (&x); } + +static void +run_pst4_tests (void) +{ + svbool_t pg = svptrue_b8 (); + + CLEANSE; struct pst4 res = make_pst4_asm (); + CLEANSE; test_pst4 (&res); + CLEANSE; consume_pst4 (deref_pst4 (&res)); + CLEANSE; consume_pst4 (passthru_pst4_asm (res)); + CLEANSE; consume_pst4 (passthru_pst4 (res)); + CLEANSE; consume_pst4 (passthru_pst4_p1_asm (pg, res)); + CLEANSE; consume_pst4 (passthru_pst4_p1 (pg, res)); + CLEANSE; consume_pst4 (passthru_pst4_x0_asm (pg, pg, res)); + CLEANSE; consume_pst4 (passthru_pst4_x0 (pg, pg, res)); +} + +//-------------------------------------------------------------------------- + +struct pst5 +{ + fixed_uint16_t v[8]; +}; + +ASM_FUNCTION (make_pst5_asm, struct pst5, (), + "index z0.h, #0, #-1\n\t" + "index z1.h, #0, #-2\n\t" + "index z2.h, #0, #-3\n\t" + "index z3.h, #0, #-4\n\t" + "index z4.h, #0, #-5\n\t" + "index z5.h, #0, #-6\n\t" + "index z6.h, #0, #-7\n\t" + "index z7.h, #0, #-8"); + +ASM_FUNCTION (passthru_pst5_asm, struct pst5, (struct pst5), ""); + +void +test_pst5 (struct pst5 *x) +{ + svbool_t pg = svptrue_b8 (); + for (int i = 0; i < 8; ++i) + if (svptest_any (pg, svcmpne (pg, x->v[i], svindex_u16 (0, -1 - i)))) + __builtin_abort (); +} + +struct pst5 deref_pst5 (struct pst5 *ptr) { return *ptr; } +struct pst5 passthru_pst5 (struct pst5 x) { return x; } + +void consume_pst5 (struct pst5 x) { test_pst5 (&x); } + +static void +run_pst5_tests (void) +{ + CLEANSE; struct pst5 res = make_pst5_asm (); + CLEANSE; test_pst5 (&res); + CLEANSE; consume_pst5 (deref_pst5 (&res)); + CLEANSE; consume_pst5 (passthru_pst5_asm (res)); + CLEANSE; consume_pst5 (passthru_pst5 (res)); +} + +//-------------------------------------------------------------------------- + +struct pst6 +{ + fixed_uint16_t v[9]; +}; + +ASM_FUNCTION (make_pst6_asm, struct pst6, (), + "mov x0, #10\n\t" + "ptrue p0.b\n" + "1:\n\t" + "index z0.h, #0, w0\n\t" + "st1h z0.h, p0, [x8]\n\t" + "add x0, x0, #1\n\t" + "incb x8\n\t" + "cmp x0, #19\n\t" + "bne 1b"); + +ASM_FUNCTION (passthru_pst6_asm, struct pst6, (struct pst6), + "mov x1, x0\n\t" + "mov x0, x8\n\t" + "cntb x2, all, mul #9\n\t" + "b memcpy"); + +void +test_pst6 (struct pst6 *x) +{ + svbool_t pg = svptrue_b8 (); + for (int i = 0; i < 9; ++i) + if (svptest_any (pg, svcmpne (pg, x->v[i], svindex_u16 (0, i + 10)))) + __builtin_abort (); +} + +struct pst6 deref_pst6 (struct pst6 *ptr) { return *ptr; } +struct pst6 passthru_pst6 (struct pst6 x) { return x; } + +void consume_pst6 (struct pst6 x) { test_pst6 (&x); } + +static void +run_pst6_tests (void) +{ + CLEANSE; struct pst6 res = make_pst6_asm (); + CLEANSE; test_pst6 (&res); + CLEANSE; consume_pst6 (deref_pst6 (&res)); + CLEANSE; consume_pst6 (passthru_pst6_asm (res)); + CLEANSE; consume_pst6 (passthru_pst6 (res)); +} + +//-------------------------------------------------------------------------- + +struct pst7 +{ + fixed_bool_t p[2][2]; +}; + +ASM_FUNCTION (make_pst7_asm, struct pst7, (), + "ptrue p0.b, vl6\n\t" + "ptrue p1.b, vl7\n\t" + "ptrue p2.h, vl3\n\t" + "ptrue p3.h, vl2"); + +ASM_FUNCTION (passthru_pst7_asm, struct pst7, (struct pst7), ""); + +void +test_pst7 (struct pst7 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, sveor_z (pg, x->p[0][0], svptrue_pat_b8 (SV_VL6))) + || svptest_any (pg, sveor_z (pg, x->p[0][1], svptrue_pat_b8 (SV_VL7))) + || svptest_any (pg, sveor_z (pg, x->p[1][0], svptrue_pat_b16 (SV_VL3))) + || svptest_any (pg, sveor_z (pg, x->p[1][1], svptrue_pat_b16 (SV_VL2)))) + __builtin_abort (); +} + +struct pst7 deref_pst7 (struct pst7 *ptr) { return *ptr; } +struct pst7 passthru_pst7 (struct pst7 x) { return x; } + +void consume_pst7 (struct pst7 x) { test_pst7 (&x); } + +static void +run_pst7_tests (void) +{ + CLEANSE; struct pst7 res = make_pst7_asm (); + CLEANSE; test_pst7 (&res); + CLEANSE; consume_pst7 (deref_pst7 (&res)); + CLEANSE; consume_pst7 (passthru_pst7_asm (res)); + CLEANSE; consume_pst7 (passthru_pst7 (res)); +} + +//-------------------------------------------------------------------------- + +struct pst8 +{ + fixed_bool_t p[2][3]; +}; + +ASM_FUNCTION (make_pst8_asm, struct pst8, (), + "ptrue p3.h, vl2\n\t" + "str p3, [x8]\n\t" + "ptrue p3.h, vl3\n\t" + "str p3, [x8, #1, mul vl]\n\t" + "ptrue p3.h, vl4\n\t" + "str p3, [x8, #2, mul vl]\n\t" + "ptrue p3.s, vl2\n\t" + "str p3, [x8, #3, mul vl]\n\t" + "ptrue p3.s, vl3\n\t" + "str p3, [x8, #4, mul vl]\n\t" + "ptrue p3.s, vl4\n\t" + "str p3, [x8, #5, mul vl]"); + +ASM_FUNCTION (passthru_pst8_asm, struct pst8, (struct pst8), + "cntw x1, all, mul #3\n\t" + "whilelo p0.b, xzr, x1\n\t" + "ld1b z0.b, p0/z, [x0]\n\t" + "st1b z0.b, p0, [x8]"); + +void +test_pst8 (struct pst8 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, sveor_z (pg, x->p[0][0], svptrue_pat_b16 (SV_VL2))) + || svptest_any (pg, sveor_z (pg, x->p[0][1], svptrue_pat_b16 (SV_VL3))) + || svptest_any (pg, sveor_z (pg, x->p[0][2], svptrue_pat_b16 (SV_VL4))) + || svptest_any (pg, sveor_z (pg, x->p[1][0], svptrue_pat_b32 (SV_VL2))) + || svptest_any (pg, sveor_z (pg, x->p[1][1], svptrue_pat_b32 (SV_VL3))) + || svptest_any (pg, sveor_z (pg, x->p[1][2], svptrue_pat_b32 (SV_VL4)))) + __builtin_abort (); +} + +struct pst8 deref_pst8 (struct pst8 *ptr) { return *ptr; } +struct pst8 passthru_pst8 (struct pst8 x) { return x; } + +void consume_pst8 (struct pst8 x) { test_pst8 (&x); } + +static void +run_pst8_tests (void) +{ + CLEANSE; struct pst8 res = make_pst8_asm (); + CLEANSE; test_pst8 (&res); + CLEANSE; consume_pst8 (deref_pst8 (&res)); + CLEANSE; consume_pst8 (passthru_pst8_asm (res)); + CLEANSE; consume_pst8 (passthru_pst8 (res)); +} + +//-------------------------------------------------------------------------- + +struct nonpst1 +{ + int x; + fixed_uint8_t v; + fixed_bool_t p; +}; + +ASM_FUNCTION (make_nonpst1_asm, struct nonpst1, (), + "mov w0, #42\n\t" + "str w0, [x8]\n\t" + "add x0, x8, #16\n\t" + "ptrue p0.b\n\t" + "index z0.b, #0, #3\n\t" + "st1b z0.b, p0, [x0]\n\t" + "ptrue p3.b, vl5\n\t" + "str p3, [x0, #8, mul vl]"); + +ASM_FUNCTION (passthru_nonpst1_asm, struct nonpst1, (struct nonpst1), + "mov x1, x0\n\t" + "mov x0, x8\n\t" + "cntd x2, all, mul #9\n\t" + "add x2, x2, #16\n\t" + "b memcpy"); + +void +test_nonpst1 (struct nonpst1 *x) +{ + svbool_t pg = svptrue_b8 (); + if (x->x != 42 + || svptest_any (pg, svcmpne (pg, x->v, svindex_u8 (0, 3))) + || svptest_any (pg, sveor_z (pg, x->p, svptrue_pat_b8 (SV_VL5)))) + __builtin_abort (); +} + +struct nonpst1 deref_nonpst1 (struct nonpst1 *ptr) { return *ptr; } +struct nonpst1 passthru_nonpst1 (struct nonpst1 x) { return x; } + +void consume_nonpst1 (struct nonpst1 x) { test_nonpst1 (&x); } + +static void +run_nonpst1_tests (void) +{ + CLEANSE; struct nonpst1 res = make_nonpst1_asm (); + CLEANSE; test_nonpst1 (&res); + CLEANSE; consume_nonpst1 (deref_nonpst1 (&res)); + CLEANSE; consume_nonpst1 (passthru_nonpst1_asm (res)); + CLEANSE; consume_nonpst1 (passthru_nonpst1 (res)); +} + +//-------------------------------------------------------------------------- + +struct nonpst2 +{ + union { struct { fixed_bool_t p; }; }; +}; + +ASM_FUNCTION (make_nonpst2_asm, struct nonpst2, (), + "ptrue p3.h, mul3\n\t" + "cntd x2\n\t" + "cmp x2, #16\n\t" + "b.ls 1f\n\t" + "str p3, [x8]\n\t" + "ret\n" + "1:\n\t" + "addvl sp, sp, #-1\n\t" + "str p3, [sp]\n\t" + "ldp x0, x1, [sp]\n\t" + "addvl sp, sp, #1"); + +ASM_FUNCTION (passthru_nonpst2_asm, struct nonpst2, (struct nonpst2), + "cntb x2\n\t" + "cmp x2, #128\n\t" + "b.eq 1f\n\t" + "b.lo 2f\n\t" + "ldr p3, [x0]\n\t" + "str p3, [x8]\n" + "1:\n\t" + "ret\n" + "2:\n\t" + "mov x3, #-1\n\t" +#if __ARM_BIG_ENDIAN + "lsr x3, x3, x2\n\t" +#else + "lsl x3, x3, x2\n\t" +#endif + "bic x1, x0, x3\n\t" + "cmp x2, #64\n\t" + "csel x0, x0, x1, eq"); + +void +test_nonpst2 (struct nonpst2 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, sveor_z (pg, x->p, svptrue_pat_b16 (SV_MUL3)))) + __builtin_abort (); +} + +struct nonpst2 deref_nonpst2 (struct nonpst2 *ptr) { return *ptr; } +struct nonpst2 passthru_nonpst2 (struct nonpst2 x) { return x; } + +void consume_nonpst2 (struct nonpst2 x) { test_nonpst2 (&x); } + +static void +run_nonpst2_tests (void) +{ + CLEANSE; struct nonpst2 res = make_nonpst2_asm (); + CLEANSE; test_nonpst2 (&res); + CLEANSE; consume_nonpst2 (deref_nonpst2 (&res)); + CLEANSE; consume_nonpst2 (passthru_nonpst2_asm (res)); + CLEANSE; consume_nonpst2 (passthru_nonpst2 (res)); +} + +//-------------------------------------------------------------------------- + +struct nonpst3 +{ + union { struct { fixed_int32_t v; }; }; +}; + +ASM_FUNCTION (make_nonpst3_asm, struct nonpst3, (), + "ptrue p0.b\n\t" + "index z1.s, #15, #-9\n\t" + "cntb x2\n\t" + "cmp x2, #16\n\t" + "b.ls 1f\n\t" + "st1w z1.s, p0, [x8]\n\t" + "ret\n" + "1:\n\t" + "addvl sp, sp, #-1\n\t" + "st1w z1.s, p0, [sp]\n\t" + "ldp x0, x1, [sp]\n\t" + "addvl sp, sp, #1"); + +ASM_FUNCTION (passthru_nonpst3_asm, struct nonpst3, (struct nonpst3), + "cntb x2\n\t" + "cmp x2, #16\n\t" + "b.ls 1f\n\t" + "ptrue p0.b\n\t" + "ld1w z1.s, p0/z, [x0]\n\t" + "st1w z1.s, p0, [x8]\n" + "1:"); + +void +test_nonpst3 (struct nonpst3 *x) +{ + svbool_t pg = svptrue_b8 (); + if (svptest_any (pg, svcmpne (pg, x->v, svindex_s32 (15, -9)))) + __builtin_abort (); +} + +struct nonpst3 deref_nonpst3 (struct nonpst3 *ptr) { return *ptr; } +struct nonpst3 passthru_nonpst3 (struct nonpst3 x) { return x; } + +void consume_nonpst3 (struct nonpst3 x) { test_nonpst3 (&x); } + +static void +run_nonpst3_tests (void) +{ + CLEANSE; struct nonpst3 res = make_nonpst3_asm (); + CLEANSE; test_nonpst3 (&res); + CLEANSE; consume_nonpst3 (deref_nonpst3 (&res)); + CLEANSE; consume_nonpst3 (passthru_nonpst3_asm (res)); + CLEANSE; consume_nonpst3 (passthru_nonpst3 (res)); +} + +//-------------------------------------------------------------------------- + +int +main (void) +{ + run_pst1_tests (); + run_pst2_tests (); + run_pst3_tests (); + run_pst4_tests (); + run_pst5_tests (); + run_pst6_tests (); + run_pst7_tests (); + run_pst8_tests (); + run_nonpst1_tests (); + run_nonpst2_tests (); + run_nonpst3_tests (); + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_2048.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_2048.c new file mode 100644 index 00000000000..6df410d4713 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_2048.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve2048_hw } } } */ +/* { dg-options "-msve-vector-bits=2048" } */ + +#include "struct_2_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_256.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_256.c new file mode 100644 index 00000000000..230fa8c9664 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_256.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve256_hw } } } */ +/* { dg-options "-msve-vector-bits=256" } */ + +#include "struct_2_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_512.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_512.c new file mode 100644 index 00000000000..e6d0512c3cd --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_2_512.c @@ -0,0 +1,4 @@ +/* { dg-do run { target { aarch64_sve512_hw } } } */ +/* { dg-options "-msve-vector-bits=512" } */ + +#include "struct_2_128.c" diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_128.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_128.c new file mode 100644 index 00000000000..443ce4cca6e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_128.c @@ -0,0 +1,1092 @@ +/* { dg-options "-O -msve-vector-bits=128" } */ +/* { dg-require-effective-target aarch64_little_endian } +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "struct.h" + +#define CONSUME(VAR) \ + { \ + register void *ptr_ asm ("x7") = &(VAR); \ + asm volatile ("" :: "r" (ptr_) : "memory"); \ + } + +#define SEL2(TAG, TYPE) \ + TAG TYPE \ + sel2_##TYPE (TAG TYPE x, TAG TYPE y) \ + { \ + return y; \ + } + +#define WRAP(TYPE) \ + struct wrap_##TYPE \ + { \ + TYPE data; \ + }; \ + SEL2 (struct, wrap_##TYPE) + +/* +** sel2_wrap_fixed_int8_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int8_t\n} } } */ +WRAP (fixed_int8_t); + +/* +** sel2_wrap_fixed_int16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int16_t\n} } } */ +WRAP (fixed_int16_t); + +/* +** sel2_wrap_fixed_int32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int32_t\n} } } */ +WRAP (fixed_int32_t); + +/* +** sel2_wrap_fixed_int64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int64_t\n} } } */ +WRAP (fixed_int64_t); + +/* +** sel2_wrap_fixed_uint8_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint8_t\n} } } */ +WRAP (fixed_uint8_t); + +/* +** sel2_wrap_fixed_uint16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint16_t\n} } } */ +WRAP (fixed_uint16_t); + +/* +** sel2_wrap_fixed_uint32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint32_t\n} } } */ +WRAP (fixed_uint32_t); + +/* +** sel2_wrap_fixed_uint64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint64_t\n} } } */ +WRAP (fixed_uint64_t); + +/* +** sel2_wrap_fixed_bfloat16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_bfloat16_t\n} } } */ +WRAP (fixed_bfloat16_t); + +/* +** sel2_wrap_fixed_float16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float16_t\n} } } */ +WRAP (fixed_float16_t); + +/* +** sel2_wrap_fixed_float32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float32_t\n} } } */ +WRAP (fixed_float32_t); + +/* +** sel2_wrap_fixed_float64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float64_t\n} } } */ +WRAP (fixed_float64_t); + +/* +** sel2_wrap_fixed_bool_t: +** mov p0\.b, p1\.b +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_bool_t\n} } } */ +WRAP (fixed_bool_t); + +struct pst_arr1 +{ + fixed_uint8_t u8[1]; +}; + +/* +** sel2_pst_arr1: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr1\n} } } */ +SEL2 (struct, pst_arr1) + +/* +** test_pst_arr1: +** eor z0\.b, z0\.b, #(?:0x)?1 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr1\n} } } */ +svuint8_t +test_pst_arr1 (struct pst_arr1 x) +{ + return sveor_x (svptrue_b8 (), x.u8[0], 1); +} + +struct pst_arr2 +{ + fixed_uint8_t u8[2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr2\n} } } */ +SEL2 (struct, pst_arr2) + +/* +** test_pst_arr2: +** sub z0\.b, z0\.b, z1\.b +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr2\n} } } */ +svuint8_t +test_pst_arr2 (struct pst_arr2 x) +{ + return svsub_x (svptrue_b8 (), x.u8[0], x.u8[1]); +} + +struct pst_arr3 +{ + fixed_uint16_t u16[3]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr3\n} } } */ +SEL2 (struct, pst_arr3) + +/* +** test_pst_arr3: +** sub z0\.h, z0\.h, z2\.h +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr3\n} } } */ +svuint16_t +test_pst_arr3 (struct pst_arr3 x) +{ + return svsub_x (svptrue_b8 (), x.u16[0], x.u16[2]); +} + +struct pst_arr4 +{ + fixed_uint32_t u32[4]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr4\n} } } */ +SEL2 (struct, pst_arr4) + +/* +** test_pst_arr4: +** sub z0\.s, z0\.s, z3\.s +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr4\n} } } */ +svuint32_t +test_pst_arr4 (struct pst_arr4 x) +{ + return svsub_x (svptrue_b8 (), x.u32[0], x.u32[3]); +} + +struct pst_arr5 +{ + fixed_uint64_t u64[2][2][2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr5\n} } } */ +SEL2 (struct, pst_arr5) + +/* +** test_pst_arr5: +** sub sp, sp, #128 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** str z3, \[sp, #3, mul vl\] +** str z4, \[sp, #4, mul vl\] +** str z5, \[sp, #5, mul vl\] +** str z6, \[sp, #6, mul vl\] +** str z7, \[sp, #7, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?128 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5\n} } } */ +void +test_pst_arr5 (struct pst_arr5 x) +{ + CONSUME (x); +} + +/* +** test_pst_arr5_x0: +** ( +** mov z0\.d, z7\.d +** mov (x7, x0|w7, w0) +** | +** mov (x7, x0|w7, w0) +** mov z0\.d, z7\.d +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_x0\n} } } */ +svint32_t +test_pst_arr5_x0 (svint32_t z0, struct pst_arr5 x, + svint32_t z1, svint32_t z2, svint32_t z3, svint32_t z4, + svint32_t z5, svint32_t z6, svint32_t z7) +{ + CONSUME (x); + return z7; +} + +/* +** test_pst_arr5_x7: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_x7\n} } } */ +svint32_t +test_pst_arr5_x7 (svint32_t z0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, struct pst_arr5 x) +{ + CONSUME (x); + return z0; +} + +/* +** test_pst_arr5_sp: { target lp64 } +** ldr x7, \[sp\] +** ret +*/ +/* +** test_pst_arr5_sp: { target ilp32 } +** ldr w7, \[sp\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_sp\n} } } */ +svint32_t +test_pst_arr5_sp (svint32_t z0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, int x7, struct pst_arr5 x) +{ + CONSUME (x); + return z0; +} + +struct pst_arr6 +{ + fixed_bool_t b[2][2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr6\n} } } */ +SEL2 (struct, pst_arr6) + +/* +** test_pst_arr6: +** ... +** brkpa p0\.b, p0/z, p2\.b, p3\.b +** ... +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6\n} } } */ +fixed_bool_t +test_pst_arr6 (struct pst_arr6 x) +{ + return svbrkpa_z (x.b[0][0], x.b[1][0], x.b[1][1]); +} + +/* +** test_pst_arr6_x0: +** ( +** mov p0\.b, p3\.b +** mov (x7, x0|w7, w0) +** | +** mov (x7, x0|w7, w0) +** mov p0\.b, p3\.b +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_x0\n} } } */ +fixed_bool_t +test_pst_arr6_x0 (svbool_t p0, struct pst_arr6 x, svbool_t p1, svbool_t p2, + svbool_t p3) +{ + CONSUME (x); + return p3; +} + +/* +** test_pst_arr6_x7: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_x7\n} } } */ +fixed_bool_t +test_pst_arr6_x7 (svbool_t p0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, struct pst_arr6 x) +{ + CONSUME (x); + return p0; +} + +/* +** test_pst_arr6_sp: { target lp64 } +** ldr x7, \[sp\] +** ret +*/ +/* +** test_pst_arr6_sp: { target ilp32 } +** ldr w7, \[sp\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_sp\n} } } */ +fixed_bool_t +test_pst_arr6_sp (svbool_t p0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, int x7, struct pst_arr6 x) +{ + CONSUME (x); + return p0; +} + +struct pst_uniform1 +{ + fixed_int8_t a, b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform1\n} } } */ +SEL2 (struct, pst_uniform1) + +/* +** test_pst_uniform1: +** sub sp, sp, #32 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?32 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform1\n} } } */ +void +test_pst_uniform1 (struct pst_uniform1 x) +{ + CONSUME (x); +} + +struct pst_uniform2 +{ + fixed_int16_t a; + fixed_int16_t b[2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform2\n} } } */ +SEL2 (struct, pst_uniform2) + +/* +** test_pst_uniform2: +** sub sp, sp, #48 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?48 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform2\n} } } */ +void +test_pst_uniform2 (struct pst_uniform2 x) +{ + CONSUME (x); +} + +struct pst_uniform3 +{ + fixed_int32_t a; + fixed_int32_t b[2]; + fixed_int32_t c; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform3\n} } } */ +SEL2 (struct, pst_uniform3) + +/* +** test_pst_uniform3: +** sub sp, sp, #64 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** str z3, \[sp, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?64 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform3\n} } } */ +void +test_pst_uniform3 (struct pst_uniform3 x) +{ + CONSUME (x); +} + +struct pst_uniform4 +{ + fixed_int32_t a __attribute__((aligned(SVE_BYTES * 2))); + fixed_int32_t b[3] __attribute__((aligned(SVE_BYTES * 2))); + fixed_int32_t c __attribute__((aligned(SVE_BYTES * 2))); +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform4\n} } } */ +SEL2 (struct, pst_uniform4) + +/* +** test_pst_uniform4: +** sub sp, sp, #144 +** add (x[0-9]+), sp, #?31 +** and x7, \1, #?(?:-32|4294967264) +** ptrue (p[0-7])\.b, vl16 +** st1w z0\.s, \2, \[x7\] +** add (x[0-9]+), x7, #?32 +** str z1, \[\3\] +** str z2, \[\3, #1, mul vl\] +** str z3, \[\3, #2, mul vl\] +** st1w z4\.s, \2, \[x7, #6, mul vl\] +** add sp, sp, #?144 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform4\n} } } */ +void +test_pst_uniform4 (struct pst_uniform4 x) +{ + CONSUME (x); +} + +struct pst_mixed1 +{ + fixed_bool_t p0; + fixed_bfloat16_t z0; + fixed_float16_t z1; + fixed_float32_t z2; + fixed_float64_t z3; + fixed_bool_t p1; + fixed_bool_t p2; + fixed_int8_t z4; + fixed_int16_t z5; + fixed_int32_t z6; + fixed_int64_t z7; + fixed_bool_t p3; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_mixed1\n} } } */ +SEL2 (struct, pst_mixed1) + +/* +** test_pst_mixed1: +** sub sp, sp, #176 +** str p0, \[sp\] +** ptrue p0\.b, vl16 +** st1h z0\.h, p0, \[sp, #1, mul vl\] +** st1h z1\.h, p0, \[sp, #2, mul vl\] +** st1w z2\.s, p0, \[sp, #3, mul vl\] +** st1d z3\.d, p0, \[sp, #4, mul vl\] +** str p1, \[sp, #40, mul vl\] +** str p2, \[sp, #41, mul vl\] +** st1b z4\.b, p0, \[sp, #6, mul vl\] +** st1h z5\.h, p0, \[sp, #7, mul vl\] +** ... +** st1w z6\.s, p0, [^\n]* +** ... +** st1d z7\.d, p0, [^\n]* +** ... +** str p3, \[sp, #80, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?176 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_mixed1\n} } } */ +void +test_pst_mixed1 (struct pst_mixed1 x) +{ + CONSUME (x); +} + +struct pst_mixed2 +{ + struct __attribute__ ((packed)) { + fixed_bool_t p; + fixed_int8_t z; + } a[3]; + fixed_int16_t b[1][1][1][4]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_mixed2\n} } } */ +SEL2 (struct, pst_mixed2) + +/* +** test_pst_mixed2: +** sub sp, sp, #128 +** str p0, \[sp\] +** ptrue (p[03])\.b, vl16 +** add (x[0-9]+), sp, #?2 +** st1b z0\.b, \1, \[\2\] +** str p1, \[sp, #9, mul vl\] +** add (x[0-9]+), sp, #?20 +** st1b z1\.b, \1, \[\3\] +** str p2, \[sp, #18, mul vl\] +** add (x[0-9]+), sp, #?38 +** st1b z2\.b, \1, \[\4\] +** str z3, \[sp, #4, mul vl\] +** str z4, \[sp, #5, mul vl\] +** str z5, \[sp, #6, mul vl\] +** str z6, \[sp, #7, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?128 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_mixed2\n} } } */ +void +test_pst_mixed2 (struct pst_mixed2 x) +{ + CONSUME (x); +} + +struct pst_big1 +{ + fixed_int8_t a[9]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big1\n} } } */ +SEL2 (struct, pst_big1) + +/* +** test_pst_big1_a: { target lp64 } +** ptrue (p[0-7])\.b, vl16 +** ld1b z0\.b, \1/z, \[x0\] +** ret +*/ +/* +** test_pst_big1_a: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl16 +** ld1b z0\.b, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big1_a\n} } } */ +svint8_t +test_pst_big1_a (struct pst_big1 x) +{ + return x.a[0]; +} + +/* +** test_pst_big1_b: { target lp64 } +** add x7, x0, #?128 +** ret +*/ +/* +** test_pst_big1_b: { target ilp32 } +** add w7, w0, #?128 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big1_b\n} } } */ +svint8_t +test_pst_big1_b (struct pst_big1 x) +{ + CONSUME (x.a[8]); +} + +struct pst_big2 +{ + fixed_bool_t a[5]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big2\n} } } */ +SEL2 (struct, pst_big2) + +/* +** test_pst_big2_a: { target lp64 } +** ldr p0, \[x0\] +** ret +*/ +/* +** test_pst_big2_a: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big2_a\n} } } */ +svbool_t +test_pst_big2_a (struct pst_big2 x) +{ + return x.a[0]; +} + +/* +** test_pst_big2_b: { target lp64 } +** ldr p0, \[x0, #4, mul vl\] +** ret +*/ +/* +** test_pst_big2_b: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #4, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big2_b\n} } } */ +svbool_t +test_pst_big2_b (struct pst_big2 x) +{ + return x.a[4]; +} + +struct pst_big3 +{ + fixed_bool_t p0; + fixed_int8_t a[2]; + fixed_bool_t p1; + fixed_bool_t p2; + fixed_bool_t p3; + fixed_int8_t b[6]; + fixed_bool_t p4; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big3\n} } } */ +SEL2 (struct, pst_big3) + +/* +** test_pst_big3_a: { target lp64 } +** ldr p0, \[x0\] +** ret +*/ +/* +** test_pst_big3_a: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_a\n} } } */ +svbool_t +test_pst_big3_a (struct pst_big3 x) +{ + return x.p0; +} + +/* +** test_pst_big3_b: { target lp64 } +** ldr p0, \[x0, #24, mul vl\] +** ret +*/ +/* +** test_pst_big3_b: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #24, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_b\n} } } */ +svbool_t +test_pst_big3_b (struct pst_big3 x) +{ + return x.p1; +} + +/* +** test_pst_big3_c: { target lp64 } +** ldr p0, \[x0, #25, mul vl\] +** ret +*/ +/* +** test_pst_big3_c: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #25, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_c\n} } } */ +svbool_t +test_pst_big3_c (struct pst_big3 x) +{ + return x.p2; +} + +/* +** test_pst_big3_d: { target lp64 } +** ldr p0, \[x0, #80, mul vl\] +** ret +*/ +/* +** test_pst_big3_d: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #80, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_d\n} } } */ +svbool_t +test_pst_big3_d (struct pst_big3 x) +{ + return x.p4; +} + +/* +** test_pst_big3_e: { target lp64 } +** ptrue (p[0-7])\.b, vl16 +** ld1b z0\.b, \1/z, \[x0, #1, mul vl\] +** ret +*/ +/* +** test_pst_big3_e: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl16 +** ld1b z0\.b, \1/z, \[x0, #1, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_e\n} } } */ +svint8_t +test_pst_big3_e (struct pst_big3 x) +{ + return x.a[0]; +} + +/* +** test_pst_big3_f: { target lp64 } +** ptrue (p[0-7])\.b, vl16 +** ld1b z0\.b, \1/z, \[x0, #5, mul vl\] +** ret +*/ +/* +** test_pst_big3_f: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl16 +** ld1b z0\.b, \1/z, \[x0, #5, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_f\n} } } */ +svint8_t +test_pst_big3_f (struct pst_big3 x) +{ + return x.b[1]; +} + +struct pst_zero1 +{ + fixed_bool_t a[0]; + fixed_int32_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero1\n} } } */ +SEL2 (struct, pst_zero1) + +/* +** test_pst_zero1: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero1\n} } } */ +svint32_t +test_pst_zero1 (struct pst_zero1 x) +{ + return x.b; +} + +struct pst_zero2 +{ + unsigned int : 0; + fixed_bool_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero2\n} } } */ +SEL2 (struct, pst_zero2) + +/* +** test_pst_zero2: +** ( +** sub sp, sp, #16 +** add sp, sp, #?16 +** | +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero2\n} } } */ +svbool_t +test_pst_zero2 (struct pst_zero2 x) +{ + return x.b; +} + +struct pst_zero3 +{ + struct {} empty; + fixed_uint64_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero3\n} } } */ +SEL2 (struct, pst_zero3) + +/* +** test_pst_zero3: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero3\n} } } */ +svuint64_t +test_pst_zero3 (struct pst_zero3 x) +{ + return x.b; +} + +typedef unsigned char small_vec __attribute__((vector_size(SVE_BYTES / 4))); + +struct nonpst1 +{ + small_vec a[4]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst1\n} } } */ +SEL2 (struct, nonpst1) + +/* +** test_nonpst1: +** ... +** lsr x0, x1, #?32 +** ... +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\ttest_nonpst1\n} } } */ +small_vec +test_nonpst1 (struct nonpst1 x) +{ + return x.a[3]; +} + +union nonpst2 +{ + struct { + fixed_bool_t a[0]; + fixed_int32_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst2\n} } } */ +SEL2 (union, nonpst2) + +/* +** test_nonpst2: +** sub sp, sp, #16 +** stp x0, x1, \[sp\] +** ... +** ldr z0, \[sp\] +** add sp, sp, #?16 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst2\n} } } */ +svint32_t +test_nonpst2 (union nonpst2 x) +{ + return x.b; +} + +/* +** ret_nonpst2: +** mov x0, #?1 +** movk x0, #?0x3, lsl #?32 +** mov x1, #?5 +** movk x1, #?0x7, lsl #?32 +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst2\n} } } */ +union nonpst2 +ret_nonpst2 (void) +{ + return (union nonpst2) { { {}, 1, 3, 5, 7 } }; +} + +union nonpst3 +{ + struct { + unsigned int : 0; + fixed_bool_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst3\n} } } */ +SEL2 (union, nonpst3) + +/* +** test_nonpst3: +** sub sp, sp, #16 +** strh w0, \[sp, #?6\] +** ldr p0, \[sp, #3, mul vl\] +** add sp, sp, #?16 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst3\n} } } */ +svbool_t +test_nonpst3 (union nonpst3 x) +{ + return x.b; +} + +/* +** ret_nonpst3: { xfail *-*-* } +** mov w0, #?(?:0xffff|65535) +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst3\n} } } */ +union nonpst3 +ret_nonpst3 (void) +{ + return (union nonpst3) { { svptrue_b8 () } }; +} + +union nonpst4 +{ + struct { + struct {} empty; + fixed_uint64_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst4\n} } } */ +SEL2 (union, nonpst4) + +/* +** test_nonpst4: +** sub sp, sp, #16 +** stp x0, x1, \[sp\] +** ... +** ldr z0, \[sp\] +** add sp, sp, #?16 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst4\n} } } */ +svuint64_t +test_nonpst4 (union nonpst4 x) +{ + return x.b; +} + +/* +** ret_nonpst4: +** mov x0, 1 +** mov x1, 2 +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst4\n} } } */ +union nonpst4 +ret_nonpst4 (void) +{ + return (union nonpst4) { { {}, 1, 2 } }; +} + +struct nonpst5 +{ + union { + fixed_uint16_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst5\n} } } */ +SEL2 (struct, nonpst5) + +/* +** test_nonpst5: +** sub sp, sp, #16 +** stp x0, x1, \[sp\] +** ... +** ldr z0, \[sp\] +** add sp, sp, #?16 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst5\n} } } */ +svuint16_t +test_nonpst5 (struct nonpst5 x) +{ + return x.b; +} + +struct nonpst6 +{ + fixed_uint64_t b; + fixed_uint64_t *ptr; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst6\n} } } */ +SEL2 (struct, nonpst6) + +/* +** test_nonpst6: { target lp64 } +** ptrue (p[0-3])\.b, vl16 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst6: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-3])\.b, vl16 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst6\n} } } */ +svuint64_t +test_nonpst6 (struct nonpst6 x) +{ + return x.b; +} + +struct nonpst7 +{ + fixed_uint64_t b; + uint32_t foo __attribute__((vector_size(SVE_BYTES))); +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst7\n} } } */ +SEL2 (struct, nonpst7) + +/* +** test_nonpst7: { target lp64 } +** ptrue (p[0-3])\.b, vl16 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst7: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-3])\.b, vl16 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst7\n} } } */ +svuint64_t +test_nonpst7 (struct nonpst7 x) +{ + return x.b; +} + +typedef unsigned char tiny_vec __attribute__((vector_size(SVE_BYTES / 8))); + +struct nonpst8 +{ + tiny_vec a; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst8\n} } } */ +SEL2 (struct, nonpst8) + +/* +** test_nonpst8: +** ubfx x0, x0, 8, 8 +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\ttest_nonpst8\n} } } */ +unsigned int +test_nonpst8 (struct nonpst8 x) +{ + return x.a[1]; +} + +/* +** ret_nonpst8: +** ( +** sub sp, sp, #16 +** mov w0, #?513 +** add sp, sp, #?16 +** | +** mov w0, #?513 +** ) +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst8\n} } } */ +struct nonpst8 +ret_nonpst8 (void) +{ + return (struct nonpst8) { { 1, 2 } }; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_256.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_256.c new file mode 100644 index 00000000000..fdfbec51bf8 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_256.c @@ -0,0 +1,1231 @@ +/* { dg-options "-O -msve-vector-bits=256" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "struct.h" + +#define CONSUME(VAR) \ + { \ + register void *ptr_ asm ("x7") = &(VAR); \ + asm volatile ("" :: "r" (ptr_) : "memory"); \ + } + +#define SEL2(TAG, TYPE) \ + TAG TYPE \ + sel2_##TYPE (TAG TYPE x, TAG TYPE y) \ + { \ + return y; \ + } + +#define WRAP(TYPE) \ + struct wrap_##TYPE \ + { \ + TYPE data; \ + }; \ + SEL2 (struct, wrap_##TYPE) + +/* +** sel2_wrap_fixed_int8_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int8_t\n} } } */ +WRAP (fixed_int8_t); + +/* +** sel2_wrap_fixed_int16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int16_t\n} } } */ +WRAP (fixed_int16_t); + +/* +** sel2_wrap_fixed_int32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int32_t\n} } } */ +WRAP (fixed_int32_t); + +/* +** sel2_wrap_fixed_int64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int64_t\n} } } */ +WRAP (fixed_int64_t); + +/* +** sel2_wrap_fixed_uint8_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint8_t\n} } } */ +WRAP (fixed_uint8_t); + +/* +** sel2_wrap_fixed_uint16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint16_t\n} } } */ +WRAP (fixed_uint16_t); + +/* +** sel2_wrap_fixed_uint32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint32_t\n} } } */ +WRAP (fixed_uint32_t); + +/* +** sel2_wrap_fixed_uint64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint64_t\n} } } */ +WRAP (fixed_uint64_t); + +/* +** sel2_wrap_fixed_bfloat16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_bfloat16_t\n} } } */ +WRAP (fixed_bfloat16_t); + +/* +** sel2_wrap_fixed_float16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float16_t\n} } } */ +WRAP (fixed_float16_t); + +/* +** sel2_wrap_fixed_float32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float32_t\n} } } */ +WRAP (fixed_float32_t); + +/* +** sel2_wrap_fixed_float64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float64_t\n} } } */ +WRAP (fixed_float64_t); + +/* +** sel2_wrap_fixed_bool_t: +** mov p0\.b, p1\.b +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_bool_t\n} } } */ +WRAP (fixed_bool_t); + +struct pst_arr1 +{ + fixed_uint8_t u8[1]; +}; + +/* +** sel2_pst_arr1: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr1\n} } } */ +SEL2 (struct, pst_arr1) + +/* +** test_pst_arr1: +** eor z0\.b, z0\.b, #(?:0x)?1 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr1\n} } } */ +svuint8_t +test_pst_arr1 (struct pst_arr1 x) +{ + return sveor_x (svptrue_b8 (), x.u8[0], 1); +} + +struct pst_arr2 +{ + fixed_uint8_t u8[2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr2\n} } } */ +SEL2 (struct, pst_arr2) + +/* +** test_pst_arr2: +** sub z0\.b, z0\.b, z1\.b +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr2\n} } } */ +svuint8_t +test_pst_arr2 (struct pst_arr2 x) +{ + return svsub_x (svptrue_b8 (), x.u8[0], x.u8[1]); +} + +struct pst_arr3 +{ + fixed_uint16_t u16[3]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr3\n} } } */ +SEL2 (struct, pst_arr3) + +/* +** test_pst_arr3: +** sub z0\.h, z0\.h, z2\.h +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr3\n} } } */ +svuint16_t +test_pst_arr3 (struct pst_arr3 x) +{ + return svsub_x (svptrue_b8 (), x.u16[0], x.u16[2]); +} + +struct pst_arr4 +{ + fixed_uint32_t u32[4]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr4\n} } } */ +SEL2 (struct, pst_arr4) + +/* +** test_pst_arr4: +** sub z0\.s, z0\.s, z3\.s +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr4\n} } } */ +svuint32_t +test_pst_arr4 (struct pst_arr4 x) +{ + return svsub_x (svptrue_b8 (), x.u32[0], x.u32[3]); +} + +struct pst_arr5 +{ + fixed_uint64_t u64[2][2][2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr5\n} } } */ +SEL2 (struct, pst_arr5) + +/* +** test_pst_arr5: { target aarch64_little_endian } +** sub sp, sp, #256 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** str z3, \[sp, #3, mul vl\] +** str z4, \[sp, #4, mul vl\] +** str z5, \[sp, #5, mul vl\] +** str z6, \[sp, #6, mul vl\] +** str z7, \[sp, #7, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?256 +** ret +*/ +/* +** test_pst_arr5: { target aarch64_big_endian } +** sub sp, sp, #256 +** ptrue (p[0-3])\.b, vl32 +** st1d z0\.d, \1, \[sp\] +** st1d z1\.d, \1, \[sp, #1, mul vl\] +** st1d z2\.d, \1, \[sp, #2, mul vl\] +** st1d z3\.d, \1, \[sp, #3, mul vl\] +** st1d z4\.d, \1, \[sp, #4, mul vl\] +** st1d z5\.d, \1, \[sp, #5, mul vl\] +** st1d z6\.d, \1, \[sp, #6, mul vl\] +** st1d z7\.d, \1, \[sp, #7, mul vl\] +** mov ((x7, sp|w7, wsp)|w7, wsp) +** add sp, sp, #?256 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5\n} } } */ +void +test_pst_arr5 (struct pst_arr5 x) +{ + CONSUME (x); +} + +/* +** test_pst_arr5_x0: +** ( +** mov z0\.d, z7\.d +** mov (x7, x0|w7, w0) +** | +** mov (x7, x0|w7, w0) +** mov z0\.d, z7\.d +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_x0\n} } } */ +svint32_t +test_pst_arr5_x0 (svint32_t z0, struct pst_arr5 x, + svint32_t z1, svint32_t z2, svint32_t z3, svint32_t z4, + svint32_t z5, svint32_t z6, svint32_t z7) +{ + CONSUME (x); + return z7; +} + +/* +** test_pst_arr5_x7: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_x7\n} } } */ +svint32_t +test_pst_arr5_x7 (svint32_t z0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, struct pst_arr5 x) +{ + CONSUME (x); + return z0; +} + +/* +** test_pst_arr5_sp: { target lp64 } +** ldr x7, \[sp\] +** ret +*/ +/* +** test_pst_arr5_sp: { target ilp32 } +** ldr w7, \[sp(, 4)?\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_sp\n} } } */ +svint32_t +test_pst_arr5_sp (svint32_t z0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, int x7, struct pst_arr5 x) +{ + CONSUME (x); + return z0; +} + +struct pst_arr6 +{ + fixed_bool_t b[2][2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr6\n} } } */ +SEL2 (struct, pst_arr6) + +/* +** test_pst_arr6: +** ... +** brkpa p0\.b, p0/z, p2\.b, p3\.b +** ... +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6\n} } } */ +fixed_bool_t +test_pst_arr6 (struct pst_arr6 x) +{ + return svbrkpa_z (x.b[0][0], x.b[1][0], x.b[1][1]); +} + +/* +** test_pst_arr6_x0: +** ( +** mov p0\.b, p3\.b +** mov (x7, x0|w7, w0) +** | +** mov (x7, x0|w7, w0) +** mov p0\.b, p3\.b +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_x0\n} } } */ +fixed_bool_t +test_pst_arr6_x0 (svbool_t p0, struct pst_arr6 x, svbool_t p1, svbool_t p2, + svbool_t p3) +{ + CONSUME (x); + return p3; +} + +/* +** test_pst_arr6_x7: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_x7\n} } } */ +fixed_bool_t +test_pst_arr6_x7 (svbool_t p0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, struct pst_arr6 x) +{ + CONSUME (x); + return p0; +} + +/* +** test_pst_arr6_sp: { target lp64 } +** ldr x7, \[sp\] +** ret +*/ +/* +** test_pst_arr6_sp: { target ilp32 } +** ldr w7, \[sp(, 4)?\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_sp\n} } } */ +fixed_bool_t +test_pst_arr6_sp (svbool_t p0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, int x7, struct pst_arr6 x) +{ + CONSUME (x); + return p0; +} + +struct pst_uniform1 +{ + fixed_int8_t a, b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform1\n} } } */ +SEL2 (struct, pst_uniform1) + +/* +** test_pst_uniform1: { target aarch64_little_endian } +** sub sp, sp, #64 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?64 +** ret +*/ +/* +** test_pst_uniform1: { target aarch64_big_endian } +** sub sp, sp, #64 +** ptrue (p[0-3])\.b, vl32 +** st1b z0\.b, \1, \[sp\] +** st1b z1\.b, \1, \[sp, #1, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?64 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform1\n} } } */ +void +test_pst_uniform1 (struct pst_uniform1 x) +{ + CONSUME (x); +} + +struct pst_uniform2 +{ + fixed_int16_t a; + fixed_int16_t b[2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform2\n} } } */ +SEL2 (struct, pst_uniform2) + +/* +** test_pst_uniform2: { target aarch64_little_endian } +** sub sp, sp, #96 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?96 +** ret +*/ +/* +** test_pst_uniform2: { target aarch64_big_endian } +** sub sp, sp, #96 +** ptrue (p[0-3])\.b, vl32 +** st1h z0\.h, \1, \[sp\] +** st1h z1\.h, \1, \[sp, #1, mul vl\] +** st1h z2\.h, \1, \[sp, #2, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?96 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform2\n} } } */ +void +test_pst_uniform2 (struct pst_uniform2 x) +{ + CONSUME (x); +} + +struct pst_uniform3 +{ + fixed_int32_t a; + fixed_int32_t b[2]; + fixed_int32_t c; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform3\n} } } */ +SEL2 (struct, pst_uniform3) + +/* +** test_pst_uniform3: { target aarch64_little_endian } +** sub sp, sp, #128 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** str z3, \[sp, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?128 +** ret +*/ +/* +** test_pst_uniform3: { target aarch64_big_endian } +** sub sp, sp, #128 +** ptrue (p[0-3])\.b, vl32 +** st1w z0\.s, \1, \[sp\] +** st1w z1\.s, \1, \[sp, #1, mul vl\] +** st1w z2\.s, \1, \[sp, #2, mul vl\] +** st1w z3\.s, \1, \[sp, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?128 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform3\n} } } */ +void +test_pst_uniform3 (struct pst_uniform3 x) +{ + CONSUME (x); +} + +struct pst_uniform4 +{ + fixed_int32_t a __attribute__((aligned(SVE_BYTES * 2))); + fixed_int32_t b[3] __attribute__((aligned(SVE_BYTES * 2))); + fixed_int32_t c __attribute__((aligned(SVE_BYTES * 2))); +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform4\n} } } */ +SEL2 (struct, pst_uniform4) + +/* +** test_pst_uniform4: { target aarch64_little_endian } +** sub sp, sp, #304 +** add (x[0-9]+), sp, #?63 +** and x7, \1, #?(?:-64|4294967232) +** ptrue (p[0-7])\.b, vl32 +** st1w z0\.s, \2, \[x7\] +** add (x[0-9]+), x7, #?64 +** str z1, \[\3\] +** str z2, \[\3, #1, mul vl\] +** str z3, \[\3, #2, mul vl\] +** st1w z4\.s, \2, \[x7, #6, mul vl\] +** add sp, sp, #?304 +** ret +*/ +/* +** test_pst_uniform4: { target aarch64_big_endian } +** sub sp, sp, #304 +** add (x[0-9]+), sp, #?63 +** and x7, \1, #?(?:-64|4294967232) +** ptrue (p[0-7])\.b, vl32 +** st1w z0\.s, \2, \[x7\] +** add (x[0-9]+), x7, #?64 +** st1w z1\.s, \2, \[\3\] +** st1w z2\.s, \2, \[\3, #1, mul vl\] +** st1w z3\.s, \2, \[\3, #2, mul vl\] +** st1w z4\.s, \2, \[x7, #6, mul vl\] +** add sp, sp, #?304 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform4\n} } } */ +void +test_pst_uniform4 (struct pst_uniform4 x) +{ + CONSUME (x); +} + +struct pst_mixed1 +{ + fixed_bool_t p0; + fixed_bfloat16_t z0; + fixed_float16_t z1; + fixed_float32_t z2; + fixed_float64_t z3; + fixed_bool_t p1; + fixed_bool_t p2; + fixed_int8_t z4; + fixed_int16_t z5; + fixed_int32_t z6; + fixed_int64_t z7; + fixed_bool_t p3; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_mixed1\n} } } */ +SEL2 (struct, pst_mixed1) + +/* +** test_pst_mixed1: +** sub sp, sp, #304 +** str p0, \[sp\] +** ptrue p0\.b, vl32 +** add (x[0-9+]), sp, #?16 +** st1h z0\.h, p0, \[\1\] +** add (x[0-9+]), sp, #?48 +** st1h z1\.h, p0, \[\2\] +** add (x[0-9+]), sp, #?80 +** st1w z2\.s, p0, \[\3\] +** add (x[0-9+]), sp, #?112 +** st1d z3\.d, p0, \[\4\] +** str p1, \[sp, #36, mul vl\] +** str p2, \[sp, #37, mul vl\] +** st1b z4\.b, p0, \[sp, #5, mul vl\] +** st1h z5\.h, p0, \[sp, #6, mul vl\] +** st1w z6\.s, p0, \[sp, #7, mul vl\] +** ... +** st1d z7\.d, p0, [^\n]* +** ... +** str p3, \[sp, #72, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?304 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_mixed1\n} } } */ +void +test_pst_mixed1 (struct pst_mixed1 x) +{ + CONSUME (x); +} + +struct pst_mixed2 +{ + struct __attribute__ ((packed)) { + fixed_bool_t p; + fixed_int8_t z; + } a[3]; + fixed_int16_t b[1][1][1][4]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_mixed2\n} } } */ +SEL2 (struct, pst_mixed2) + +/* +** test_pst_mixed2: { target aarch64_little_endian } +** sub sp, sp, #240 +** str p0, \[sp\] +** ptrue (p[03])\.b, vl32 +** add (x[0-9]+), sp, #?4 +** st1b z0\.b, \1, \[\2\] +** str p1, \[sp, #9, mul vl\] +** add (x[0-9]+), sp, #?40 +** st1b z1\.b, \1, \[\3\] +** str p2, \[sp, #18, mul vl\] +** add (x[0-9]+), sp, #?76 +** st1b z2\.b, \1, \[\4\] +** add (x[0-9]+), sp, #?112 +** str z3, \[\5\] +** str z4, \[\5, #1, mul vl\] +** str z5, \[\5, #2, mul vl\] +** str z6, \[\5, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?240 +** ret +*/ +/* +** test_pst_mixed2: { target aarch64_big_endian } +** sub sp, sp, #240 +** str p0, \[sp\] +** ptrue (p[03])\.b, vl32 +** add (x[0-9]+), sp, #?4 +** st1b z0\.b, \1, \[\2\] +** str p1, \[sp, #9, mul vl\] +** add (x[0-9]+), sp, #?40 +** st1b z1\.b, \1, \[\3\] +** str p2, \[sp, #18, mul vl\] +** add (x[0-9]+), sp, #?76 +** st1b z2\.b, \1, \[\4\] +** add (x[0-9]+), sp, #?112 +** st1h z3\.h, \1, \[\5\] +** st1h z4\.h, \1, \[\5, #1, mul vl\] +** st1h z5\.h, \1, \[\5, #2, mul vl\] +** st1h z6\.h, \1, \[\5, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?240 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_mixed2\n} } } */ +void +test_pst_mixed2 (struct pst_mixed2 x) +{ + CONSUME (x); +} + +struct pst_big1 +{ + fixed_int8_t a[9]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big1\n} } } */ +SEL2 (struct, pst_big1) + +/* +** test_pst_big1_a: { target lp64 } +** ptrue (p[0-7])\.b, vl32 +** ld1b z0\.b, \1/z, \[x0\] +** ret +*/ +/* +** test_pst_big1_a: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl32 +** ld1b z0\.b, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big1_a\n} } } */ +svint8_t +test_pst_big1_a (struct pst_big1 x) +{ + return x.a[0]; +} + +/* +** test_pst_big1_b: { target lp64 } +** add x7, x0, #?256 +** ret +*/ +/* +** test_pst_big1_b: { target ilp32 } +** add w7, w0, #?256 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big1_b\n} } } */ +svint8_t +test_pst_big1_b (struct pst_big1 x) +{ + CONSUME (x.a[8]); +} + +struct pst_big2 +{ + fixed_bool_t a[5]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big2\n} } } */ +SEL2 (struct, pst_big2) + +/* +** test_pst_big2_a: { target lp64 } +** ldr p0, \[x0\] +** ret +*/ +/* +** test_pst_big2_a: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big2_a\n} } } */ +svbool_t +test_pst_big2_a (struct pst_big2 x) +{ + return x.a[0]; +} + +/* +** test_pst_big2_b: { target lp64 } +** ldr p0, \[x0, #4, mul vl\] +** ret +*/ +/* +** test_pst_big2_b: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #4, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big2_b\n} } } */ +svbool_t +test_pst_big2_b (struct pst_big2 x) +{ + return x.a[4]; +} + +struct pst_big3 +{ + fixed_bool_t p0; + fixed_int8_t a[2]; + fixed_bool_t p1; + fixed_bool_t p2; + fixed_bool_t p3; + fixed_int8_t b[6]; + fixed_bool_t p4; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big3\n} } } */ +SEL2 (struct, pst_big3) + +/* +** test_pst_big3_a: { target lp64 } +** ldr p0, \[x0\] +** ret +*/ +/* +** test_pst_big3_a: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_a\n} } } */ +svbool_t +test_pst_big3_a (struct pst_big3 x) +{ + return x.p0; +} + +/* +** test_pst_big3_b: { target lp64 } +** ldr p0, \[x0, #20, mul vl\] +** ret +*/ +/* +** test_pst_big3_b: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #20, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_b\n} } } */ +svbool_t +test_pst_big3_b (struct pst_big3 x) +{ + return x.p1; +} + +/* +** test_pst_big3_c: { target lp64 } +** ldr p0, \[x0, #21, mul vl\] +** ret +*/ +/* +** test_pst_big3_c: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #21, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_c\n} } } */ +svbool_t +test_pst_big3_c (struct pst_big3 x) +{ + return x.p2; +} + +/* +** test_pst_big3_d: { target lp64 } +** ldr p0, \[x0, #72, mul vl\] +** ret +*/ +/* +** test_pst_big3_d: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #72, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_d\n} } } */ +svbool_t +test_pst_big3_d (struct pst_big3 x) +{ + return x.p4; +} + +/* +** test_pst_big3_e: { target lp64 } +** add (x[0-9]+), x0, #?16 +** ptrue (p[0-7])\.b, vl32 +** ld1b z0\.b, \2/z, \[\1\] +** ret +*/ +/* +** test_pst_big3_e: { target ilp32 } +** uxtw x0, w0 +** add (x[0-9]+), x0, #?16 +** ptrue (p[0-7])\.b, vl32 +** ld1b z0\.b, \2/z, \[\1\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_e\n} } } */ +svint8_t +test_pst_big3_e (struct pst_big3 x) +{ + return x.a[0]; +} + +/* +** test_pst_big3_f: { target lp64 } +** ptrue (p[0-7])\.b, vl32 +** ld1b z0\.b, \1/z, \[x0, #4, mul vl\] +** ret +*/ +/* +** test_pst_big3_f: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl32 +** ld1b z0\.b, \1/z, \[x0, #4, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_f\n} } } */ +svint8_t +test_pst_big3_f (struct pst_big3 x) +{ + return x.b[1]; +} + +struct pst_zero1 +{ + fixed_bool_t a[0]; + fixed_int32_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero1\n} } } */ +SEL2 (struct, pst_zero1) + +/* +** test_pst_zero1: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero1\n} } } */ +svint32_t +test_pst_zero1 (struct pst_zero1 x) +{ + return x.b; +} + +struct pst_zero2 +{ + unsigned int : 0; + fixed_bool_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero2\n} } } */ +SEL2 (struct, pst_zero2) + +/* +** test_pst_zero2: +** ( +** sub sp, sp, #16 +** add sp, sp, #?16 +** | +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero2\n} } } */ +svbool_t +test_pst_zero2 (struct pst_zero2 x) +{ + return x.b; +} + +struct pst_zero3 +{ + struct {} empty; + fixed_uint64_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero3\n} } } */ +SEL2 (struct, pst_zero3) + +/* +** test_pst_zero3: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero3\n} } } */ +svuint64_t +test_pst_zero3 (struct pst_zero3 x) +{ + return x.b; +} + +typedef unsigned char small_vec __attribute__((vector_size(SVE_BYTES / 4))); + +struct nonpst1 +{ + small_vec a[4]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst1\n} } } */ +SEL2 (struct, nonpst1) + +/* +** test_nonpst1: +** mov v0\.8b, v3\.8b +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\ttest_nonpst1\n} } } */ +small_vec +test_nonpst1 (struct nonpst1 x) +{ + return x.a[3]; +} + +union nonpst2 +{ + struct { + fixed_bool_t a[0]; + fixed_int32_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst2\n} } } */ +SEL2 (union, nonpst2) + +/* +** test_nonpst2: { target lp64 } +** ptrue (p[0-7])\.b, vl32 +** ld1w z0\.s, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst2: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl32 +** ld1w z0\.s, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst2\n} } } */ +svint32_t +test_nonpst2 (union nonpst2 x) +{ + return x.b; +} + +/* +** ret_nonpst2: +** ptrue (p[0-7])\.b, vl32 +** index (z[0-9]+\.s), #1, #2 +** st1w \2, \1, \[x8\] +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst2\n} } } */ +union nonpst2 +ret_nonpst2 (void) +{ + return (union nonpst2) { { {}, 1, 3, 5, 7, 9, 11, 13, 15 } }; +} + +union nonpst3 +{ + struct { + unsigned int : 0; + fixed_bool_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst3\n} } } */ +SEL2 (union, nonpst3) + +/* +** test_nonpst3: { target aarch64_little_endian } +** sub sp, sp, #16 +** str w0, \[sp, #?12\] +** ldr p0, \[sp, #3, mul vl\] +** add sp, sp, #?16 +** ret +*/ +/* +** test_nonpst3: { target aarch64_big_endian } +** sub sp, sp, #16 +** ( +** lsr (x[0-9]+), x0, #?32 +** str \1, \[sp\] +** ldr p0, \[sp, #1, mul vl\] +** | +** str x0, \[sp\] +** ldr p0, \[sp\] +** ) +** add sp, sp, #?16 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst3\n} } } */ +svbool_t +test_nonpst3 (union nonpst3 x) +{ + return x.b; +} + +/* +** ret_nonpst3: { target aarch64_little_endian } +** mov w0, -1 +** ret +*/ +/* +** ret_nonpst3: { target aarch64_big_endian } +** mov x0, -4294967296 +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst3\n} } } */ +union nonpst3 +ret_nonpst3 (void) +{ + return (union nonpst3) { { svptrue_b8 () } }; +} + +union nonpst4 +{ + struct { + struct {} empty; + fixed_uint64_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst4\n} } } */ +SEL2 (union, nonpst4) + +/* +** test_nonpst4: { target lp64 } +** ptrue (p[0-7])\.b, vl32 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst4: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl32 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst4\n} } } */ +svuint64_t +test_nonpst4 (union nonpst4 x) +{ + return x.b; +} + +/* +** ret_nonpst4: +** ptrue (p[0-7])\.b, vl32 +** index (z[0-9]+\.d), #1, #1 +** st1d \2, \1, \[x8\] +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst4\n} } } */ +union nonpst4 +ret_nonpst4 (void) +{ + return (union nonpst4) { { {}, 1, 2, 3, 4 } }; +} + +struct nonpst5 +{ + union { + fixed_uint16_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst5\n} } } */ +SEL2 (struct, nonpst5) + +/* +** test_nonpst5: { target lp64 } +** ptrue (p[0-7])\.b, vl32 +** ld1h z0\.h, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst5: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl32 +** ld1h z0\.h, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst5\n} } } */ +svuint16_t +test_nonpst5 (struct nonpst5 x) +{ + return x.b; +} + +struct nonpst6 +{ + fixed_uint64_t b; + fixed_uint64_t *ptr; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst6\n} } } */ +SEL2 (struct, nonpst6) + +/* +** test_nonpst6: { target lp64 } +** ptrue (p[0-3])\.b, vl32 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst6: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-3])\.b, vl32 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst6\n} } } */ +svuint64_t +test_nonpst6 (struct nonpst6 x) +{ + return x.b; +} + +struct nonpst7 +{ + fixed_uint64_t b; + uint32_t foo __attribute__((vector_size(SVE_BYTES))); +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst7\n} } } */ +SEL2 (struct, nonpst7) + +/* +** test_nonpst7: { target lp64 } +** ptrue (p[0-3])\.b, vl32 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst7: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-3])\.b, vl32 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst7\n} } } */ +svuint64_t +test_nonpst7 (struct nonpst7 x) +{ + return x.b; +} + +typedef unsigned char tiny_vec __attribute__((vector_size(SVE_BYTES / 8))); + +struct nonpst8 +{ + tiny_vec a; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst8\n} } } */ +SEL2 (struct, nonpst8) + +/* +** test_nonpst8: { target aarch64_little_endian } +** ubfx x0, x0, 8, 8 +** ret +*/ +/* +** test_nonpst8: { target aarch64_big_endian } +** ( +** sub sp, sp, #16 +** ubfx x0, x0, 48, 8 +** add sp, sp, #?16 +** | +** ubfx x0, x0, 48, 8 +** ) +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\ttest_nonpst8\n} } } */ +unsigned int +test_nonpst8 (struct nonpst8 x) +{ + return x.a[1]; +} + +/* +** ret_nonpst8: { target aarch64_little_endian } +** ( +** sub sp, sp, #16 +** mov w0, #?513 +** movk w0, #?0x403, lsl #?16 +** add sp, sp, #?16 +** | +** mov w0, #?513 +** movk w0, #?0x403, lsl #?16 +** ) +** ret +*/ +/* +** ret_nonpst8: { target aarch64_big_endian } +** mov x0, #?3315714752512 +** movk x0, #?0x102, lsl #?48 +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst8\n} } } */ +struct nonpst8 +ret_nonpst8 (void) +{ + return (struct nonpst8) { { 1, 2, 3, 4 } }; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_512.c b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_512.c new file mode 100644 index 00000000000..e03fd73f80c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/struct_3_512.c @@ -0,0 +1,1197 @@ +/* { dg-options "-O -msve-vector-bits=512" } */ +/* { dg-final { check-function-bodies "**" "" } } */ + +#include "struct.h" + +#define CONSUME(VAR) \ + { \ + register void *ptr_ asm ("x7") = &(VAR); \ + asm volatile ("" :: "r" (ptr_) : "memory"); \ + } + +#define SEL2(TAG, TYPE) \ + TAG TYPE \ + sel2_##TYPE (TAG TYPE x, TAG TYPE y) \ + { \ + return y; \ + } + +#define WRAP(TYPE) \ + struct wrap_##TYPE \ + { \ + TYPE data; \ + }; \ + SEL2 (struct, wrap_##TYPE) + +/* +** sel2_wrap_fixed_int8_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int8_t\n} } } */ +WRAP (fixed_int8_t); + +/* +** sel2_wrap_fixed_int16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int16_t\n} } } */ +WRAP (fixed_int16_t); + +/* +** sel2_wrap_fixed_int32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int32_t\n} } } */ +WRAP (fixed_int32_t); + +/* +** sel2_wrap_fixed_int64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_int64_t\n} } } */ +WRAP (fixed_int64_t); + +/* +** sel2_wrap_fixed_uint8_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint8_t\n} } } */ +WRAP (fixed_uint8_t); + +/* +** sel2_wrap_fixed_uint16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint16_t\n} } } */ +WRAP (fixed_uint16_t); + +/* +** sel2_wrap_fixed_uint32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint32_t\n} } } */ +WRAP (fixed_uint32_t); + +/* +** sel2_wrap_fixed_uint64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_uint64_t\n} } } */ +WRAP (fixed_uint64_t); + +/* +** sel2_wrap_fixed_bfloat16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_bfloat16_t\n} } } */ +WRAP (fixed_bfloat16_t); + +/* +** sel2_wrap_fixed_float16_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float16_t\n} } } */ +WRAP (fixed_float16_t); + +/* +** sel2_wrap_fixed_float32_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float32_t\n} } } */ +WRAP (fixed_float32_t); + +/* +** sel2_wrap_fixed_float64_t: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_float64_t\n} } } */ +WRAP (fixed_float64_t); + +/* +** sel2_wrap_fixed_bool_t: +** mov p0\.b, p1\.b +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_wrap_fixed_bool_t\n} } } */ +WRAP (fixed_bool_t); + +struct pst_arr1 +{ + fixed_uint8_t u8[1]; +}; + +/* +** sel2_pst_arr1: +** mov z0\.d, z1\.d +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr1\n} } } */ +SEL2 (struct, pst_arr1) + +/* +** test_pst_arr1: +** eor z0\.b, z0\.b, #(?:0x)?1 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr1\n} } } */ +svuint8_t +test_pst_arr1 (struct pst_arr1 x) +{ + return sveor_x (svptrue_b8 (), x.u8[0], 1); +} + +struct pst_arr2 +{ + fixed_uint8_t u8[2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr2\n} } } */ +SEL2 (struct, pst_arr2) + +/* +** test_pst_arr2: +** sub z0\.b, z0\.b, z1\.b +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr2\n} } } */ +svuint8_t +test_pst_arr2 (struct pst_arr2 x) +{ + return svsub_x (svptrue_b8 (), x.u8[0], x.u8[1]); +} + +struct pst_arr3 +{ + fixed_uint16_t u16[3]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr3\n} } } */ +SEL2 (struct, pst_arr3) + +/* +** test_pst_arr3: +** sub z0\.h, z0\.h, z2\.h +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr3\n} } } */ +svuint16_t +test_pst_arr3 (struct pst_arr3 x) +{ + return svsub_x (svptrue_b8 (), x.u16[0], x.u16[2]); +} + +struct pst_arr4 +{ + fixed_uint32_t u32[4]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr4\n} } } */ +SEL2 (struct, pst_arr4) + +/* +** test_pst_arr4: +** sub z0\.s, z0\.s, z3\.s +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr4\n} } } */ +svuint32_t +test_pst_arr4 (struct pst_arr4 x) +{ + return svsub_x (svptrue_b8 (), x.u32[0], x.u32[3]); +} + +struct pst_arr5 +{ + fixed_uint64_t u64[2][2][2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr5\n} } } */ +SEL2 (struct, pst_arr5) + +/* +** test_pst_arr5: { target aarch64_little_endian } +** sub sp, sp, #512 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** str z3, \[sp, #3, mul vl\] +** str z4, \[sp, #4, mul vl\] +** str z5, \[sp, #5, mul vl\] +** str z6, \[sp, #6, mul vl\] +** str z7, \[sp, #7, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?512 +** ret +*/ +/* +** test_pst_arr5: { target aarch64_big_endian } +** sub sp, sp, #512 +** ptrue (p[0-3])\.b, vl64 +** st1d z0\.d, \1, \[sp\] +** st1d z1\.d, \1, \[sp, #1, mul vl\] +** st1d z2\.d, \1, \[sp, #2, mul vl\] +** st1d z3\.d, \1, \[sp, #3, mul vl\] +** st1d z4\.d, \1, \[sp, #4, mul vl\] +** st1d z5\.d, \1, \[sp, #5, mul vl\] +** st1d z6\.d, \1, \[sp, #6, mul vl\] +** st1d z7\.d, \1, \[sp, #7, mul vl\] +** mov ((x7, sp|w7, wsp)|w7, wsp) +** add sp, sp, #?512 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5\n} } } */ +void +test_pst_arr5 (struct pst_arr5 x) +{ + CONSUME (x); +} + +/* +** test_pst_arr5_x0: +** ( +** mov z0\.d, z7\.d +** mov (x7, x0|w7, w0) +** | +** mov (x7, x0|w7, w0) +** mov z0\.d, z7\.d +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_x0\n} } } */ +svint32_t +test_pst_arr5_x0 (svint32_t z0, struct pst_arr5 x, + svint32_t z1, svint32_t z2, svint32_t z3, svint32_t z4, + svint32_t z5, svint32_t z6, svint32_t z7) +{ + CONSUME (x); + return z7; +} + +/* +** test_pst_arr5_x7: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_x7\n} } } */ +svint32_t +test_pst_arr5_x7 (svint32_t z0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, struct pst_arr5 x) +{ + CONSUME (x); + return z0; +} + +/* +** test_pst_arr5_sp: { target lp64 } +** ldr x7, \[sp\] +** ret +*/ +/* +** test_pst_arr5_sp: { target ilp32 } +** ldr w7, \[sp(, 4)?\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr5_sp\n} } } */ +svint32_t +test_pst_arr5_sp (svint32_t z0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, int x7, struct pst_arr5 x) +{ + CONSUME (x); + return z0; +} + +struct pst_arr6 +{ + fixed_bool_t b[2][2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_arr6\n} } } */ +SEL2 (struct, pst_arr6) + +/* +** test_pst_arr6: +** ... +** brkpa p0\.b, p0/z, p2\.b, p3\.b +** ... +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6\n} } } */ +fixed_bool_t +test_pst_arr6 (struct pst_arr6 x) +{ + return svbrkpa_z (x.b[0][0], x.b[1][0], x.b[1][1]); +} + +/* +** test_pst_arr6_x0: +** ( +** mov p0\.b, p3\.b +** mov (x7, x0|w7, w0) +** | +** mov (x7, x0|w7, w0) +** mov p0\.b, p3\.b +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_x0\n} } } */ +fixed_bool_t +test_pst_arr6_x0 (svbool_t p0, struct pst_arr6 x, svbool_t p1, svbool_t p2, + svbool_t p3) +{ + CONSUME (x); + return p3; +} + +/* +** test_pst_arr6_x7: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_x7\n} } } */ +fixed_bool_t +test_pst_arr6_x7 (svbool_t p0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, struct pst_arr6 x) +{ + CONSUME (x); + return p0; +} + +/* +** test_pst_arr6_sp: { target lp64 } +** ldr x7, \[sp\] +** ret +*/ +/* +** test_pst_arr6_sp: { target ilp32 } +** ldr w7, \[sp(, 4)?\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_arr6_sp\n} } } */ +fixed_bool_t +test_pst_arr6_sp (svbool_t p0, int x0, int x1, int x2, int x3, int x4, + int x5, int x6, int x7, struct pst_arr6 x) +{ + CONSUME (x); + return p0; +} + +struct pst_uniform1 +{ + fixed_int8_t a, b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform1\n} } } */ +SEL2 (struct, pst_uniform1) + +/* +** test_pst_uniform1: { target aarch64_little_endian } +** sub sp, sp, #128 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?128 +** ret +*/ +/* +** test_pst_uniform1: { target aarch64_big_endian } +** sub sp, sp, #128 +** ptrue (p[0-3])\.b, vl64 +** st1b z0\.b, \1, \[sp\] +** st1b z1\.b, \1, \[sp, #1, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?128 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform1\n} } } */ +void +test_pst_uniform1 (struct pst_uniform1 x) +{ + CONSUME (x); +} + +struct pst_uniform2 +{ + fixed_int16_t a; + fixed_int16_t b[2]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform2\n} } } */ +SEL2 (struct, pst_uniform2) + +/* +** test_pst_uniform2: { target aarch64_little_endian } +** sub sp, sp, #192 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?192 +** ret +*/ +/* +** test_pst_uniform2: { target aarch64_big_endian } +** sub sp, sp, #192 +** ptrue (p[0-3])\.b, vl64 +** st1h z0\.h, \1, \[sp\] +** st1h z1\.h, \1, \[sp, #1, mul vl\] +** st1h z2\.h, \1, \[sp, #2, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?192 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform2\n} } } */ +void +test_pst_uniform2 (struct pst_uniform2 x) +{ + CONSUME (x); +} + +struct pst_uniform3 +{ + fixed_int32_t a; + fixed_int32_t b[2]; + fixed_int32_t c; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform3\n} } } */ +SEL2 (struct, pst_uniform3) + +/* +** test_pst_uniform3: { target aarch64_little_endian } +** sub sp, sp, #256 +** str z0, \[sp\] +** str z1, \[sp, #1, mul vl\] +** str z2, \[sp, #2, mul vl\] +** str z3, \[sp, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?256 +** ret +*/ +/* +** test_pst_uniform3: { target aarch64_big_endian } +** sub sp, sp, #256 +** ptrue (p[0-3])\.b, vl64 +** st1w z0\.s, \1, \[sp\] +** st1w z1\.s, \1, \[sp, #1, mul vl\] +** st1w z2\.s, \1, \[sp, #2, mul vl\] +** st1w z3\.s, \1, \[sp, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?256 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform3\n} } } */ +void +test_pst_uniform3 (struct pst_uniform3 x) +{ + CONSUME (x); +} + +struct pst_uniform4 +{ + fixed_int32_t a __attribute__((aligned(SVE_BYTES * 2))); + fixed_int32_t b[3] __attribute__((aligned(SVE_BYTES * 2))); + fixed_int32_t c __attribute__((aligned(SVE_BYTES * 2))); +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_uniform4\n} } } */ +SEL2 (struct, pst_uniform4) + +/* +** test_pst_uniform4: { target aarch64_little_endian } +** sub sp, sp, #624 +** add (x[0-9]+), sp, #?127 +** and x7, \1, #?(?:-128|4294967168) +** ptrue (p[0-7])\.b, vl64 +** st1w z0\.s, \2, \[x7\] +** add (x[0-9]+), x7, #?128 +** str z1, \[\3\] +** str z2, \[\3, #1, mul vl\] +** str z3, \[\3, #2, mul vl\] +** st1w z4\.s, \2, \[x7, #6, mul vl\] +** add sp, sp, #?624 +** ret +*/ +/* +** test_pst_uniform4: { target aarch64_big_endian } +** sub sp, sp, #624 +** add (x[0-9]+), sp, #?127 +** and x7, \1, #?(?:-128|4294967168) +** ptrue (p[0-7])\.b, vl64 +** st1w z0\.s, \2, \[x7\] +** add (x[0-9]+), x7, #?128 +** st1w z1\.s, \2, \[\3\] +** st1w z2\.s, \2, \[\3, #1, mul vl\] +** st1w z3\.s, \2, \[\3, #2, mul vl\] +** st1w z4\.s, \2, \[x7, #6, mul vl\] +** add sp, sp, #?624 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_uniform4\n} } } */ +void +test_pst_uniform4 (struct pst_uniform4 x) +{ + CONSUME (x); +} + +struct pst_mixed1 +{ + fixed_bool_t p0; + fixed_bfloat16_t z0; + fixed_float16_t z1; + fixed_float32_t z2; + fixed_float64_t z3; + fixed_bool_t p1; + fixed_bool_t p2; + fixed_int8_t z4; + fixed_int16_t z5; + fixed_int32_t z6; + fixed_int64_t z7; + fixed_bool_t p3; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_mixed1\n} } } */ +SEL2 (struct, pst_mixed1) + +/* +** test_pst_mixed1: +** sub sp, sp, #560 +** str p0, \[sp\] +** ptrue p0\.b, vl64 +** add (x[0-9+]), sp, #?16 +** st1h z0\.h, p0, \[\1\] +** add (x[0-9+]), sp, #?80 +** st1h z1\.h, p0, \[\2\] +** add (x[0-9+]), sp, #?144 +** st1w z2\.s, p0, \[\3\] +** add (x[0-9+]), sp, #?208 +** st1d z3\.d, p0, \[\4\] +** str p1, \[sp, #34, mul vl\] +** str p2, \[sp, #35, mul vl\] +** add (x[0-9+]), sp, #?288 +** st1b z4\.b, p0, \[\5\] +** add (x[0-9+]), sp, #?352 +** st1h z5\.h, p0, \[\6\] +** add (x[0-9+]), sp, #?416 +** st1w z6\.s, p0, \[\7\] +** add (x[0-9+]), sp, #?480 +** st1d z7\.d, p0, \[\8\] +** str p3, \[sp, #68, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?560 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_mixed1\n} } } */ +void +test_pst_mixed1 (struct pst_mixed1 x) +{ + CONSUME (x); +} + +struct pst_mixed2 +{ + struct __attribute__ ((packed)) { + fixed_bool_t p; + fixed_int8_t z; + } a[3]; + fixed_int16_t b[1][1][1][4]; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_mixed2\n} } } */ +SEL2 (struct, pst_mixed2) + +/* +** test_pst_mixed2: { target aarch64_little_endian } +** sub sp, sp, #480 +** str p0, \[sp\] +** ptrue (p[03])\.b, vl64 +** add (x[0-9]+), sp, #?8 +** st1b z0\.b, \1, \[\2\] +** str p1, \[sp, #9, mul vl\] +** add (x[0-9]+), sp, #?80 +** st1b z1\.b, \1, \[\3\] +** str p2, \[sp, #18, mul vl\] +** add (x[0-9]+), sp, #?152 +** st1b z2\.b, \1, \[\4\] +** add (x[0-9]+), sp, #?224 +** str z3, \[\5\] +** str z4, \[\5, #1, mul vl\] +** str z5, \[\5, #2, mul vl\] +** str z6, \[\5, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?480 +** ret +*/ +/* +** test_pst_mixed2: { target aarch64_big_endian } +** sub sp, sp, #480 +** str p0, \[sp\] +** ptrue (p[03])\.b, vl64 +** add (x[0-9]+), sp, #?8 +** st1b z0\.b, \1, \[\2\] +** str p1, \[sp, #9, mul vl\] +** add (x[0-9]+), sp, #?80 +** st1b z1\.b, \1, \[\3\] +** str p2, \[sp, #18, mul vl\] +** add (x[0-9]+), sp, #?152 +** st1b z2\.b, \1, \[\4\] +** add (x[0-9]+), sp, #?224 +** st1h z3\.h, \1, \[\5\] +** st1h z4\.h, \1, \[\5, #1, mul vl\] +** st1h z5\.h, \1, \[\5, #2, mul vl\] +** st1h z6\.h, \1, \[\5, #3, mul vl\] +** mov (x7, sp|w7, wsp) +** add sp, sp, #?480 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_mixed2\n} } } */ +void +test_pst_mixed2 (struct pst_mixed2 x) +{ + CONSUME (x); +} + +struct pst_big1 +{ + fixed_int8_t a[9]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big1\n} } } */ +SEL2 (struct, pst_big1) + +/* +** test_pst_big1_a: { target lp64 } +** ptrue (p[0-7])\.b, vl64 +** ld1b z0\.b, \1/z, \[x0\] +** ret +*/ +/* +** test_pst_big1_a: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl64 +** ld1b z0\.b, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big1_a\n} } } */ +svint8_t +test_pst_big1_a (struct pst_big1 x) +{ + return x.a[0]; +} + +/* +** test_pst_big1_b: { target lp64 } +** add x7, x0, #?512 +** ret +*/ +/* +** test_pst_big1_b: { target ilp32 } +** add w7, w0, #?512 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big1_b\n} } } */ +svint8_t +test_pst_big1_b (struct pst_big1 x) +{ + CONSUME (x.a[8]); +} + +struct pst_big2 +{ + fixed_bool_t a[5]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big2\n} } } */ +SEL2 (struct, pst_big2) + +/* +** test_pst_big2_a: { target lp64 } +** ldr p0, \[x0\] +** ret +*/ +/* +** test_pst_big2_a: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big2_a\n} } } */ +svbool_t +test_pst_big2_a (struct pst_big2 x) +{ + return x.a[0]; +} + +/* +** test_pst_big2_b: { target lp64 } +** ldr p0, \[x0, #4, mul vl\] +** ret +*/ +/* +** test_pst_big2_b: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #4, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big2_b\n} } } */ +svbool_t +test_pst_big2_b (struct pst_big2 x) +{ + return x.a[4]; +} + +struct pst_big3 +{ + fixed_bool_t p0; + fixed_int8_t a[2]; + fixed_bool_t p1; + fixed_bool_t p2; + fixed_bool_t p3; + fixed_int8_t b[6]; + fixed_bool_t p4; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_big3\n} } } */ +SEL2 (struct, pst_big3) + +/* +** test_pst_big3_a: { target lp64 } +** ldr p0, \[x0\] +** ret +*/ +/* +** test_pst_big3_a: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_a\n} } } */ +svbool_t +test_pst_big3_a (struct pst_big3 x) +{ + return x.p0; +} + +/* +** test_pst_big3_b: { target lp64 } +** ldr p0, \[x0, #18, mul vl\] +** ret +*/ +/* +** test_pst_big3_b: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #18, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_b\n} } } */ +svbool_t +test_pst_big3_b (struct pst_big3 x) +{ + return x.p1; +} + +/* +** test_pst_big3_c: { target lp64 } +** ldr p0, \[x0, #19, mul vl\] +** ret +*/ +/* +** test_pst_big3_c: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #19, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_c\n} } } */ +svbool_t +test_pst_big3_c (struct pst_big3 x) +{ + return x.p2; +} + +/* +** test_pst_big3_d: { target lp64 } +** ldr p0, \[x0, #70, mul vl\] +** ret +*/ +/* +** test_pst_big3_d: { target ilp32 } +** uxtw x0, w0 +** ldr p0, \[x0, #70, mul vl\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_d\n} } } */ +svbool_t +test_pst_big3_d (struct pst_big3 x) +{ + return x.p4; +} + +/* +** test_pst_big3_e: { target lp64 } +** add (x[0-9]+), x0, #?16 +** ptrue (p[0-7])\.b, vl64 +** ld1b z0\.b, \2/z, \[\1\] +** ret +*/ +/* +** test_pst_big3_e: { target ilp32 } +** uxtw x0, w0 +** add (x[0-9]+), x0, #?16 +** ptrue (p[0-7])\.b, vl64 +** ld1b z0\.b, \2/z, \[\1\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_e\n} } } */ +svint8_t +test_pst_big3_e (struct pst_big3 x) +{ + return x.a[0]; +} + +/* +** test_pst_big3_f: { target lp64 } +** add (x[0-9]+), x0, #?240 +** ptrue (p[0-7])\.b, vl64 +** ld1b z0\.b, \2/z, \[\1\] +** ret +*/ +/* +** test_pst_big3_f: { target ilp32 } +** uxtw x0, w0 +** add (x[0-9]+), x0, #?240 +** ptrue (p[0-7])\.b, vl64 +** ld1b z0\.b, \2/z, \[\1\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_big3_f\n} } } */ +svint8_t +test_pst_big3_f (struct pst_big3 x) +{ + return x.b[1]; +} + +struct pst_zero1 +{ + fixed_bool_t a[0]; + fixed_int32_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero1\n} } } */ +SEL2 (struct, pst_zero1) + +/* +** test_pst_zero1: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero1\n} } } */ +svint32_t +test_pst_zero1 (struct pst_zero1 x) +{ + return x.b; +} + +struct pst_zero2 +{ + unsigned int : 0; + fixed_bool_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero2\n} } } */ +SEL2 (struct, pst_zero2) + +/* +** test_pst_zero2: +** ( +** sub sp, sp, #16 +** add sp, sp, #?16 +** | +** ) +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero2\n} } } */ +svbool_t +test_pst_zero2 (struct pst_zero2 x) +{ + return x.b; +} + +struct pst_zero3 +{ + struct {} empty; + fixed_uint64_t b; +}; +/* { dg-final { scan-assembler {\t\.variant_pcs\tsel2_pst_zero3\n} } } */ +SEL2 (struct, pst_zero3) + +/* +** test_pst_zero3: +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_pst_zero3\n} } } */ +svuint64_t +test_pst_zero3 (struct pst_zero3 x) +{ + return x.b; +} + +typedef unsigned char small_vec __attribute__((vector_size(SVE_BYTES / 4))); + +struct nonpst1 +{ + small_vec a[4]; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst1\n} } } */ +SEL2 (struct, nonpst1) + +/* +** test_nonpst1: +** mov v0\.16b, v3\.16b +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\ttest_nonpst1\n} } } */ +small_vec +test_nonpst1 (struct nonpst1 x) +{ + return x.a[3]; +} + +union nonpst2 +{ + struct { + fixed_bool_t a[0]; + fixed_int32_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst2\n} } } */ +SEL2 (union, nonpst2) + +/* +** test_nonpst2: { target lp64 } +** ptrue (p[0-7])\.b, vl64 +** ld1w z0\.s, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst2: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl64 +** ld1w z0\.s, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst2\n} } } */ +svint32_t +test_nonpst2 (union nonpst2 x) +{ + return x.b; +} + +/* +** ret_nonpst2: +** ptrue (p[0-7])\.b, vl64 +** index (z[0-9]+\.s), #1, #2 +** st1w \2, \1, \[x8\] +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst2\n} } } */ +union nonpst2 +ret_nonpst2 (void) +{ + return (union nonpst2) { { {}, 1, 3, 5, 7, 9, 11, 13, 15, + 17, 19, 21, 23, 25, 27, 29, 31 } }; +} + +union nonpst3 +{ + struct { + unsigned int : 0; + fixed_bool_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst3\n} } } */ +SEL2 (union, nonpst3) + +/* +** test_nonpst3: +** sub sp, sp, #16 +** str x0, \[sp, #?8\] +** ldr p0, \[sp, #1, mul vl\] +** add sp, sp, #?16 +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst3\n} } } */ +svbool_t +test_nonpst3 (union nonpst3 x) +{ + return x.b; +} + +/* +** ret_nonpst3: +** mov x0, -1 +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst3\n} } } */ +union nonpst3 +ret_nonpst3 (void) +{ + return (union nonpst3) { { svptrue_b8 () } }; +} + +union nonpst4 +{ + struct { + struct {} empty; + fixed_uint64_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst4\n} } } */ +SEL2 (union, nonpst4) + +/* +** test_nonpst4: { target lp64 } +** ptrue (p[0-7])\.b, vl64 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst4: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl64 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst4\n} } } */ +svuint64_t +test_nonpst4 (union nonpst4 x) +{ + return x.b; +} + +/* +** ret_nonpst4: +** ptrue (p[0-7])\.b, vl64 +** index (z[0-9]+\.d), #1, #1 +** st1d \2, \1, \[x8\] +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst4\n} } } */ +union nonpst4 +ret_nonpst4 (void) +{ + return (union nonpst4) { { {}, 1, 2, 3, 4, 5, 6, 7, 8 } }; +} + +struct nonpst5 +{ + union { + fixed_uint16_t b; + }; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst5\n} } } */ +SEL2 (struct, nonpst5) + +/* +** test_nonpst5: { target lp64 } +** ptrue (p[0-7])\.b, vl64 +** ld1h z0\.h, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst5: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-7])\.b, vl64 +** ld1h z0\.h, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst5\n} } } */ +svuint16_t +test_nonpst5 (struct nonpst5 x) +{ + return x.b; +} + +struct nonpst6 +{ + fixed_uint64_t b; + fixed_uint64_t *ptr; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst6\n} } } */ +SEL2 (struct, nonpst6) + +/* +** test_nonpst6: { target lp64 } +** ptrue (p[0-3])\.b, vl64 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst6: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-3])\.b, vl64 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst6\n} } } */ +svuint64_t +test_nonpst6 (struct nonpst6 x) +{ + return x.b; +} + +struct nonpst7 +{ + fixed_uint64_t b; + uint32_t foo __attribute__((vector_size(SVE_BYTES))); +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst7\n} } } */ +SEL2 (struct, nonpst7) + +/* +** test_nonpst7: { target lp64 } +** ptrue (p[0-3])\.b, vl64 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* +** test_nonpst7: { target ilp32 } +** uxtw x0, w0 +** ptrue (p[0-3])\.b, vl64 +** ld1d z0\.d, \1/z, \[x0\] +** ret +*/ +/* { dg-final { scan-assembler {\t\.variant_pcs\ttest_nonpst7\n} } } */ +svuint64_t +test_nonpst7 (struct nonpst7 x) +{ + return x.b; +} + +typedef unsigned char tiny_vec __attribute__((vector_size(SVE_BYTES / 8))); + +struct nonpst8 +{ + tiny_vec a; +}; +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tsel2_pst_nonpst8\n} } } */ +SEL2 (struct, nonpst8) + +/* +** test_nonpst8: { target aarch64_little_endian } +** umov w0, v0\.b\[1\] +** ret +*/ +/* +** test_nonpst8: { target aarch64_big_endian } +** umov w0, v0\.b\[6\] +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\ttest_nonpst8\n} } } */ +unsigned int +test_nonpst8 (struct nonpst8 x) +{ + return x.a[1]; +} + +/* +** ret_nonpst8: +** movi v0\.8b, 0x1 +** ret +*/ +/* { dg-final { scan-assembler-not {\t\.variant_pcs\tret_nonpst8\n} } } */ +struct nonpst8 +ret_nonpst8 (void) +{ + return (struct nonpst8) { { 1, 1, 1, 1, 1, 1, 1, 1 } }; +} diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index e42d0ea489c..3758bb3a91d 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -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 { } {