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.

The SME svluti6_lane forms need custom name construction because they include
both the table tuple suffix and the index tuple suffix which the existing
suffix machinery cannot represent directly.

gcc/ChangeLog:
        * 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-sve-builtins.cc
        (TYPES_h_unsigned): New data type.
        (TYPES_h_signed): Likewise.
        (b_data): Likewise.
        (groups_x23): New group suffix.
        (function_builder::get_name): Add case for svluti6_lane names.
        * 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.
---

Here 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-sve-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/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       |  59 ++++-
 .../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-sve-builtins.cc    |  25 +++
 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 +++++
 15 files changed, 743 insertions(+), 2 deletions(-)
 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-sme.md 
b/gcc/config/aarch64/aarch64-sme.md
index 7f1c3abbc51..91a4dfb54a5 100644
--- a/gcc/config/aarch64/aarch64-sme.md
+++ b/gcc/config/aarch64/aarch64-sme.md
@@ -3021,6 +3021,7 @@
 ;; Includes:
 ;; - LUTI2 (SME2)
 ;; - LUTI4 (SME2)
+;; - LUTI6 (SME2p3)
 ;; -------------------------------------------------------------------------
 
 (define_c_enum "unspec" [
@@ -3069,3 +3070,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")
+       (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 d5409f2e8ba..334ed8007c3 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
@@ -212,6 +214,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)
@@ -303,6 +307,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);
@@ -983,13 +1005,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)
 
@@ -1032,6 +1086,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 343c267a1cd..5735bf1890a 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-shapes.h
+++ b/gcc/config/aarch64/aarch64-sve-builtins-shapes.h
@@ -169,9 +169,14 @@ namespace aarch64_sve
     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 bc1f4d14f39..b5d36dde27f 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-sme.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-sme.cc
@@ -376,6 +376,58 @@ 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_sve::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
 {
@@ -468,7 +520,7 @@ public:
   unspec_for (const function_instance &instance) const
   {
     if (instance.fpm_mode == FPM_set)
-      return UNSPEC_SME_FTMOPA_FP8;                         
+      return UNSPEC_SME_FTMOPA_FP8;
     auto &suffix1 = instance.type_suffix (1);
     if (!suffix1.integer_p)
       return UNSPEC_SME_FTMOPA;
@@ -674,6 +726,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 bb5b7ebe7c9..0493125ded1 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 69b145a6027..99b68be34ed 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_sve
     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 c8eedf3e723..a20ec5d5385 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.cc
@@ -1018,12 +1018,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
@@ -1380,5 +1392,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,)
 
 } /* end namespace aarch64_sve */
diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.def 
b/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
index 0ae0d274b03..5c348bbb1d8 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
+++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
@@ -382,6 +382,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 bcd4904c3b9..7fdac69be37 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.h
+++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.h
@@ -275,6 +275,8 @@ namespace aarch64_sve
     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-sve-builtins.cc 
b/gcc/config/aarch64/aarch64-sve-builtins.cc
index 34ad120ab4e..11114023070 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins.cc
@@ -311,6 +311,14 @@ CONSTEXPR const group_suffix_info group_suffixes[] = {
 #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) \
@@ -919,6 +927,7 @@ DEF_SVE_TYPES_ARRAY (all_integer);
 DEF_SVE_TYPES_ARRAY (all_arith);
 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);
@@ -934,6 +943,8 @@ DEF_SVE_TYPES_ARRAY (h_bfloat);
 DEF_SVE_TYPES_ARRAY (h_float);
 DEF_SVE_TYPES_ARRAY (h_float_mf8);
 DEF_SVE_TYPES_ARRAY (h_integer);
+DEF_SVE_TYPES_ARRAY (h_unsigned);
+DEF_SVE_TYPES_ARRAY (h_signed);
 DEF_SVE_TYPES_ARRAY (h_data);
 DEF_SVE_TYPES_ARRAY (hs_signed);
 DEF_SVE_TYPES_ARRAY (hs_integer);
@@ -1044,6 +1055,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
 };
@@ -1543,6 +1558,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-sve2.md 
b/gcc/config/aarch64/aarch64-sve2.md
index 55597db973d..a0713633e28 100644
--- a/gcc/config/aarch64/aarch64-sve2.md
+++ b/gcc/config/aarch64/aarch64-sve2.md
@@ -4840,6 +4840,7 @@
 ;; Includes:
 ;; - LUTI2
 ;; - LUTI4
+;; - LUTI6 (SVE2p3)
 ;; -------------------------------------------------------------------------
 
 (define_insn "@aarch64_sve_luti<LUTI_BITS><mode>"
@@ -4868,6 +4869,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 00000000000..97dc1e9e2a8
--- /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 00000000000..fb012f62f83
--- /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 00000000000..df3736a890e
--- /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 00000000000..6891ce054e8
--- /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

Reply via email to