> On 9 Jul 2026, at 14:41, [email protected] <[email protected]> wrote:
>
> From: Ezra Sitorus <[email protected]>
>
> This patch adds the following SVE2p3 intrinsics:
> * svluti6[_s8_x2]
> * svluti6_lane[_s16_x2]
>
> and the following SME2p3 intrinsics:
> * svluti6_zt_s8
> * svluti6_zt_s8_x4
> * svluti6_lane_s16_x4[_s16_x2_u8_x2]
> * svluti6_lane_s16_x4[_s16_x2_u8_x3]
>
> along with their other type variants.
>
> This patch depends on:
> * SVE2p3/SME2p3 flags from Richard Ball's SVE2p3/SME2p3 dot product
> intrinsic patch. Here's one version but there may be a more recent
> version:
>
> https://inbox.sourceware.org/gcc-patches/bmm.hj1cfgo5za.gcc.gcc-test.ricbal02.164....@forge-stage.sourceware.org/
> * SVE_FULL_BIx2 mode iterator from Karl Meakin's SME_MOP4 patch:
>
> https://inbox.sourceware.org/gcc-patches/[email protected]/
>
> Regarding this patch, there are 2 things I want to highlight:
>
> 1) For those last 2 intrinsics, AFAIK, the current system won't allow us
> to have multiple group suffixes, let alone match them with multiple
> type suffixes. The way I've resolved it for these is to:
> 1) have the return type and group suffix to the base name
> 2) check if it's a luti6_lane_sme shape
> 3) manually append "_x2_u8" to the name if it is the right shape
> 4) add the group suffix (either x2 or x3). 2 - 3 is done in
> gcc/config/aarch64/aarch64-acle-builtins.cc:function_builder::get_name.
>
> I'd appreciate if there are better ways of doing this, or perhaps other
> intrinsics which follow this pattern which I've missed out on.
>
> 2) In the tests, since some of these intrinsics don't have an overloaded
> form, a few of them have the same code repeated:
>
> TEST_XN_SINGLE (luti6_zt_s8_test, svint8_t, svuint8_t, z1,
> svluti6_zt_s8 (0, z0), svluti6_zt_s8 (0, z0))
>
> I'm wondering if this is OK? Or should I write new macros for these
> intrinsics which only have 1 form?
>
> Ezra
>
> gcc/ChangeLog:
> * config/aarch64/aarch64-acle-builtins.cc
> (function_builder::get_name): Add case for svluti6_lane names.
> * config/aarch64/aarch64-acle-builtins.h
> (TYPES_h_unsigned): New data type.
> (TYPES_h_signed): Likewise.
> (b_data): Likewise.
> (groups_x23): New group suffix.
> * config/aarch64/aarch64-sme.md
> (@aarch64_sme_luti6<mode>): New insn.
> (aarch64_sme_luti6_ztvnx16qi): Likewise.
> (aarch64_sme_luti6_ztvnx64qi): Likewise.
> * config/aarch64/aarch64-sve-builtins-shapes.cc
> (parse_type): Add 'm', 'p' options for vectors per tuple minus/plus one.
> (luti6_def): New class.
> (luti6_no_lane_def): Likewise.
> (luti6_lane_sme_def): Likewise.
> (luti6_table_zt_def): Likewise.
> (luti6_single_zt_def): Likewise.
> * config/aarch64/aarch64-sve-builtins-shapes.h
> (luti6, luti6_no_lane, luti6_lane_sme, luti6_single_zt)
> (luti6_table_zt): Declare new shapes.
> * config/aarch64/aarch64-sve-builtins-sme.cc
> (svluti6_lane_impl, svluti6_zt_impl): New classes.
> (svluti6_lane_s16_x4, svluti6_lane_u16_x4, svluti6_lane_f16_x4)
> (svluti6_lane_bf16_x4, svluti6_zt): New function entries.
> * config/aarch64/aarch64-sve-builtins-sme.def
> (svluti6_lane_s16_x4, svluti6_lane_u16_x4, svluti6_lane_f16_x4)
> (svluti6_lane_bf16_x4, svluti6_zt): Define new SME functions.
> * config/aarch64/aarch64-sve-builtins-sme.h
> (svluti6_lane_s16_x4, svluti6_lane_u16_x4, svluti6_lane_f16_x4)
> (svluti6_lane_bf16_x4, svluti6_zt): Declare new function base.
> * config/aarch64/aarch64-sve-builtins-sve2.cc
> (svluti_lane_impl): Add luti6 case.
> (svluti6_impl): New class.
> (svluti6_lane, svluti6): New function entries.
> * config/aarch64/aarch64-sve-builtins-sve2.def
> (svluti6, svluti6_lane): Define new SVE functions.
> * config/aarch64/aarch64-sve-builtins-sve2.h
> (svluti6, svluti6_lane): Declare new function base.
> * config/aarch64/aarch64-sve2.md
> (@aarch64_sve_luti6<mode>): New pattern.
> (@aarch64_sve_luti6_no_lane<mode>): Likewise.
>
> gcc/testsuite/ChangeLog:
> * gcc.target/aarch64/sme2/acle-asm/luti6_lane.c: New test.
> * gcc.target/aarch64/sme2/acle-asm/luti6_zt.c: New test.
> * gcc.target/aarch64/sve2/acle/asm/luti6.c: New test.
> * gcc.target/aarch64/sve2/acle/asm/luti6_lane.c: New test.
> ---
> gcc/config/aarch64/aarch64-acle-builtins.cc | 10 +
> gcc/config/aarch64/aarch64-acle-builtins.h | 15 ++
> gcc/config/aarch64/aarch64-sme.md | 51 +++++
> .../aarch64/aarch64-sve-builtins-shapes.cc | 208 +++++++++++++++++-
> .../aarch64/aarch64-sve-builtins-shapes.h | 5 +
> .../aarch64/aarch64-sve-builtins-sme.cc | 58 +++++
> .../aarch64/aarch64-sve-builtins-sme.def | 9 +
> gcc/config/aarch64/aarch64-sve-builtins-sme.h | 5 +
> .../aarch64/aarch64-sve-builtins-sve2.cc | 14 ++
> .../aarch64/aarch64-sve-builtins-sve2.def | 5 +
> .../aarch64/aarch64-sve-builtins-sve2.h | 2 +
> gcc/config/aarch64/aarch64-sve2.md | 24 ++
> .../aarch64/sme2/acle-asm/luti6_lane.c | 183 +++++++++++++++
> .../aarch64/sme2/acle-asm/luti6_zt.c | 55 +++++
> .../gcc.target/aarch64/sve2/acle/asm/luti6.c | 40 ++++
> .../aarch64/sve2/acle/asm/luti6_lane.c | 60 +++++
> 16 files changed, 743 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_lane.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_zt.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6.c
> create mode 100644 gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6_lane.c
>
> diff --git a/gcc/config/aarch64/aarch64-acle-builtins.cc
> b/gcc/config/aarch64/aarch64-acle-builtins.cc
> index 426316001ced..6adae597e441 100644
> --- a/gcc/config/aarch64/aarch64-acle-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-acle-builtins.cc
> @@ -615,6 +615,16 @@ function_builder::get_name (const function_instance
> &instance,
> for (unsigned int i = 0; i < 3; ++i)
> if (!overloaded_p || instance.shape->explicit_type_suffix_p (i))
> append_name (instance.type_suffix (i).string);
> +
> + /* The non-overloaded SME LUTI6 lane forms have names like
> + svluti6_lane_<t>_x4_<t>_x2_u8_x2 and svluti6_lane_<t>_x4_<t>_x2_u8_x3.
> +
> + The current naming machinery adds the table type <t> and the final
> _x2/_x3
> + but has no way to express the table group suffix (e.g. <t>_x2) nor the
> + indices type (fixed u8) so these are manually done here. */
> + if (!overloaded_p && instance.shape == shapes::luti6_lane_sme)
> + append_name ("_x2_u8");
> +
> if (!overloaded_p || instance.shape->explicit_group_suffix_p ())
> append_name (instance.group_suffix ().string);
> append_name (pred_suffixes[instance.pred]);
> diff --git a/gcc/config/aarch64/aarch64-acle-builtins.h
> b/gcc/config/aarch64/aarch64-acle-builtins.h
> index dac45dbe058a..2c479a03d138 100644
> --- a/gcc/config/aarch64/aarch64-acle-builtins.h
> +++ b/gcc/config/aarch64/aarch64-acle-builtins.h
> @@ -1321,6 +1321,14 @@ function_expander::result_mode () const
> #define TYPES_h_float(S, D, T) \
> S (f16)
>
> +/* _u16. */
> +#define TYPES_h_unsigned(S, D, T) \
> + S (u16)
> +
> +/* _s16. */
> +#define TYPES_h_signed(S, D, T) \
> + S (s16)
> +
> /* _s16
> _u16. */
> #define TYPES_h_integer(S, D, T) \
> @@ -1965,6 +1973,7 @@ DEF_SVE_TYPES_ARRAY (all_arith);
> DEF_SVE_TYPES_ARRAY (all_arith_no_fp16);
> DEF_SVE_TYPES_ARRAY (all_data);
> DEF_SVE_TYPES_ARRAY (b);
> +DEF_SVE_TYPES_ARRAY (b_data);
> DEF_SVE_TYPES_ARRAY (b_unsigned);
> DEF_SVE_TYPES_ARRAY (b_integer);
> DEF_SVE_TYPES_ARRAY (bh_integer);
> @@ -1981,6 +1990,8 @@ DEF_SVE_TYPES_ARRAY (h_float);
> DEF_SVE_TYPES_ARRAY (h_float_mf8);
> DEF_SVE_TYPES_ARRAY (h_integer);
> DEF_SVE_TYPES_ARRAY (h_data);
> +DEF_SVE_TYPES_ARRAY (h_unsigned);
> +DEF_SVE_TYPES_ARRAY (h_signed);
> DEF_SVE_TYPES_ARRAY (hs_signed);
> DEF_SVE_TYPES_ARRAY (hs_integer);
> DEF_SVE_TYPES_ARRAY (hs_float);
> @@ -2091,6 +2102,10 @@ static const group_suffix_index groups_x12[] = {
>
> static const group_suffix_index groups_x4[] = { GROUP_x4, NUM_GROUP_SUFFIXES
> };
>
> +static const group_suffix_index groups_x23[] = {
> + GROUP_x2, GROUP_x3, NUM_GROUP_SUFFIXES
> +};
> +
> static const group_suffix_index groups_x24[] = {
> GROUP_x2, GROUP_x4, NUM_GROUP_SUFFIXES
> };
> diff --git a/gcc/config/aarch64/aarch64-sme.md
> b/gcc/config/aarch64/aarch64-sme.md
> index 7091f566ba8d..1e1e5f13cc58 100644
> --- a/gcc/config/aarch64/aarch64-sme.md
> +++ b/gcc/config/aarch64/aarch64-sme.md
> @@ -2747,6 +2747,7 @@
> ;; Includes:
> ;; - LUTI2 (SME2)
> ;; - LUTI4 (SME2)
> +;; - LUTI6 (SME2p3)
> ;; -------------------------------------------------------------------------
>
> (define_c_enum "unspec" [
> @@ -2795,3 +2796,53 @@
> "TARGET_SME_LUTv2 && TARGET_STREAMING"
> "luti4\t%0, zt0, {%Z1 - %T1}"
> )
> +
> +;; LUTI6 (vector, 16-bit)
> +;; Variants are also available for: _u16, _f16 and _bf16.
> +;; svint16x4_t svluti6_lane_s16_x4_s16_x2_u8_x2 (svint16x2_t table,
> +;; svuint8x2_t indices,
> +;; uint64_t imm_idx)
> __arm_streaming;
> +
> +(define_insn "@aarch64_sme_luti6<mode>"
> + [(set (match_operand:VNx32HI 0 "register_operand" "=w")
Do you need to use aligned_register_operand and =Uw4 here?
> + (unspec:VNx32HI
> + [(match_operand:SVE_FULL_Hx2 1 "register_operand" "w")
> + (match_operand:VNx32QI 2 "register_operand" "w")
> + (match_operand:DI 3 "const_int_operand")]
> + UNSPEC_SME_LUTI))]
> + "TARGET_SME2p3 && TARGET_STREAMING"
> + "luti6\t%0, %1, {%Z2 - %T2}[%3]"
> + [(set_attr "sve_type" "sve_int_general")]
> +)
> +
> +;; LUTI6 (table, single, 8-bit)
> +;; Variants are also available for: _u8 and _mf8.
> +;; svint8_t svluti6_zt_s8(uint64_t zt0, svuint8_t zn)
> +;; __arm_streaming __arm_in("zt0");
> +
> +(define_insn "aarch64_sme_luti6_ztvnx16qi"
> + [(set (match_operand:VNx16QI 0 "register_operand" "=w")
> + (unspec:VNx16QI
> + [(reg:V8DI ZT0_REGNUM)
> + (reg:DI SME_STATE_REGNUM)
> + (match_operand:VNx16QI 1 "register_operand" "w")]
> + UNSPEC_SME_LUTI_ZT))]
> + "TARGET_SME2p3 && TARGET_STREAMING"
> + "luti6\t%0.b, zt0, %Z1"
> +)
> +
> +;; LUTI6 (table, four registers, 8-bit)
> +;; Variants are also available for: _u8 and _mf8.
> +;; svint8x4_t svluti6_zt_s8_x4(uint64_t zt0, svuint8x3_t zn)
> +;; __arm_streaming __arm_in ("zt0");
> +
> +(define_insn "aarch64_sme_luti6_ztvnx64qi"
> + [(set (match_operand:VNx64QI 0 "aligned_register_operand" "=Uw4")
> + (unspec:VNx64QI
> + [(reg:V8DI ZT0_REGNUM)
> + (reg:DI SME_STATE_REGNUM)
> + (match_operand:VNx48QI 1 "register_operand" "w")]
> + UNSPEC_SME_LUTI_ZT))]
> + "TARGET_SME2p3 && TARGET_STREAMING"
> + "luti6\t%0, zt0, {%Z1 - %U1}"
> +)
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc
> b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc
> index 00aa57a7a2c4..f1a529c26447 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.cc
> @@ -202,6 +202,8 @@ parse_element_type (const function_instance &instance,
> const char *&format)
> t<elt> - a vector or tuple type with given element suffix [*1]
> T<elt> - a vector or tuple type with given element suffix [*2]
> u<elt> - a vector or tuple type with given element suffix [*3]
> + m<elt> - a vector or tuple type with given element suffix [*4]
> + p<elt> - a vector or tuple type with given element suffix [*5]
> v<elt> - a vector with the given element suffix
> D<elt> - a 64 bit neon vector
> Q<elt> - a 128 bit neon vector
> @@ -214,6 +216,8 @@ parse_element_type (const function_instance &instance,
> const char *&format)
> be a tuple, and if so, how many vectors it should contain.
> [*2] same as for [*1], but the tuple contains half as many vectors.
> [*3] same as for [*1], but the tuple contains twice as many vectors.
> + [*4] same as for [*1], but the tuple contains one fewer vector.
> + [*5] same as for [*1], but the tuple contains one more vector.
> */
> static tree
> parse_type (const function_instance &instance, const char *&format)
> @@ -317,6 +321,24 @@ parse_type (const function_instance &instance, const
> char *&format)
> return acle_vector_types[num_vectors - 1][vector_type];
> }
>
> + if (ch == 'm')
> + {
> + type_suffix_index suffix = parse_element_type (instance, format);
> + vector_type_index vector_type = type_suffixes[suffix].vector_type;
> + unsigned int num_vectors = instance.vectors_per_tuple ();
> + gcc_assert (num_vectors > 1);
> + return acle_vector_types[num_vectors - 2][vector_type];
> + }
> +
> + if (ch == 'p')
> + {
> + type_suffix_index suffix = parse_element_type (instance, format);
> + vector_type_index vector_type = type_suffixes[suffix].vector_type;
> + unsigned int num_vectors = instance.vectors_per_tuple ();
> + gcc_assert (num_vectors < 4);
> + return acle_vector_types[num_vectors][vector_type];
> + }
> +
> if (ch == 'v')
> {
> type_suffix_index suffix = parse_element_type (instance, format);
> @@ -1003,13 +1025,45 @@ struct luti_base : public overloaded_base<0>
> }
> };
>
> -/* Specializations for 2-bit and 4-bit indices. */
> +/* Specializations for 2-bit, 4-bit and 6-bit indices. */
> using luti2_def = luti_base<2>;
> SHAPE (luti2);
>
> using luti4_def = luti_base<4>;
> SHAPE (luti4);
>
> +using luti6_def = luti_base<6>;
> +SHAPE (luti6);
> +
> +/* sv<v0>_t svluti6[_<t0>](sv<t0>x2_t, svuint8_t)
> +
> + note the final argument is not a constant index, the instruction divides
> + the vector argument in BITS-bit quantities. */
> +struct luti6_no_lane_def : public overloaded_base<0>
> +{
> + bool explicit_group_suffix_p () const override { return false; }
> +
> + void
> + build (function_builder &b, const function_group_info &group) const
> override
> + {
> + /* Format: return type, table vector, indices vector. */
> + b.add_overloaded_functions (group, MODE_none);
> + build_all (b, "v0,t0,vu8", group, MODE_none);
> + }
> +
> + tree
> + resolve (function_resolver &r) const override
> + {
> + sve_type type;
> + if (!r.check_num_arguments (2)
> + || !(type = r.infer_sve_type (0))
> + || !r.require_vector_type (1, VECTOR_TYPE_svuint8_t))
> + return error_mark_node;
> +
> + return r.resolve_to (r.mode_suffix_id, type);
> + }
> +};
> +SHAPE (luti6_no_lane);
>
> /* sv<t0>x<g>_t svfoo_t0_g(uint64_t, svuint8_t, uint64_t)
>
> @@ -1052,6 +1106,158 @@ template <unsigned int BITS> struct luti_zt_base :
> public nonoverloaded_base
> }
> };
>
> +/* svint16x4_t svluti6_lane_s16_x4_<t0>_x2_u8_x2 (sv<t0>_x2_t table,
> + svuint8x2_t indices,
> + uint64_t imm_idx) __arm_streaming;
> + svint16x4_t svluti6_lane_s16_x4_<t0>_x2_u8_x3 (sv<t0>_x2_t table,
> + svuint8x3_t indices,
> + uint64_t imm_idx) __arm_streaming;
> +*/
> +
> +struct luti6_lane_sme_def : public overloaded_base<0>
> +{
> + bool explicit_group_suffix_p () const override { return false; }
> +
> + void
> + build (function_builder &b, const function_group_info &group) const
> override
> + {
> + /* Format: return type, table vector, indices vector, immediate value.
> */
> + b.add_overloaded_functions (group, MODE_none);
> + build_one (b, "u0,t0,tu8,su64", group, MODE_none, 0, 0, 0, false);
> + build_one (b, "p0,m0,tu8,su64", group, MODE_none, 0, 1, 0, false);
> + }
> +
> + bool
> + check (function_checker &c) const override
> + {
> + return c.require_immediate_range (2, 0, 1);
> + }
> +
> + tree
> + resolve (function_resolver &r) const override
> + {
> + if (!r.check_num_arguments (3))
> + return error_mark_node;
> +
> + sve_type table = r.infer_sve_type (0);
> + if (!table)
> + return error_mark_node;
> +
> + if (table.num_vectors != 2)
> + {
> + r.report_incorrect_num_vectors (0, table, 2);
> + return error_mark_node;
> + }
> +
> + if (!r.require_scalar_type (2, "uint64_t"))
> + return error_mark_node;
> +
> + sve_type indices = r.infer_sve_type (1);
> + if (!indices)
> + return error_mark_node;
> +
> + if (indices.num_vectors == 2)
> + {
> + if (!r.require_derived_vector_type (1, 0, table, TYPE_unsigned, 8, 2))
> + return error_mark_node;
> + return r.resolve_to (r.mode_suffix_id, table.type, NUM_TYPE_SUFFIXES,
> + NUM_TYPE_SUFFIXES, GROUP_x2);
> + }
> +
> + if (indices.num_vectors == 3)
> + {
> + if (!r.require_derived_vector_type (1, 0, table, TYPE_unsigned, 8, 3))
> + return error_mark_node;
> + return r.resolve_to (r.mode_suffix_id, table.type, NUM_TYPE_SUFFIXES,
> + NUM_TYPE_SUFFIXES, GROUP_x3);
> + }
> +
> + r.report_no_such_form (indices);
> + return error_mark_node;
> + }
> +};
> +
> +SHAPE (luti6_lane_sme);
> +
> +/* LUTI6 (table, four registers, 8-bit)
> + Variants are also available for: _u8 and _mf8.
> + svint8x4_t svluti6_zt_s8_x4(uint64_t zt0, svuint8x3_t zn)
> + __arm_streaming __arm_in("zt0"); */
> +struct luti6_table_zt_def : public nonoverloaded_base
> +{
> + void build (function_builder &b,
> + const function_group_info &group) const override
> + {
> + build_all (b, "t0,su64,mu8", group, MODE_none);
> + }
> +
> + bool check (function_checker &c) const override
> + {
> + return c.require_immediate_range (0, 0, 0);
> + }
> +
> + tree
> + resolve (function_resolver &r) const override
> + {
> + if (!r.check_num_arguments (2))
> + return error_mark_node;
> +
> + if (!r.require_scalar_type (0, "uint64_t"))
> + return error_mark_node;
> +
> + sve_type type = r.infer_sve_type (1);
> + if (!type)
> + return error_mark_node;
> +
> + if (type.num_vectors != 3)
> + {
> + r.report_incorrect_num_vectors (1, type, 3);
> + return error_mark_node;
> + }
> +
> + return r.resolve_to (r.mode_suffix_id, type);
> + }
> +};
> +
> +SHAPE (luti6_table_zt);
> +
> +struct luti6_single_zt_def : public nonoverloaded_base
> +{
> + void build (function_builder &b,
> + const function_group_info &group) const override
> + {
> + build_all (b, "v0,su64,vu8", group, MODE_none);
> + }
> +
> + bool check (function_checker &c) const override
> + {
> + return c.require_immediate_range (0, 0, 0);
> + }
> +
> + tree
> + resolve (function_resolver &r) const override
> + {
> + if (!r.check_num_arguments (2))
> + return error_mark_node;
> +
> + if (!r.require_scalar_type (0, "uint64_t"))
> + return error_mark_node;
> +
> + sve_type type = r.infer_sve_type (1);
> + if (!type)
> + return error_mark_node;
> +
> + if (type.num_vectors != 1)
> + {
> + r.report_incorrect_num_vectors (1, type, 1);
> + return error_mark_node;
> + }
> +
> + return r.resolve_to (r.mode_suffix_id, type);
> + }
> +};
> +SHAPE (luti6_single_zt);
> +
> /* sv<t0>_t svfoo[_t0](sv<t0>_t, sv<t0:quarter>_t,
> sv<t0:quarter>_t) (for integer t0)
> sv<t0>_t svmmla[_t0](sv<t0>_t, sv<t0>_t, sv<t0>_t) (for floating-point t0)
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-shapes.h
> b/gcc/config/aarch64/aarch64-sve-builtins-shapes.h
> index ce02b5a45ecc..7724f5b9ae00 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-shapes.h
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.h
> @@ -167,9 +167,14 @@ namespace aarch64_acle
> extern const function_shape *const load_za;
> extern const function_shape *const luti2;
> extern const function_shape *const luti4;
> + extern const function_shape *const luti6;
> + extern const function_shape *const luti6_no_lane;
> extern const function_shape *const luti2_lane_zt;
> extern const function_shape *const luti4_lane_zt;
> extern const function_shape *const luti4_zt;
> + extern const function_shape *const luti6_lane_sme;
> + extern const function_shape *const luti6_single_zt;
> + extern const function_shape *const luti6_table_zt;
> extern const function_shape *const mmla;
> extern const function_shape *const pattern_pred;
> extern const function_shape *const pmov_from_vector;
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sme.cc
> b/gcc/config/aarch64/aarch64-sve-builtins-sme.cc
> index 9431feb7eeb5..fbecebafafa8 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-sme.cc
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-sme.cc
> @@ -376,6 +376,59 @@ public:
> unsigned int m_bits;
> };
>
> +class svluti6_lane_impl : public function_base
> +{
> +public:
> + rtx
> + expand (function_expander &e) const override
> + {
> + if (e.group_suffix_id == aarch64_acle::GROUP_x3)
> + {
> + rtx vecs[2];
> + for (int i = 0; i < 2; i++)
> + {
> + vecs[i] = force_subreg (
> + E_VNx16QImode, e.args[1], GET_MODE (e.args[1]),
> + (i + INTVAL (e.args[2])) * BYTES_PER_SVE_VECTOR);
> + }
> +
> + rtx tuple = gen_reg_rtx (E_VNx32QImode);
> + for (int i = 0; i < 2; i++)
> + emit_move_insn (simplify_gen_subreg (E_VNx16QImode, tuple,
> + E_VNx32QImode,
> + i * BYTES_PER_SVE_VECTOR),
> + vecs[i]);
> + e.args[1] = tuple;
> + }
> +
> + machine_mode mode = GET_MODE (e.args[0]);
> + rtx res = e.use_exact_insn (code_for_aarch64_sme_luti6 (mode));
> + return aarch64_sve_reinterpret (e.result_mode (), res);
> + }
> +};
> +
> +class svluti6_zt_impl : public read_zt0<function_base>
> +{
> +public:
> + unsigned int
> + call_properties (const function_instance &) const override
> + {
> + return CP_READ_ZT0;
> + }
> +
> + rtx
> + expand (function_expander &e) const override
> + {
> + // Remove `zt0` argument, since it is ignored.
> + e.args.ordered_remove (0);
> + insn_code icode = e.vectors_per_tuple () == 4
> + ? CODE_FOR_aarch64_sme_luti6_ztvnx64qi
> + : CODE_FOR_aarch64_sme_luti6_ztvnx16qi;
> + return e.use_exact_insn (icode);
> + }
> +};
> +
> +
> template<insn_code (*CODE) (machine_mode)>
> class svread_za_slice_base : public function_base
> {
> @@ -641,6 +694,11 @@ FUNCTION (svldr_zt, svldr_zt_impl, )
> FUNCTION (svluti2_lane_zt, svluti_lane_zt_impl, (2))
> FUNCTION (svluti4_lane_zt, svluti_lane_zt_impl, (4))
> FUNCTION (svluti4_zt, svluti_zt_impl, (4))
> +FUNCTION (svluti6_lane_s16_x4, svluti6_lane_impl,)
> +FUNCTION (svluti6_lane_u16_x4, svluti6_lane_impl,)
> +FUNCTION (svluti6_lane_f16_x4, svluti6_lane_impl,)
> +FUNCTION (svluti6_lane_bf16_x4, svluti6_lane_impl,)
> +FUNCTION (svluti6_zt, svluti6_zt_impl,)
> FUNCTION (svmla_za, sme_2mode_function, (UNSPEC_SME_SMLA, UNSPEC_SME_UMLA,
> UNSPEC_SME_FMLA, UNSPEC_SME_FMLAL))
> FUNCTION (svmla_lane_za, sme_2mode_lane_function, (UNSPEC_SME_SMLA,
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sme.def
> b/gcc/config/aarch64/aarch64-sve-builtins-sme.def
> index 4feb47952874..2ff6486f9efb 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-sme.def
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-sme.def
> @@ -293,6 +293,15 @@ DEF_SME_FUNCTION_GS (svwrite_lane_zt, write_lane_zt,
> all_data, none, none)
> DEF_SME_FUNCTION_GS (svluti4_zt, luti4_zt, b_integer, x4, none)
> #undef REQUIRED_EXTENSIONS
>
> +#define REQUIRED_EXTENSIONS streaming_only (AARCH64_FL_SME2p3)
> +DEF_SME_FUNCTION_GS (svluti6_lane_s16_x4, luti6_lane_sme, h_signed, x23,
> none)
> +DEF_SME_FUNCTION_GS (svluti6_lane_u16_x4, luti6_lane_sme, h_unsigned, x23,
> none)
> +DEF_SME_FUNCTION_GS (svluti6_lane_f16_x4, luti6_lane_sme, h_float, x23, none)
> +DEF_SME_FUNCTION_GS (svluti6_lane_bf16_x4, luti6_lane_sme, h_bfloat, x23,
> none)
> +DEF_SME_FUNCTION_GS (svluti6_zt, luti6_single_zt, b_data, none, none)
> +DEF_SME_FUNCTION_GS (svluti6_zt, luti6_table_zt, b_data, x4, none)
> +#undef REQUIRED_EXTENSIONS
> +
> #define REQUIRED_EXTENSIONS streaming_only (AARCH64_FL_SME_F8F16)
> DEF_SME_ZA_FUNCTION_GS_FPM (svmla_lane, binary_za_slice_lane, za_h_mf8,
> vg2, none, set)
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sme.h
> b/gcc/config/aarch64/aarch64-sve-builtins-sme.h
> index cc264ea84869..10238249e113 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-sme.h
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-sme.h
> @@ -47,6 +47,11 @@ namespace aarch64_acle
> extern const function_base *const svluti2_lane_zt;
> extern const function_base *const svluti4_lane_zt;
> extern const function_base *const svluti4_zt;
> + extern const function_base *const svluti6_zt;
> + extern const function_base *const svluti6_lane_s16_x4;
> + extern const function_base *const svluti6_lane_u16_x4;
> + extern const function_base *const svluti6_lane_f16_x4;
> + extern const function_base *const svluti6_lane_bf16_x4;
> extern const function_base *const svmla_za;
> extern const function_base *const svmla_lane_za;
> extern const function_base *const svmls_za;
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
> b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
> index 4c227a71453d..3f3fa616cb50 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
> @@ -973,12 +973,24 @@ public:
> rtx expand (function_expander &e) const override
> {
> auto mode = e.tuple_mode (0);
> + if (m_bits == 6)
> + return e.use_exact_insn (code_for_aarch64_sve_luti6 (mode));
> return e.use_exact_insn (code_for_aarch64_sve_luti (m_bits, mode));
> }
>
> unsigned int m_bits;
> };
>
> +class svluti6_impl : public function_base
> +{
> +public:
> + rtx expand (function_expander &e) const override
> + {
> + auto mode = e.tuple_mode (0);
> + return e.use_exact_insn (code_for_aarch64_sve_luti6_no_lane (mode));
> + }
> +};
> +
> /* The same as cond_or_uncond_unspec_function but the intrinsics with vector
> modes are SME2 extensions instead of SVE. */
> class faminmaximpl : public function_base
> @@ -1319,5 +1331,7 @@ FUNCTION (svzipq1, svzipq_impl, (0))
> FUNCTION (svzipq2, svzipq_impl, (1))
> FUNCTION (svluti2_lane, svluti_lane_impl, (2))
> FUNCTION (svluti4_lane, svluti_lane_impl, (4))
> +FUNCTION (svluti6_lane, svluti_lane_impl, (6))
> +FUNCTION (svluti6, svluti6_impl,)
>
> }
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
> b/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
> index 659231299c1e..509c5512adb9 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
> @@ -370,6 +370,11 @@ DEF_SVE_FUNCTION (svluti4_lane, luti4, bh_data, none)
> DEF_SVE_FUNCTION_GS (svluti4_lane, luti4, h_data, x2, none)
> #undef REQUIRED_EXTENSIONS
>
> +#define REQUIRED_EXTENSIONS sve_and_sme (AARCH64_FL_SVE2p3,
> AARCH64_FL_SME2p3)
> +DEF_SVE_FUNCTION_GS (svluti6, luti6_no_lane, b_data, x2, none)
> +DEF_SVE_FUNCTION_GS (svluti6_lane, luti6, h_data, x2, none)
> +#undef REQUIRED_EXTENSIONS
> +
> #define REQUIRED_EXTENSIONS streaming_only (AARCH64_FL_SME_F16F16)
> DEF_SVE_FUNCTION_GS (svcvt, unary_convertxn, cvt_f32_f16, x2, none)
> DEF_SVE_FUNCTION_GS (svcvtl, unary_convertxn, cvt_f32_f16, x2, none)
> diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.h
> b/gcc/config/aarch64/aarch64-sve-builtins-sve2.h
> index 1a029fc1cff4..85bf30a47b28 100644
> --- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.h
> +++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.h
> @@ -263,6 +263,8 @@ namespace aarch64_acle
> extern const function_base *const svzipq2;
> extern const function_base *const svluti2_lane;
> extern const function_base *const svluti4_lane;
> + extern const function_base *const svluti6;
> + extern const function_base *const svluti6_lane;
> }
> }
>
> diff --git a/gcc/config/aarch64/aarch64-sve2.md
> b/gcc/config/aarch64/aarch64-sve2.md
> index 09f6d40bd3ad..0efa8717d5b4 100644
> --- a/gcc/config/aarch64/aarch64-sve2.md
> +++ b/gcc/config/aarch64/aarch64-sve2.md
> @@ -4698,6 +4698,7 @@
> ;; Includes:
> ;; - LUTI2
> ;; - LUTI4
> +;; - LUTI6 (SVE2p3)
> ;; -------------------------------------------------------------------------
>
> (define_insn "@aarch64_sve_luti<LUTI_BITS><mode>"
> @@ -4726,6 +4727,29 @@
> [(set_attr "sve_type" "sve_int_general")]
> )
>
> +(define_insn "@aarch64_sve_luti6<mode>"
> + [(set (match_operand:<VSINGLE> 0 "register_operand" "=w")
> + (unspec:<VSINGLE>
> + [(match_operand:SVE_FULL_Hx2 1 "register_operand" "w")
> + (match_operand:VNx16QI 2 "register_operand" "w")
> + (match_operand:DI 3 "const_int_operand")]
> + UNSPEC_SVE_LUTI))]
> + "TARGET_SVE2p3_OR_SME2p3"
> + "luti6\t%0.<Vetype>, %1, %2[%3]"
> + [(set_attr "sve_type" "sve_int_general")]
> +)
> +
> +(define_insn "@aarch64_sve_luti6_no_lane<mode>"
> + [(set (match_operand:<VSINGLE> 0 "register_operand" "=w")
> + (unspec:<VSINGLE>
> + [(match_operand:SVE_FULL_BIx2 1 "register_operand" "w")
> + (match_operand:VNx16QI 2 "register_operand" "w")]
> + UNSPEC_SVE_LUTI))]
> + "TARGET_SVE2p3_OR_SME2p3"
> + "luti6\t%0.<Vetype>, %1, %2"
> + [(set_attr "sve_type" "sve_int_general")]
> +)
> +
> ;; =========================================================================
> ;; == Cryptographic extensions
> ;; =========================================================================
> diff --git a/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_lane.c
> b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_lane.c
> new file mode 100644
> index 000000000000..5fe03ba8db3a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_lane.c
> @@ -0,0 +1,183 @@
> +/* { dg-do assemble { target aarch64_asm_sme2p3_ok } } */
> +/* { dg-do compile { target { ! aarch64_asm_sme2p3_ok } } } */
> +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
> +
> +#pragma GCC target "+sme2p3"
> +#define SHARED_ZT0
> +#include "test_sme2_acle.h"
> +
> +/*
> +** luti6_lane_s16_x4_u8_x2_min_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_s16_x4_u8_x2_min_test, svint16x4_t, svint16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_s16_x4_s16_x2_u8_x2 (z16, z22, 0),
> + z0 = svluti6_lane_s16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_s16_x4_u8_x2_max_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_s16_x4_u8_x2_max_test, svint16x4_t, svint16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_s16_x4_s16_x2_u8_x2 (z16, z22, 1),
> + z0 = svluti6_lane_s16_x4 (z16, z22, 1))
> +
> +/*
> +** luti6_lane_u16_x4_u8_x2_min_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_u16_x4_u8_x2_min_test, svuint16x4_t,
> svuint16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_u16_x4_u16_x2_u8_x2 (z16, z22, 0),
> + z0 = svluti6_lane_u16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_u16_x4_u8_x2_max_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_u16_x4_u8_x2_max_test, svuint16x4_t,
> svuint16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_u16_x4_u16_x2_u8_x2 (z16, z22, 1),
> + z0 = svluti6_lane_u16_x4 (z16, z22, 1))
> +
> +/*
> +** luti6_lane_f16_x4_u8_x2_min_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_f16_x4_u8_x2_min_test, svfloat16x4_t,
> svfloat16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_f16_x4_f16_x2_u8_x2 (z16, z22, 0),
> + z0 = svluti6_lane_f16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_f16_x4_u8_x2_max_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_f16_x4_u8_x2_max_test, svfloat16x4_t,
> svfloat16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_f16_x4_f16_x2_u8_x2 (z16, z22, 1),
> + z0 = svluti6_lane_f16_x4 (z16, z22, 1))
> +
> +/*
> +** luti6_lane_bf16_x4_u8_x2_min_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_bf16_x4_u8_x2_min_test, svbfloat16x4_t,
> svbfloat16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_bf16_x4_bf16_x2_u8_x2 (z16, z22, 0),
> + z0 = svluti6_lane_bf16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_bf16_x4_u8_x2_max_test:
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z22 - z23\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_bf16_x4_u8_x2_max_test, svbfloat16x4_t,
> svbfloat16x2_t,
> + svuint8x2_t,
> + z0 = svluti6_lane_bf16_x4_bf16_x2_u8_x2 (z16, z22, 1),
> + z0 = svluti6_lane_bf16_x4 (z16, z22, 1))
> +
> +/*
> +** luti6_lane_s16_x4_u8_x3_min_test:
> +** mov z0\.d, z22\.d
> +** mov z1\.d, z23\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_s16_x4_u8_x3_min_test, svint16x4_t, svint16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_s16_x4_s16_x2_u8_x3 (z16, z22, 0),
> + z0 = svluti6_lane_s16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_s16_x4_u8_x3_max_test:
> +** mov z0\.d, z23\.d
> +** mov z1\.d, z24\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_s16_x4_u8_x3_max_test, svint16x4_t, svint16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_s16_x4_s16_x2_u8_x3 (z16, z22, 1),
> + z0 = svluti6_lane_s16_x4 (z16, z22, 1))
> +
> +/*
> +** luti6_lane_u16_x4_u8_x3_min_test:
> +** mov z0\.d, z22\.d
> +** mov z1\.d, z23\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_u16_x4_u8_x3_min_test, svuint16x4_t,
> svuint16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_u16_x4_u16_x2_u8_x3 (z16, z22, 0),
> + z0 = svluti6_lane_u16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_u16_x4_u8_x3_max_test:
> +** mov z0\.d, z23\.d
> +** mov z1\.d, z24\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_u16_x4_u8_x3_max_test, svuint16x4_t,
> svuint16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_u16_x4_u16_x2_u8_x3 (z16, z22, 1),
> + z0 = svluti6_lane_u16_x4 (z16, z22, 1))
> +
> +/*
> +** luti6_lane_f16_x4_u8_x3_min_test:
> +** mov z0\.d, z22\.d
> +** mov z1\.d, z23\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_f16_x4_u8_x3_min_test, svfloat16x4_t,
> svfloat16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_f16_x4_f16_x2_u8_x3 (z16, z22, 0),
> + z0 = svluti6_lane_f16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_f16_x4_u8_x3_max_test:
> +** mov z0\.d, z23\.d
> +** mov z1\.d, z24\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_f16_x4_u8_x3_max_test, svfloat16x4_t,
> svfloat16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_f16_x4_f16_x2_u8_x3 (z16, z22, 1),
> + z0 = svluti6_lane_f16_x4 (z16, z22, 1))
> +
> +/*
> +** luti6_lane_bf16_x4_u8_x3_min_test:
> +** mov z0\.d, z22\.d
> +** mov z1\.d, z23\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[0\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_bf16_x4_u8_x3_min_test, svbfloat16x4_t,
> svbfloat16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_bf16_x4_bf16_x2_u8_x3 (z16, z22, 0),
> + z0 = svluti6_lane_bf16_x4 (z16, z22, 0))
> +
> +/*
> +** luti6_lane_bf16_x4_u8_x3_max_test:
> +** mov z0\.d, z23\.d
> +** mov z1\.d, z24\.d
> +** luti6 \{z0\.h - z3\.h\}, \{z16\.h - z17\.h\}, \{z0 - z1\}\[1\]
> +** ret
> +*/
> +TEST_1X2_NARROW (luti6_lane_bf16_x4_u8_x3_max_test, svbfloat16x4_t,
> svbfloat16x2_t,
> + svuint8x3_t,
> + z0 = svluti6_lane_bf16_x4_bf16_x2_u8_x3 (z16, z22, 1),
> + z0 = svluti6_lane_bf16_x4 (z16, z22, 1))
> diff --git a/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_zt.c
> b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_zt.c
> new file mode 100644
> index 000000000000..33520a0c817a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/luti6_zt.c
> @@ -0,0 +1,55 @@
> +/* { dg-do assemble { target aarch64_asm_sme2p3_ok } } */
> +/* { dg-do compile { target { ! aarch64_asm_sme2p3_ok } } } */
> +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
> +
> +#pragma GCC target "+sme2p3"
> +#define SHARED_ZT0
> +#include "test_sme2_acle.h"
> +
> +/*
> +** luti6_zt_s8_test:
> +** luti6 z1\.b, zt0, z0
> +** ret
> +*/
> +TEST_XN_SINGLE (luti6_zt_s8_test, svint8_t, svuint8_t, z1,
> + svluti6_zt_s8 (0, z0), svluti6_zt_s8 (0, z0))
> +
> +/*
> +** luti6_zt_u8_test:
> +** luti6 z1\.b, zt0, z0
> +** ret
> +*/
> +TEST_XN_SINGLE (luti6_zt_u8_test, svuint8_t, svuint8_t, z1,
> + svluti6_zt_u8 (0, z0), svluti6_zt_u8 (0, z0))
> +
> +/*
> +** luti6_zt_mf8_test:
> +** luti6 z1\.b, zt0, z0
> +** ret
> +*/
> +TEST_XN_SINGLE (luti6_zt_mf8_test, svmfloat8_t, svuint8_t, z1,
> + svluti6_zt_mf8 (0, z0), svluti6_zt_mf8 (0, z0))
> +
> +/*
> +** luti6_zt_s8_x4_test:
> +** luti6 \{z0\.b - z3\.b\}, zt0, \{z4 - z6\}
> +** ret
> +*/
> +TEST_DUAL_XN (luti6_zt_s8_x4_test, svint8x4_t, svuint8x3_t, z0,
> + svluti6_zt_s8_x4 (0, z4), svluti6_zt_s8_x4 (0, z4))
> +
> +/*
> +** luti6_zt_u8_x4_test:
> +** luti6 \{z0\.b - z3\.b\}, zt0, \{z4 - z6\}
> +** ret
> +*/
> +TEST_DUAL_XN (luti6_zt_u8_x4_test, svuint8x4_t, svuint8x3_t, z0,
> + svluti6_zt_u8_x4 (0, z4), svluti6_zt_u8_x4 (0, z4))
> +
> +/*
> +** luti6_zt_mf8_x4_test:
> +** luti6 \{z0\.b - z3\.b\}, zt0, \{z4 - z6\}
> +** ret
> +*/
> +TEST_DUAL_XN (luti6_zt_mf8_x4_test, svmfloat8x4_t, svuint8x3_t, z0,
> + svluti6_zt_mf8_x4 (0, z4), svluti6_zt_mf8_x4 (0, z4))
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6.c
> b/gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6.c
> new file mode 100644
> index 000000000000..df3736a890e1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6.c
> @@ -0,0 +1,40 @@
> +/* { dg-do assemble { target aarch64_asm_sve2p3_ok } } */
> +/* { dg-do compile { target { ! aarch64_asm_sve2p3_ok } } } */
> +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
> +
> +#pragma GCC target "+sve2p3"
> +#include <arm_sve.h>
> +#include "test_sve_acle.h"
> +#ifdef STREAMING_COMPATIBLE
> +#pragma GCC target "+sme2p3"
> +#endif
> +
> +/*
> +** luti6_s8_x2_test:
> +** luti6 z0\.b, \{z6\.b - z7\.b\}, z22
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_s8_x2_test, svint8_t, svint8x2_t, svuint8_t,
> + z0 = svluti6_s8_x2 (z6, z22),
> + z0 = svluti6 (z6, z22))
> +
> +/*
> +** luti6_u8_x2_test:
> +** luti6 z0\.b, \{z6\.b - z7\.b\}, z22
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_u8_x2_test, svuint8_t, svuint8x2_t, svuint8_t,
> + z0 = svluti6_u8_x2 (z6, z22),
> + z0 = svluti6 (z6, z22))
> +
> +/*
> +** luti6_mf8_x2_test:
> +** luti6 z0\.b, \{z6\.b - z7\.b\}, z22
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_mf8_x2_test, svmfloat8_t, svmfloat8x2_t, svuint8_t,
> + z0 = svluti6_mf8_x2 (z6, z22),
> + z0 = svluti6 (z6, z22))
> diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6_lane.c
> b/gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6_lane.c
> new file mode 100644
> index 000000000000..6891ce054e84
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/asm/luti6_lane.c
> @@ -0,0 +1,60 @@
> +/* { dg-do assemble { target aarch64_asm_sve2p3_ok } } */
> +/* { dg-do compile { target { ! aarch64_asm_sve2p3_ok } } } */
> +/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
> +
> +#pragma GCC target "+sve2p3"
> +#include <arm_sve.h>
> +#include "test_sve_acle.h"
> +#ifdef STREAMING_COMPATIBLE
> +#pragma GCC target "+sme2p3"
> +#endif
> +
> +/*
> +** luti6_s16_x2_min_idx_test:
> +** luti6 z0\.h, \{z6\.h - z7\.h\}, z22\[0\]
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_s16_x2_min_idx_test, svint16_t, svint16x2_t, svuint8_t,
> + z0 = svluti6_lane_s16_x2 (z6, z22, 0),
> + z0 = svluti6_lane (z6, z22, 0))
> +
> +/*
> +** luti6_s16_x2_max_idx_test:
> +** luti6 z0\.h, \{z6\.h - z7\.h\}, z22\[1\]
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_s16_x2_max_idx_test, svint16_t, svint16x2_t, svuint8_t,
> + z0 = svluti6_lane_s16_x2 (z6, z22, 1),
> + z0 = svluti6_lane (z6, z22, 1))
> +
> +/*
> +** luti6_u16_x2_test:
> +** luti6 z0\.h, \{z6\.h - z7\.h\}, z22\[1\]
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_u16_x2_test, svuint16_t, svuint16x2_t, svuint8_t,
> + z0 = svluti6_lane_u16_x2 (z6, z22, 1),
> + z0 = svluti6_lane (z6, z22, 1))
> +
> +/*
> +** luti6_f16_x2_test:
> +** luti6 z0\.h, \{z6\.h - z7\.h\}, z22\[1\]
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_f16_x2_test, svfloat16_t, svfloat16x2_t, svuint8_t,
> + z0 = svluti6_lane_f16_x2 (z6, z22, 1),
> + z0 = svluti6_lane (z6, z22, 1))
> +
> +/*
> +** luti6_bf16_x2_test:
> +** luti6 z0\.h, \{z6\.h - z7\.h\}, z22\[1\]
> +** ret
> +*/
> +
> +TEST_1X2_NARROW(luti6_bf16_x2_test, svbfloat16_t, svbfloat16x2_t, svuint8_t,
> + z0 = svluti6_lane_bf16_x2 (z6, z22, 1),
> + z0 = svluti6_lane (z6, z22, 1))
> --
> 2.53.0
>