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")
+ (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