+2020-04-09 Richard Sandiford <richard.sandiford@arm.com>
+
+ * doc/sourcebuild.texi (aarch64_sve_hw, aarch64_sve128_hw)
+ (aarch64_sve256_hw, aarch64_sve512_hw, aarch64_sve1024_hw)
+ (aarch64_sve2048_hw): Document.
+ * config/aarch64/aarch64-protos.h
+ (aarch64_sve::handle_arm_sve_vector_bits_attribute): Declare.
+ * config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins): Define
+ __ARM_FEATURE_SVE_VECTOR_OPERATIONS when SVE is enabled.
+ * config/aarch64/aarch64-sve-builtins.cc (matches_type_p): New
+ function.
+ (find_type_suffix_for_scalar_type): Use it instead of comparing
+ TYPE_MAIN_VARIANTs.
+ (function_resolver::infer_vector_or_tuple_type): Likewise.
+ (function_resolver::require_vector_type): Likewise.
+ (handle_arm_sve_vector_bits_attribute): New function.
+ * config/aarch64/aarch64.c (pure_scalable_type_info): New class.
+ (aarch64_attribute_table): Add arm_sve_vector_bits.
+ (aarch64_return_in_memory_1):
+ (pure_scalable_type_info::piece::get_rtx): New function.
+ (pure_scalable_type_info::num_zr): Likewise.
+ (pure_scalable_type_info::num_pr): Likewise.
+ (pure_scalable_type_info::get_rtx): Likewise.
+ (pure_scalable_type_info::analyze): Likewise.
+ (pure_scalable_type_info::analyze_registers): Likewise.
+ (pure_scalable_type_info::analyze_array): Likewise.
+ (pure_scalable_type_info::analyze_record): Likewise.
+ (pure_scalable_type_info::add_piece): Likewise.
+ (aarch64_some_values_include_pst_objects_p): Likewise.
+ (aarch64_returns_value_in_sve_regs_p): Use pure_scalable_type_info
+ to analyze whether the type is returned in SVE registers.
+ (aarch64_takes_arguments_in_sve_regs_p): Likwise whether the type
+ is passed in SVE registers.
+ (aarch64_pass_by_reference_1): New function, extracted from...
+ (aarch64_pass_by_reference): ...here. Use pure_scalable_type_info
+ to analyze whether the type is a pure scalable type and, if so,
+ whether it should be passed by reference.
+ (aarch64_return_in_msb): Return false for pure scalable types.
+ (aarch64_function_value_1): Fold back into...
+ (aarch64_function_value): ...this function. Use
+ pure_scalable_type_info to analyze whether the type is a pure
+ scalable type and, if so, which registers it should use. Handle
+ types that include pure scalable types but are not themselves
+ pure scalable types.
+ (aarch64_return_in_memory_1): New function, split out from...
+ (aarch64_return_in_memory): ...here. Use pure_scalable_type_info
+ to analyze whether the type is a pure scalable type and, if so,
+ whether it should be returned by reference.
+ (aarch64_layout_arg): Remove orig_mode argument. Use
+ pure_scalable_type_info to analyze whether the type is a pure
+ scalable type and, if so, which registers it should use. Handle
+ types that include pure scalable types but are not themselves
+ pure scalable types.
+ (aarch64_function_arg): Update call accordingly.
+ (aarch64_function_arg_advance): Likewise.
+ (aarch64_pad_reg_upward): On big-endian targets, return false for
+ pure scalable types that are smaller than 16 bytes.
+ (aarch64_member_type_forces_blk): New function.
+ (aapcs_vfp_sub_candidate): Exit early for built-in SVE types.
+ (aarch64_short_vector_p): Return false for VECTOR_TYPEs that
+ correspond to built-in SVE types. Do not rely on a vector mode
+ if the type includes an pure scalable type. When returning true,
+ assert that the mode is not an SVE mode.
+ (aarch64_vfp_is_call_or_return_candidate): Do not check for SVE
+ built-in types here. When returning true, assert that the type
+ does not have an SVE mode.
+ (aarch64_can_change_mode_class): Don't allow anything to change
+ between a predicate mode and a non-predicate mode. Also don't
+ allow changes between SVE vector modes and other modes that
+ might be bigger than 128 bits.
+ (aarch64_invalid_binary_op): Reject binary operations that mix
+ SVE and GNU vector types.
+ (TARGET_MEMBER_TYPE_FORCES_BLK): Define.
+
2020-04-09 Richard Sandiford <richard.sandiford@arm.com>
* config/aarch64/aarch64.c (aarch64_attribute_table): Add
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,
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
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
{
/* 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;
{
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);
{
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);
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,
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<piece, MAX_PIECES> 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;
#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 *,
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 }
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 &
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. */
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
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);
}
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);
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)
&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))
{
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);
}
}
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.
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;
/* 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,
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)
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;
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
/* 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)
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. */
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)
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
{
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;
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);
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;
}
|| 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;
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;
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. */
}
}
+/* 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
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))
{
{
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
{
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);
else
return false;
+ gcc_assert (!aarch64_sve_mode_p (new_mode));
*base_mode = new_mode;
return true;
}
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. */
|| 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.
|| element_mode (type2) == BFmode)
return N_("operation not permitted on type %<bfloat16_t%>");
+ 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;
}
#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
@item aarch64_small_fpic
Binutils installed on test system supports relocation types required by -fpic
for AArch64 small memory model.
+@item aarch64_sve_hw
+AArch64 target that is able to generate and execute SVE code (regardless of
+whether it does so by default).
+@item aarch64_sve128_hw
+@itemx aarch64_sve256_hw
+@itemx aarch64_sve512_hw
+@itemx aarch64_sve1024_hw
+@itemx aarch64_sve2048_hw
+Like @code{aarch64_sve_hw}, but also test for an exact hardware vector length.
@end table
+2020-04-09 Richard Sandiford <richard.sandiford@arm.com>
+
+ * gcc.target/aarch64/sve/acle/general/attributes_1.c: New test.
+ * gcc.target/aarch64/sve/acle/general/attributes_2.c: Likewise.
+ * gcc.target/aarch64/sve/acle/general/attributes_3.c: Likewise.
+ * gcc.target/aarch64/sve/acle/general/attributes_4.c: Likewise.
+ * gcc.target/aarch64/sve/acle/general/attributes_5.c: Likewise.
+ * gcc.target/aarch64/sve/acle/general/attributes_6.c: Likewise.
+ * gcc.target/aarch64/sve/acle/general/attributes_7.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct.h: New file.
+ * gcc.target/aarch64/sve/pcs/struct_1_128.c: New test.
+ * gcc.target/aarch64/sve/pcs/struct_1_256.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_1_512.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_1_1024.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_1_2048.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_2_128.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_2_256.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_2_512.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_2_1024.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_2_2048.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_3_128.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_3_256.c: Likewise.
+ * gcc.target/aarch64/sve/pcs/struct_3_512.c: Likewise.
+ * lib/target-supports.exp (check_effective_target_aarch64_sve128_hw)
+ (check_effective_target_aarch64_sve512_hw)
+ (check_effective_target_aarch64_sve1024_hw)
+ (check_effective_target_aarch64_sve2048_hw): New procedures.
+
2020-04-09 Matthew Malcomson <matthew.malcomson@arm.com>
* g++.target/arm/cde_mve.C: New test.
--- /dev/null
+/* { dg-options "-msve-vector-bits=256" } */
+
+#include <arm_sve.h>
+
+#ifndef __ARM_FEATURE_SVE_BITS
+#error "__ARM_FEATURE_SVE_BITS is not defined but should be"
+#endif
+
+#if __ARM_FEATURE_SVE_VECTOR_OPERATIONS != 1
+#error "__ARM_FEATURE_SVE_VECTOR_OPERATIONS should be equal to 1"
+#endif
+
+#ifndef __cplusplus
+#define alignof _Alignof
+#endif
+
+#define N __ARM_FEATURE_SVE_BITS
+#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
+#define GNU_ATTR __attribute__ ((vector_size (N / 8)))
+
+typedef svint8_t fixed_int8_t FIXED_ATTR;
+typedef svint16_t fixed_int16_t FIXED_ATTR;
+typedef svint32_t fixed_int32_t FIXED_ATTR;
+typedef svint64_t fixed_int64_t FIXED_ATTR;
+
+typedef svuint8_t fixed_uint8_t FIXED_ATTR;
+typedef svuint16_t fixed_uint16_t FIXED_ATTR;
+typedef svuint32_t fixed_uint32_t FIXED_ATTR;
+typedef svuint64_t fixed_uint64_t FIXED_ATTR;
+
+typedef svbfloat16_t fixed_bfloat16_t FIXED_ATTR;
+typedef svfloat16_t fixed_float16_t FIXED_ATTR;
+typedef svfloat32_t fixed_float32_t FIXED_ATTR;
+typedef svfloat64_t fixed_float64_t FIXED_ATTR;
+
+typedef svbool_t fixed_bool_t FIXED_ATTR;
+
+typedef int8_t gnu_int8_t GNU_ATTR;
+typedef int16_t gnu_int16_t GNU_ATTR;
+typedef int32_t gnu_int32_t GNU_ATTR;
+typedef int64_t gnu_int64_t GNU_ATTR;
+
+typedef uint8_t gnu_uint8_t GNU_ATTR;
+typedef uint16_t gnu_uint16_t GNU_ATTR;
+typedef uint32_t gnu_uint32_t GNU_ATTR;
+typedef uint64_t gnu_uint64_t GNU_ATTR;
+
+typedef bfloat16_t gnu_bfloat16_t GNU_ATTR;
+typedef float16_t gnu_float16_t GNU_ATTR;
+typedef float32_t gnu_float32_t GNU_ATTR;
+typedef float64_t gnu_float64_t GNU_ATTR;
+
+void f() {
+#define TEST_VECTOR(TYPE) \
+ do \
+ { \
+ int assert_sizeof[sizeof (TYPE) == N / 8 ? 1 : -1]; \
+ int assert_alignof[alignof (TYPE) == 16 ? 1 : -1]; \
+ } \
+ while (0)
+
+ TEST_VECTOR (fixed_int8_t);
+ TEST_VECTOR (fixed_int16_t);
+ TEST_VECTOR (fixed_int32_t);
+ TEST_VECTOR (fixed_int64_t);
+
+ TEST_VECTOR (fixed_uint8_t);
+ TEST_VECTOR (fixed_uint16_t);
+ TEST_VECTOR (fixed_uint32_t);
+ TEST_VECTOR (fixed_uint64_t);
+
+ TEST_VECTOR (fixed_bfloat16_t);
+ TEST_VECTOR (fixed_float16_t);
+ TEST_VECTOR (fixed_float32_t);
+ TEST_VECTOR (fixed_float64_t);
+
+#undef TEST_VECTOR
+
+ {
+ int assert_sizeof[sizeof(fixed_bool_t) == N / 64 ? 1 : -1];
+ int assert_alignof[alignof(fixed_bool_t) == 2 ? 1 : -1];
+ }
+}
+
+#define TEST_GLOBAL(TYPE) \
+ extern fixed_##TYPE extern_##TYPE; \
+ fixed_##TYPE global_##TYPE;
+
+#define TEST_STRUCT(TYPE) \
+ struct struct_##TYPE \
+ { \
+ fixed_##TYPE a, b, c[3]; \
+ }; \
+ \
+ union union_##TYPE \
+ { \
+ fixed_##TYPE a, b, c[3]; \
+ };
+
+#define TEST_CONVERT(TYPE, PREFIX) \
+ PREFIX##TYPE \
+ to_##PREFIX##TYPE (fixed_##TYPE x) \
+ { \
+ return x; \
+ } \
+ \
+ fixed_##TYPE \
+ from_##PREFIX##TYPE (PREFIX##TYPE x) \
+ { \
+ return x; \
+ }
+
+#define TEST_UNARY(TYPE, NAME, OP) \
+ fixed_##TYPE \
+ NAME##_##TYPE (fixed_##TYPE x) \
+ { \
+ return OP x; \
+ }
+
+#define TEST_BINARY(TYPE, NAME, OP) \
+ fixed_##TYPE \
+ NAME##_##TYPE (fixed_##TYPE x, fixed_##TYPE y) \
+ { \
+ return x OP y; \
+ } \
+ \
+ fixed_##TYPE \
+ NAME##_##TYPE##_eq (fixed_##TYPE x, fixed_##TYPE y) \
+ { \
+ x OP##= y; return x; \
+ }
+
+#define TEST_COMPARISON(TYPE, NAME, OP) \
+ fixed_##TYPE \
+ NAME##_##TYPE (fixed_##TYPE x, fixed_##TYPE y) \
+ { \
+ return x OP y; \
+ }
+
+#define TEST_CALL(TYPE) \
+ fixed_##TYPE \
+ call_##TYPE##_ff (svbool_t pg, fixed_##TYPE x, fixed_##TYPE y) \
+ { \
+ return svsel (pg, x, y); \
+ } \
+ \
+ fixed_##TYPE \
+ call_##TYPE##_sf (svbool_t pg, sv##TYPE x, fixed_##TYPE y) \
+ { \
+ return svsel (pg, x, y); \
+ } \
+ \
+ fixed_##TYPE \
+ call_##TYPE##_fs (svbool_t pg, fixed_##TYPE x, sv##TYPE y) \
+ { \
+ return svsel (pg, x, y); \
+ }
+
+#define TEST_COMMON(TYPE) \
+ TEST_GLOBAL (TYPE) \
+ TEST_STRUCT (TYPE) \
+ TEST_CONVERT (TYPE, sv) \
+ TEST_CALL (TYPE)
+
+#define TEST_VECTOR(TYPE) \
+ TEST_COMMON (TYPE) \
+ TEST_CONVERT (TYPE, gnu_) \
+ TEST_UNARY (TYPE, nop, +) \
+ TEST_UNARY (TYPE, neg, -) \
+ TEST_BINARY (TYPE, add, +) \
+ TEST_BINARY (TYPE, sub, -) \
+ TEST_BINARY (TYPE, mul, *) \
+ TEST_BINARY (TYPE, div, /) \
+
+#define TEST_INT_VECTOR(TYPE) \
+ TEST_VECTOR (TYPE) \
+ TEST_UNARY (TYPE, inv, ~) \
+ TEST_BINARY (TYPE, mod, %) \
+ TEST_BINARY (TYPE, shl, <<) \
+ TEST_BINARY (TYPE, shr, >>) \
+ TEST_BINARY (TYPE, and, &) \
+ TEST_BINARY (TYPE, ior, |) \
+ TEST_BINARY (TYPE, xor, ^) \
+ TEST_COMPARISON (TYPE, eq, =) \
+ TEST_COMPARISON (TYPE, ne, !=) \
+ TEST_COMPARISON (TYPE, lt, <) \
+ TEST_COMPARISON (TYPE, le, <=) \
+ TEST_COMPARISON (TYPE, ge, >=) \
+ TEST_COMPARISON (TYPE, gt, >)
+
+TEST_INT_VECTOR (int8_t);
+TEST_INT_VECTOR (int16_t);
+TEST_INT_VECTOR (int32_t);
+TEST_INT_VECTOR (int64_t);
+
+TEST_INT_VECTOR (uint8_t);
+TEST_INT_VECTOR (uint16_t);
+TEST_INT_VECTOR (uint32_t);
+TEST_INT_VECTOR (uint64_t);
+
+TEST_VECTOR (float16_t);
+TEST_VECTOR (float32_t);
+TEST_VECTOR (float64_t);
+
+TEST_COMMON (bool_t)
--- /dev/null
+/* { dg-options "-msve-vector-bits=512" } */
+
+#include "attributes_1.c"
--- /dev/null
+/* { dg-options "-msve-vector-bits=1024" } */
+
+#include "attributes_1.c"
--- /dev/null
+/* { dg-options "-msve-vector-bits=2048" } */
+
+#include "attributes_1.c"
--- /dev/null
+/* { dg-options "-msve-vector-bits=128" } */
+
+#if __ARM_BIG_ENDIAN && !__ARM_FEATURE_SVE_BITS
+int pass = 1;
+#else
+#include "attributes_1.c"
+#endif
--- /dev/null
+/* { dg-options "-O2 -msve-vector-bits=256" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_sve.h>
+
+#define N __ARM_FEATURE_SVE_BITS
+#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
+#define GNU_ATTR __attribute__ ((vector_size (N / 8)))
+
+typedef svint8_t fixed_int8_t FIXED_ATTR;
+
+typedef svbool_t fixed_bool_t FIXED_ATTR;
+
+typedef int8_t gnu_int8_t GNU_ATTR;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** test_add:
+** add z0\.b, (?:z0\.b, z1\.b|z1\.b, z0\.b)
+** ret
+*/
+fixed_int8_t
+test_add (fixed_int8_t x, fixed_int8_t y)
+{
+ return x + y;
+}
+
+/*
+** test_add_gnu:
+** (
+** add (z[0-9]+\.b), (?:z0\.b, z1\.b|z1\.b, z0\.b)
+** ptrue (p[0-7])\.b, vl32
+** st1b \1, \2, \[x8\]
+** |
+** ptrue (p[0-7]\.b), vl32
+** add (z[0-9]+)\.b, (?:z0\.b, z1\.b|z1\.b, z0\.b)
+** st1b \4, \3, \[x8\]
+** )
+** ret
+*/
+gnu_int8_t
+test_add_gnu (fixed_int8_t x, fixed_int8_t y)
+{
+ return x + y;
+}
+
+/*
+** test_load: { target lp64 }
+** ld1b z0\.b, p0/z, \[x0\]
+** ret
+*/
+/*
+** test_load: { target ilp32 }
+** uxtw x0, w0
+** ld1b z0\.b, p0/z, \[x0\]
+** ret
+*/
+fixed_int8_t
+test_load (fixed_bool_t pg, int8_t *ptr)
+{
+ return svld1 (pg, ptr);
+}
+
+/*
+** test_store: { target lp64 }
+** st1b z0\.b, p0, \[x0\]
+** ret
+*/
+/*
+** test_store: { target ilp32 }
+** uxtw x0, w0
+** st1b z0\.b, p0, \[x0\]
+** ret
+*/
+void
+test_store (fixed_bool_t pg, int8_t *ptr, fixed_int8_t data)
+{
+ svst1 (pg, ptr, data);
+}
+
+/*
+** test_and_z:
+** and p0\.b, p0/z, p1\.b, p2\.b
+** ret
+*/
+fixed_bool_t
+test_and_z (fixed_bool_t pg, svbool_t p1, fixed_bool_t p2)
+{
+ return svand_z (pg, p1, p2);
+}
+
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/* { dg-options "-msve-vector-bits=256 -W -Wall" } */
+
+#include <arm_sve.h>
+
+#define N __ARM_FEATURE_SVE_BITS
+#define FIXED_ATTR __attribute__ ((arm_sve_vector_bits (N)))
+#define GNU_ATTR __attribute__ ((vector_size (N / 8)))
+
+typedef svint8_t fixed_int8_t FIXED_ATTR;
+typedef svint16_t fixed_int16_t FIXED_ATTR;
+
+typedef svuint8_t fixed_uint8_t FIXED_ATTR;
+
+typedef svbool_t fixed_bool_t FIXED_ATTR;
+
+typedef int8_t gnu_int8_t GNU_ATTR;
+typedef int16_t gnu_int16_t GNU_ATTR;
+
+typedef uint8_t gnu_uint8_t GNU_ATTR;
+
+typedef int bad_type_1 __attribute__ ((arm_sve_vector_bits (N))); // { dg-error {'arm_sve_vector_bits' applied to non-SVE type 'int'} }
+typedef svbool_t bad_type_2 __attribute__ ((arm_sve_vector_bits)); // { dg-error {wrong number of arguments specified for 'arm_sve_vector_bits' attribute} }
+typedef svbool_t bad_type_3 __attribute__ ((arm_sve_vector_bits (N, N))); // { dg-error {wrong number of arguments specified for 'arm_sve_vector_bits' attribute} }
+typedef svbool_t bad_type_4 __attribute__ ((arm_sve_vector_bits ("256"))); // { dg-error {'arm_sve_vector_bits' requires an integer constant expression} }
+typedef svbool_t bad_type_5 __attribute__ ((arm_sve_vector_bits (100))); // { dg-warning {unsupported SVE vector size} }
+
+void
+f (int c)
+{
+ svint8_t ss8;
+ fixed_int8_t fs8;
+ gnu_int8_t gs8;
+
+ svuint8_t su8;
+ fixed_uint8_t fu8;
+ gnu_uint8_t gu8;
+
+ svint16_t ss16;
+ fixed_int16_t fs16;
+ gnu_int16_t gs16;
+
+ svbool_t sb;
+ fixed_bool_t fb;
+
+ ss8 = ss8 + ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ ss8 = ss8 + fs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ ss8 = ss8 + gs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ ss8 += ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ ss8 += fs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ ss8 += gs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+
+ fs8 = fs8 + ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ fs8 = fs8 + fs8;
+ fs8 = fs8 + gs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
+ fs8 += ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ fs8 += fs8;
+ fs8 += gs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
+
+ gs8 = gs8 + ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ gs8 = gs8 + fs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
+ gs8 = gs8 + gs8;
+ gs8 += ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\+} }
+ gs8 += fs8; // { dg-error {cannot combine GNU and SVE vectors in a binary operation} }
+ gs8 += gs8;
+
+ fs8 = ss8;
+ fs8 = fs8;
+ fs8 = gs8;
+
+ fs8 = su8; // { dg-error {cannot convert|incompatible types} }
+ fs8 = fu8; // { dg-error {cannot convert|incompatible types} }
+ fs8 = gu8; // { dg-error {cannot convert|incompatible types} }
+
+ fs8 = ss16; // { dg-error {cannot convert|incompatible types} }
+ fs8 = fs16; // { dg-error {cannot convert|incompatible types} }
+ fs8 = gs16; // { dg-error {cannot convert|incompatible types} }
+
+ (void) (c ? ss8 : ss8);
+ (void) (c ? ss8 : fs8); // { dg-error {type mismatch|different types} }
+ (void) (c ? ss8 : gs8); // { dg-error {type mismatch|different types} }
+
+ (void) (c ? fs8 : ss8); // { dg-error {type mismatch|different types} }
+ (void) (c ? fs8 : fs8);
+ (void) (c ? fs8 : gs8); // { dg-error {type mismatch|different types} "" { xfail c++ } }
+
+ (void) (c ? gs8 : ss8); // { dg-error {type mismatch|different types} }
+ (void) (c ? gs8 : fs8); // { dg-error {type mismatch|different types} "" { xfail c++ } }
+ (void) (c ? gs8 : gs8);
+
+ sb = fb;
+ fb = sb;
+
+ (void) (c ? sb : sb);
+ (void) (c ? sb : fb); // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
+
+ (void) (c ? fb : sb); // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
+ (void) (c ? fb : fb);
+}
+
+void
+g (int c)
+{
+ svint8_t *ss8;
+ fixed_int8_t *fs8;
+ gnu_int8_t *gs8;
+
+ svuint8_t *su8;
+ fixed_uint8_t *fu8;
+ gnu_uint8_t *gu8;
+
+ svint16_t *ss16;
+ fixed_int16_t *fs16;
+ gnu_int16_t *gs16;
+
+ svbool_t *sb;
+ fixed_bool_t *fb;
+
+ __PTRDIFF_TYPE__ diff __attribute__((unused));
+ void *select __attribute__((unused));
+
+ diff = ss8 - ss8; // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} }
+ diff = ss8 - fs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
+ // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
+ diff = ss8 - gs8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
+ // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
+
+ diff = fs8 - ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
+ // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
+ diff = fs8 - fs8;
+ diff = fs8 - gs8;
+
+ diff = gs8 - ss8; // { dg-error {invalid operands [^\n]* binary[^\n]*\-} "" { xfail c } }
+ // { dg-error {arithmetic on pointer to SVE type 'svint8_t'} "bogus" { target c } .-1 }
+ diff = gs8 - fs8;
+ diff = gs8 - gs8;
+
+ fs8 = ss8; // { dg-error {invalid conversion} "" { xfail c } }
+ fs8 = fs8;
+ fs8 = gs8;
+
+ fs8 = su8; // { dg-error {cannot convert} "c++" { target c++ } }
+ // { dg-warning {incompatible pointer type} "c" { target c } .-1 }
+ fs8 = fu8; // { dg-error {cannot convert} "c++" { target c++ } }
+ // { dg-warning {incompatible pointer type} "c" { target c } .-1 }
+ fs8 = gu8; // { dg-error {cannot convert} "c++" { target c++ } }
+ // { dg-warning {incompatible pointer type} "c" { target c } .-1 }
+
+ fs8 = ss16; // { dg-error {cannot convert} "c++" { target c++ } }
+ // { dg-warning {incompatible pointer type} "c" { target c } .-1 }
+ fs8 = fs16; // { dg-error {cannot convert} "c++" { target c++ } }
+ // { dg-warning {incompatible pointer type} "c" { target c } .-1 }
+ fs8 = gs16; // { dg-error {cannot convert} "c++" { target c++ } }
+ // { dg-warning {incompatible pointer type} "c" { target c } .-1 }
+
+ select = c ? ss8 : ss8;
+ select = c ? ss8 : fs8; // { dg-error {distinct pointer types} "" { xfail c } }
+ select = c ? ss8 : gs8; // { dg-error {distinct pointer types} "" { xfail c } }
+
+ select = c ? fs8 : ss8; // { dg-error {distinct pointer types} "" { xfail c } }
+ select = c ? fs8 : fs8;
+ select = c ? fs8 : gs8; // { dg-error {distinct pointer types} "" { xfail *-*-* } }
+
+ select = c ? gs8 : ss8; // { dg-error {distinct pointer types} "" { xfail c } }
+ select = c ? gs8 : fs8; // { dg-error {distinct pointer types} "" { xfail *-*-* } }
+ select = c ? gs8 : gs8;
+
+ diff = sb - sb; // { dg-error {arithmetic on pointer to SVE type 'svbool_t'} }
+ diff = sb - fb; // { dg-error {arithmetic on pointer to SVE type 'svbool_t'} }
+
+ diff = fb - sb; // { dg-error {arithmetic on pointer to SVE type 'svbool_t'} }
+ diff = fb - fb;
+
+ sb = fb;
+ fb = sb;
+
+ select = c ? sb : sb;
+ select = c ? sb : fb; // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
+
+ select = c ? fb : sb; // { dg-error {type mismatch|different types} "" { xfail *-*-* } }
+ select = c ? fb : fb;
+}
--- /dev/null
+#ifndef STRUCT_H
+#define STRUCT_H 1
+
+#include <arm_sve.h>
+
+#ifndef __ARM_FEATURE_SVE_BITS
+#error "__ARM_FEATURE_SVE_BITS should be defined"
+#endif
+
+#define FIXED_ATTR \
+ __attribute__ ((arm_sve_vector_bits (__ARM_FEATURE_SVE_BITS)))
+
+#define SVE_BYTES (__ARM_FEATURE_SVE_BITS / 8)
+
+typedef __SVInt8_t fixed_int8_t FIXED_ATTR;
+typedef __SVInt16_t fixed_int16_t FIXED_ATTR;
+typedef __SVInt32_t fixed_int32_t FIXED_ATTR;
+typedef __SVInt64_t fixed_int64_t FIXED_ATTR;
+
+typedef __SVUint8_t fixed_uint8_t FIXED_ATTR;
+typedef __SVUint16_t fixed_uint16_t FIXED_ATTR;
+typedef __SVUint32_t fixed_uint32_t FIXED_ATTR;
+typedef __SVUint64_t fixed_uint64_t FIXED_ATTR;
+
+typedef __SVBfloat16_t fixed_bfloat16_t FIXED_ATTR;
+typedef __SVFloat16_t fixed_float16_t FIXED_ATTR;
+typedef __SVFloat32_t fixed_float32_t FIXED_ATTR;
+typedef __SVFloat64_t fixed_float64_t FIXED_ATTR;
+
+typedef __SVBool_t fixed_bool_t FIXED_ATTR;
+
+/* Define an asm function called NAME with return type RET_TYPE and
+ argument list ARG_TYPES. INSNS contains the body of the function,
+ except for the final "ret".
+
+ Conservatively mark the function as a variant PCS function,
+ since many uses are. */
+#define ASM_FUNCTION(NAME, RET_TYPE, ARG_TYPES, INSNS) \
+extern RET_TYPE NAME ARG_TYPES; \
+ asm( \
+" .type " #NAME ", %function\n" \
+#NAME ":\n" \
+" " INSNS "\n" \
+" ret\n" \
+" .size " #NAME ", .-" #NAME "\n" \
+" .variant_pcs " #NAME "\n" \
+)
+
+/* Set the argument registers to fixed values. */
+#define CLEANSE \
+ asm volatile ("mov\tx0, #-1\n\t" \
+ "mov\tx1, #-1\n\t" \
+ "mov\tx2, #-1\n\t" \
+ "mov\tx3, #-1\n\t" \
+ "mov\tx4, #-1\n\t" \
+ "mov\tx5, #-1\n\t" \
+ "mov\tx6, #-1\n\t" \
+ "mov\tx7, #-1\n\t" \
+ "mov\tx8, #-1\n\t" \
+ "mov\tz0.b, #0xaf\n\t" \
+ "mov\tz1.b, #0xaf\n\t" \
+ "mov\tz2.b, #0xaf\n\t" \
+ "mov\tz3.b, #0xaf\n\t" \
+ "mov\tz4.b, #0xaf\n\t" \
+ "mov\tz5.b, #0xaf\n\t" \
+ "mov\tz6.b, #0xaf\n\t" \
+ "mov\tz7.b, #0xaf\n\t" \
+ "pfalse\tp0.b\n\t" \
+ "pfalse\tp1.b\n\t" \
+ "pfalse\tp2.b\n\t" \
+ "pfalse\tp3.b" \
+ ::: \
+ "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", \
+ "z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", \
+ "p0", "p1", "p2", "p3")
+
+#endif
--- /dev/null
+/* { dg-do run { target { aarch64_sve1024_hw } } } */
+/* { dg-options "-msve-vector-bits=1024" } */
+
+#include "struct_1_128.c"
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { dg-do run { target { aarch64_sve2048_hw } } } */
+/* { dg-options "-msve-vector-bits=2048" } */
+
+#include "struct_1_128.c"
--- /dev/null
+/* { dg-do run { target { aarch64_sve256_hw } } } */
+/* { dg-options "-msve-vector-bits=256" } */
+
+#include "struct_1_128.c"
--- /dev/null
+/* { dg-do run { target { aarch64_sve512_hw } } } */
+/* { dg-options "-msve-vector-bits=512" } */
+
+#include "struct_1_128.c"
--- /dev/null
+/* { dg-do run { target { aarch64_sve1024_hw } } } */
+/* { dg-options "-msve-vector-bits=1024" } */
+
+#include "struct_2_128.c"
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { dg-do run { target { aarch64_sve2048_hw } } } */
+/* { dg-options "-msve-vector-bits=2048" } */
+
+#include "struct_2_128.c"
--- /dev/null
+/* { dg-do run { target { aarch64_sve256_hw } } } */
+/* { dg-options "-msve-vector-bits=256" } */
+
+#include "struct_2_128.c"
--- /dev/null
+/* { dg-do run { target { aarch64_sve512_hw } } } */
+/* { dg-options "-msve-vector-bits=512" } */
+
+#include "struct_2_128.c"
--- /dev/null
+/* { 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 } };
+}
--- /dev/null
+/* { 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 } };
+}
--- /dev/null
+/* { 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 } };
+}
# 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 { } {