[gcc r17-2751] aarch64: Add Support for SVE2p3/SME2p3 dot product intrinsics

Richard Ball via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:2a64a564f5eeb5aa332816459404641fb9cf8f14

commit r17-2751-g2a64a564f5eeb5aa332816459404641fb9cf8f14
Author: Richard Ball <[email protected]>
Date:   Tue Jul 28 14:45:01 2026 +0100

    aarch64: Add Support for SVE2p3/SME2p3 dot product intrinsics
    
    Add support for SVE2p3 and SME2p3 dot product intrinsics
    
    gcc/ChangeLog:
    
            * config/aarch64/aarch64-acle-builtins.h
            (TYPES_s_narrow_su): New type array.
            (s_narrow_su): Likewise.
            * config/aarch64/aarch64-sve-builtins-base.cc
            (class svdot_impl): Update impl.
            (FUNCTION): Likewise.
            * config/aarch64/aarch64-sve-builtins-sve2.def
            (REQUIRED_EXTENSIONS): New function.
            (svdot): Likewise.
            (svdot_lane): Likewise.
            * config/aarch64/aarch64-sve2.md
            (<sur>dot_prodvnx4sivnx8hi): Renamed.
            (@<sur>dot_prod<VNx4SI_ONLY:mode><VNx8HI_ONLY:mode>): New Name.
            (@<sur>dot_prod<VNx8HI_ONLY:mode><VNx16QI_ONLY:mode>): New pattern.
            (@aarch64_<sur>dot_prod_lane<VNx8HI_ONLY:mode><VNx16QI_ONLY:mode>): Likewise.
            * config/aarch64/aarch64.h
            (TARGET_SVE2p3): New Target Flag.
            (TARGET_SME2p3): Likewise.
            (TARGET_STREAMING_SME2p3): Likewise.
            (TARGET_SVE2p3_OR_SME2p3): Likewise.
            * doc/invoke.texi: Add sve2p3/sme2p3.
    
    gcc/testsuite/ChangeLog:
    
            * lib/target-supports.exp: New check_effective_targets.
            * gcc.target/aarch64/sme2/acle-asm/dot_lane_s16.c: New test.
            * gcc.target/aarch64/sme2/acle-asm/dot_lane_u16.c: New test.
            * gcc.target/aarch64/sme2/acle-asm/dot_s16.c: New test.
            * gcc.target/aarch64/sme2/acle-asm/dot_u16.c: New test.
            * gcc.target/aarch64/sve2/dotproduct_intrinsicless.c: New test.

Diff:
---
 gcc/config/aarch64/aarch64-acle-builtins.h         |  6 ++
 gcc/config/aarch64/aarch64-sve-builtins-base.cc    | 13 +--
 gcc/config/aarch64/aarch64-sve-builtins-sve2.def   |  5 ++
 gcc/config/aarch64/aarch64-sve2.md                 | 49 +++++++++--
 gcc/config/aarch64/aarch64.h                       | 10 +++
 gcc/doc/invoke.texi                                |  6 ++
 .../aarch64/sme2/acle-asm/dot_lane_s16.c           | 96 ++++++++++++++++++++++
 .../aarch64/sme2/acle-asm/dot_lane_u16.c           | 96 ++++++++++++++++++++++
 .../gcc.target/aarch64/sme2/acle-asm/dot_s16.c     | 47 +++++++++++
 .../gcc.target/aarch64/sme2/acle-asm/dot_u16.c     | 47 +++++++++++
 .../aarch64/sve2/dotproduct_intrinsicless.c        | 30 +++++++
 gcc/testsuite/lib/target-supports.exp              | 28 +++++++
 12 files changed, 421 insertions(+), 12 deletions(-)

diff --git a/gcc/config/aarch64/aarch64-acle-builtins.h b/gcc/config/aarch64/aarch64-acle-builtins.h
index d330ac7897a7..bf495bd74a0d 100644
--- a/gcc/config/aarch64/aarch64-acle-builtins.h
+++ b/gcc/config/aarch64/aarch64-acle-builtins.h
@@ -1646,6 +1646,11 @@ function_expander::result_mode () const
 #define TYPES_s_narrow_fsu(S, D, T) \
   D (f32, f16), D (s32, s16), D (u32, u16)
 
+/* _s16_s8
+   _u16_u8.  */
+#define TYPES_s_narrow_su(S, D, T) \
+  D (s16, s8), D (u16, u8)
+
 /* _za8 _za16 _za32 _za64 _za128.  */
 #define TYPES_all_za(S, D, T) \
   S (za8), S (za16), S (za32), S (za64), S (za128)
@@ -2025,6 +2030,7 @@ DEF_SVE_TYPES_ARRAY (while);
 DEF_SVE_TYPES_ARRAY (while_x);
 DEF_SVE_TYPES_ARRAY (while_x_c);
 DEF_SVE_TYPES_ARRAY (s_narrow_fsu);
+DEF_SVE_TYPES_ARRAY (s_narrow_su);
 DEF_SVE_TYPES_ARRAY (all_za);
 DEF_SVE_TYPES_ARRAY (d_za);
 DEF_SVE_TYPES_ARRAY (za_bhsd_data);
diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
index e841972cb422..7f047bb64686 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
@@ -938,13 +938,17 @@ public:
 };
 
 
-class svdot_impl : public function_base
+class svdot_impl : public unspec_based_function_base
 {
 public:
+  using unspec_based_function_base::unspec_based_function_base;
+
   rtx
   expand (function_expander &e) const override
   {
     insn_code icode;
+    machine_mode mode0 = GET_MODE (e.args[0]);
+    machine_mode mode1 = GET_MODE (e.args[1]);
     if (e.fpm_mode == aarch64_acle::FPM_set)
       icode = code_for_aarch64_sve_dot (e.result_mode ());
     else
@@ -952,6 +956,7 @@ public:
 	/* In the optab, the multiplication operands come before the accumulator
 	   operand.  The optab is keyed off the multiplication mode.  */
 	e.rotate_inputs_left (0, 3);
+	int unspec = unspec_for (e);
 	if (e.type_suffix_ids[1] == NUM_TYPE_SUFFIXES)
 	  icode = e.convert_optab_handler_for_sign (sdot_prod_optab,
 						    udot_prod_optab,
@@ -960,9 +965,7 @@ public:
 	else
 	  icode = (e.type_suffix (0).float_p
 		   ? CODE_FOR_aarch64_sve_fdotvnx4sfvnx8hf
-		   : e.type_suffix (0).unsigned_p
-		   ? CODE_FOR_udot_prodvnx4sivnx8hi
-		   : CODE_FOR_sdot_prodvnx4sivnx8hi);
+		   : code_for_dot_prod (unspec, mode0, mode1));
       }
     return e.use_unpred_insn (icode);
   }
@@ -3617,7 +3620,7 @@ FUNCTION (svcvt, svcvt_impl,)
 FUNCTION (svcvtnt, NARROWING_TOP_CONVERT0 (aarch64_sve_cvtnt),)
 FUNCTION (svdiv, svdiv_impl,)
 FUNCTION (svdivr, rtx_code_function_rotated, (DIV, UDIV, UNSPEC_COND_FDIV))
-FUNCTION (svdot, svdot_impl,)
+FUNCTION (svdot, svdot_impl,(UNSPEC_SDOT, UNSPEC_UDOT, UNSPEC_FDOT))
 FUNCTION (svdot_lane, svdotprod_lane_impl, (UNSPEC_SDOT, UNSPEC_UDOT,
 					    UNSPEC_FDOT, UNSPEC_DOT_LANE_FP8))
 FUNCTION (svdup, svdup_impl,)
diff --git a/gcc/config/aarch64/aarch64-sve-builtins-sve2.def b/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
index 16524cfedab0..62474935b49c 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
+++ b/gcc/config/aarch64/aarch64-sve-builtins-sve2.def
@@ -465,6 +465,11 @@ DEF_SVE_FUNCTION_GS_FPM (svmmla, mmla, h_float_mf8, none, none, set)
 DEF_SVE_FUNCTION_GS_FPM (svmmla, mmla, s_float_mf8, none, none, set)
 #undef REQUIRED_EXTENSIONS
 
+#define REQUIRED_EXTENSIONS sve_and_sme (AARCH64_FL_SVE2p3, AARCH64_FL_SME2p3)
+DEF_SVE_FUNCTION (svdot, ternary_qq_opt_n_or_011, s_narrow_su, none)
+DEF_SVE_FUNCTION (svdot_lane, ternary_qq_or_011_lane, s_narrow_su, none)
+#undef REQUIRED_EXTENSIONS
+
 #define REQUIRED_EXTENSIONS nonstreaming_sve (AARCH64_FL_SVE_F16F32MM)
 DEF_SVE_FUNCTION (svmmla, mmla, cvt_f32_f16, none)
 #undef REQUIRED_EXTENSIONS
diff --git a/gcc/config/aarch64/aarch64-sve2.md b/gcc/config/aarch64/aarch64-sve2.md
index 860c63460eb9..873d47368294 100644
--- a/gcc/config/aarch64/aarch64-sve2.md
+++ b/gcc/config/aarch64/aarch64-sve2.md
@@ -2862,14 +2862,14 @@
 )
 
 ;; Two-way dot-product.
-(define_insn "<sur>dot_prodvnx4sivnx8hi"
-  [(set (match_operand:VNx4SI 0 "register_operand")
-	(plus:VNx4SI
-	  (unspec:VNx4SI
-	    [(match_operand:VNx8HI 1 "register_operand")
-	     (match_operand:VNx8HI 2 "register_operand")]
+(define_insn "@<sur>dot_prod<VNx4SI_ONLY:mode><VNx8HI_ONLY:mode>"
+  [(set (match_operand:VNx4SI_ONLY 0 "register_operand")
+	(plus:VNx4SI_ONLY
+	  (unspec:VNx4SI_ONLY
+	    [(match_operand:VNx8HI_ONLY 1 "register_operand")
+	     (match_operand:VNx8HI_ONLY 2 "register_operand")]
 	    DOTPROD)
-	  (match_operand:VNx4SI 3 "register_operand")))]
+	  (match_operand:VNx4SI_ONLY 3 "register_operand")))]
   "TARGET_SVE2p1_OR_SME2"
   {@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
      [ w        , w , w , 0 ; *              ] <sur>dot\t%0.s, %1.h, %2.h
@@ -2878,6 +2878,41 @@
   [(set_attr "sve_type" "sve_int_dot")]
 )
 
+;; Two-way dot-product SME2p3 || SVE2p3.
+(define_insn "@<sur>dot_prod<VNx8HI_ONLY:mode><VNx16QI_ONLY:mode>"
+  [(set (match_operand:VNx8HI_ONLY 0 "register_operand")
+	(plus:VNx8HI_ONLY
+	  (unspec:VNx8HI_ONLY
+	    [(match_operand:VNx16QI_ONLY 1 "register_operand")
+	     (match_operand:VNx16QI_ONLY 2 "register_operand")]
+	    DOTPROD)
+	  (match_operand:VNx8HI_ONLY 3 "register_operand")))]
+  "TARGET_SVE2p3_OR_SME2p3"
+  {@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
+     [ w        , w , w , 0 ; *              ] <sur>dot\t%0.h, %1.b, %2.b
+     [ ?&w      , w , w , w ; yes            ] movprfx\t%0, %3\;<sur>dot\t%0.h, %1.b, %2.b
+  }
+  [(set_attr "sve_type" "sve_int_dot")]
+)
+
+(define_insn "@aarch64_<sur>dot_prod_lane<VNx8HI_ONLY:mode><VNx16QI_ONLY:mode>"
+  [(set (match_operand:VNx8HI_ONLY 0 "register_operand")
+	(plus:VNx8HI_ONLY
+	  (unspec:VNx8HI_ONLY
+	    [(match_operand:VNx16QI_ONLY 1 "register_operand")
+	     (unspec:VNx16QI_ONLY
+	       [(match_operand:VNx16QI_ONLY 2 "register_operand")
+		(match_operand:SI 3 "const_int_operand")]
+	       UNSPEC_SVE_LANE_SELECT)]
+	    DOTPROD)
+	  (match_operand:VNx8HI_ONLY 4 "register_operand")))]
+  "TARGET_SVE2p3_OR_SME2p3"
+  {@ [ cons: =0 , 1 , 2 , 4 ; attrs: movprfx ]
+     [ w        , w , y , 0 ; *              ] <sur>dot\t%0.h, %1.b, %2.b[%3]
+     [ ?&w      , w , y , w ; yes            ] movprfx\t%0, %4\;<sur>dot\t%0.h, %1.b, %2.b[%3]
+  }
+  [(set_attr "sve_type" "sve_fp_mul")]
+)
 ;; -------------------------------------------------------------------------
 ;; ---- [FP] Multi-register operations
 ;; -------------------------------------------------------------------------
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 26db4958a80f..752f74386c6e 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -318,6 +318,9 @@ constexpr auto AARCH64_FL_DEFAULT_ISA_MODE ATTRIBUTE_UNUSED
 /* SVE2p2 instructions, enabled through +sve2p2.  */
 #define TARGET_SVE2p2 AARCH64_HAVE_ISA (SVE2p2)
 
+/* SVE2p3 instructions, enabled through +sve2p3.  */
+#define TARGET_SVE2p3 AARCH64_HAVE_ISA (SVE2p3)
+
 /* SME instructions, enabled through +sme.  Note that this does not
    imply anything about the state of PSTATE.SM; instructions that require
    SME and streaming mode should use TARGET_STREAMING instead.  */
@@ -351,6 +354,9 @@ constexpr auto AARCH64_FL_DEFAULT_ISA_MODE ATTRIBUTE_UNUSED
 /* SME2p2 instructions, enabled through +sme2p2.  */
 #define TARGET_SME2p2 AARCH64_HAVE_ISA (SME2p2)
 
+/* SME2p3 instructions, enabled through +sme2p3.  */
+#define TARGET_SME2p3 AARCH64_HAVE_ISA (SME2p3)
+
 /* Same with streaming mode enabled.  */
 #define TARGET_STREAMING_SME2 (TARGET_STREAMING && TARGET_SME2)
 
@@ -358,6 +364,8 @@ constexpr auto AARCH64_FL_DEFAULT_ISA_MODE ATTRIBUTE_UNUSED
 
 #define TARGET_STREAMING_SME2p2 (TARGET_STREAMING && AARCH64_HAVE_ISA (SME2p2))
 
+#define TARGET_STREAMING_SME2p3 (TARGET_STREAMING && AARCH64_HAVE_ISA (SME2p3))
+
 #define TARGET_SME_B16B16 AARCH64_HAVE_ISA (SME_B16B16)
 
 /* ARMv8.3-A features.  */
@@ -532,6 +540,8 @@ constexpr auto AARCH64_FL_DEFAULT_ISA_MODE ATTRIBUTE_UNUSED
    functions, since streaming mode itself implies SME.  */
 #define TARGET_SVE2p1_OR_SME (TARGET_SVE2p1 || TARGET_STREAMING)
 
+#define TARGET_SVE2p3_OR_SME2p3 (TARGET_SVE2p3 || TARGET_SME2p3)
+
 #define TARGET_SVE2p1_OR_SME2 \
   ((TARGET_SVE2p1 || TARGET_STREAMING) \
    && (TARGET_SME2 || TARGET_NON_STREAMING))
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5be3851a9296..322d0a726b9c 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -21997,6 +21997,9 @@ Enable SVE2 sha3 instructions.  This also enables SVE2 instructions.
 Enable SVE2.1 instructions.  This also enables SVE2 instructions.
 @item sve2p2
 Enable SVE2.2 instructions.  This also enables SVE2 and SVE2.1 instructions.
+@item sve2p3
+Enable SVE2.3 instructions.  This also enables SVE2 and SVE2.1 and
+SVE2.2 instructions.
 @item i8mm
 Enable 8-bit Integer Matrix Multiply instructions.  This also enables
 Advanced SIMD and floating-point instructions.  This option is enabled by
@@ -22060,6 +22063,9 @@ instructions.
 @item sme2p2
 Enable the Scalable Matrix Extension version 2.2.  This also enables SME2
 and SME2.1 instructions.
+@item sme2p3
+Enable the Scalable Matrix Extension version 2.3.  This also enables SME2,
+SME2.1 and SME2.2 instructions.
 @item fcma
 Enable the complex number SIMD extensions.
 @item jscvt
diff --git a/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_lane_s16.c b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_lane_s16.c
new file mode 100644
index 000000000000..8e5d10339294
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_lane_s16.c
@@ -0,0 +1,96 @@
+/* { dg-do assemble { target aarch64_asm_sme2p3_ok } } */
+/* { dg-do compile { target { ! aarch64_asm_sme2p3_ok } } } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sme2_acle.h"
+#pragma GCC target "+sme2p3"
+
+/*
+** dot_lane_0_s16_tied1:
+**	sdot	z0\.h, z4\.b, z5\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_0_s16_tied1, svint16_t, svint8_t,
+	     z0 = svdot_lane_s16_s8 (z0, z4, z5, 0),
+	     z0 = svdot_lane (z0, z4, z5, 0))
+
+/*
+** dot_lane_0_s16_tied2:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	sdot	z0\.h, \1\.b, z1\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_lane_0_s16_tied2, svint16_t, svint8_t,
+		 z0_res = svdot_lane_s16_s8 (z4, z0, z1, 0),
+		 z0_res = svdot_lane (z4, z0, z1, 0))
+
+/*
+** dot_lane_0_s16_tied3:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	sdot	z0\.h, z1\.b, \1\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_lane_0_s16_tied3, svint16_t, svint8_t,
+		 z0_res = svdot_lane_s16_s8 (z4, z1, z0, 0),
+		 z0_res = svdot_lane (z4, z1, z0, 0))
+
+/*
+** dot_lane_0_s16_untied:
+**	movprfx	z0, z1
+**	sdot	z0\.h, z4\.b, z5\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_0_s16_untied, svint16_t, svint8_t,
+	     z0 = svdot_lane_s16_s8 (z1, z4, z5, 0),
+	     z0 = svdot_lane (z1, z4, z5, 0))
+
+/*
+** dot_lane_1_s16:
+**	sdot	z0\.h, z4\.b, z5\.b\[1\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_1_s16, svint16_t, svint8_t,
+	     z0 = svdot_lane_s16_s8 (z0, z4, z5, 1),
+	     z0 = svdot_lane (z0, z4, z5, 1))
+
+/*
+** dot_lane_2_s16:
+**	sdot	z0\.h, z4\.b, z5\.b\[2\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_2_s16, svint16_t, svint8_t,
+	     z0 = svdot_lane_s16_s8 (z0, z4, z5, 2),
+	     z0 = svdot_lane (z0, z4, z5, 2))
+
+/*
+** dot_lane_3_s16:
+**	sdot	z0\.h, z4\.b, z5\.b\[3\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_3_s16, svint16_t, svint8_t,
+	     z0 = svdot_lane_s16_s8 (z0, z4, z5, 3),
+	     z0 = svdot_lane (z0, z4, z5, 3))
+
+/*
+** dot_lane_z8_s16:
+**	str	d8, \[sp, -16\]!
+**	mov	(z[0-7])\.d, z8\.d
+**	sdot	z0\.h, z1\.b, \1\.b\[1\]
+**	ldr	d8, \[sp\], 16
+**	ret
+*/
+TEST_DUAL_LANE_REG (dot_lane_z8_s16, svint16_t, svint8_t, z8,
+		    z0 = svdot_lane_s16_s8 (z0, z1, z8, 1),
+		    z0 = svdot_lane (z0, z1, z8, 1))
+
+/*
+** dot_lane_z16_s16:
+**	mov	(z[0-7])\.d, z16\.d
+**	sdot	z0\.h, z1\.b, \1\.b\[1\]
+**	ret
+*/
+TEST_DUAL_LANE_REG (dot_lane_z16_s16, svint16_t, svint8_t, z16,
+		    z0 = svdot_lane_s16_s8 (z0, z1, z16, 1),
+		    z0 = svdot_lane (z0, z1, z16, 1))
diff --git a/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_lane_u16.c b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_lane_u16.c
new file mode 100644
index 000000000000..8ad5dbb81156
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_lane_u16.c
@@ -0,0 +1,96 @@
+/* { dg-do assemble { target aarch64_asm_sme2p3_ok } } */
+/* { dg-do compile { target { ! aarch64_asm_sme2p3_ok } } } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sme2_acle.h"
+#pragma GCC target "+sme2p3"
+
+/*
+** dot_lane_0_u16_tied1:
+**	udot	z0\.h, z4\.b, z5\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_0_u16_tied1, svuint16_t, svuint8_t,
+	     z0 = svdot_lane_u16_u8 (z0, z4, z5, 0),
+	     z0 = svdot_lane (z0, z4, z5, 0))
+
+/*
+** dot_lane_0_u16_tied2:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	udot	z0\.h, \1\.b, z1\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_lane_0_u16_tied2, svuint16_t, svuint8_t,
+		 z0_res = svdot_lane_u16_u8 (z4, z0, z1, 0),
+		 z0_res = svdot_lane (z4, z0, z1, 0))
+
+/*
+** dot_lane_0_u16_tied3:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	udot	z0\.h, z1\.b, \1\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_lane_0_u16_tied3, svuint16_t, svuint8_t,
+		 z0_res = svdot_lane_u16_u8 (z4, z1, z0, 0),
+		 z0_res = svdot_lane (z4, z1, z0, 0))
+
+/*
+** dot_lane_0_u16_untied:
+**	movprfx	z0, z1
+**	udot	z0\.h, z4\.b, z5\.b\[0\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_0_u16_untied, svuint16_t, svuint8_t,
+	     z0 = svdot_lane_u16_u8 (z1, z4, z5, 0),
+	     z0 = svdot_lane (z1, z4, z5, 0))
+
+/*
+** dot_lane_1_u16:
+**	udot	z0\.h, z4\.b, z5\.b\[1\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_1_u16, svuint16_t, svuint8_t,
+	     z0 = svdot_lane_u16_u8 (z0, z4, z5, 1),
+	     z0 = svdot_lane (z0, z4, z5, 1))
+
+/*
+** dot_lane_2_u16:
+**	udot	z0\.h, z4\.b, z5\.b\[2\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_2_u16, svuint16_t, svuint8_t,
+	     z0 = svdot_lane_u16_u8 (z0, z4, z5, 2),
+	     z0 = svdot_lane (z0, z4, z5, 2))
+
+/*
+** dot_lane_3_u16:
+**	udot	z0\.h, z4\.b, z5\.b\[3\]
+**	ret
+*/
+TEST_DUAL_Z (dot_lane_3_u16, svuint16_t, svuint8_t,
+	     z0 = svdot_lane_u16_u8 (z0, z4, z5, 3),
+	     z0 = svdot_lane (z0, z4, z5, 3))
+
+/*
+** dot_lane_z8_u16:
+**	str	d8, \[sp, -16\]!
+**	mov	(z[0-7])\.d, z8\.d
+**	udot	z0\.h, z1\.b, \1\.b\[1\]
+**	ldr	d8, \[sp\], 16
+**	ret
+*/
+TEST_DUAL_LANE_REG (dot_lane_z8_u16, svuint16_t, svuint8_t, z8,
+		    z0 = svdot_lane_u16_u8 (z0, z1, z8, 1),
+		    z0 = svdot_lane (z0, z1, z8, 1))
+
+/*
+** dot_lane_z16_u16:
+**	mov	(z[0-7])\.d, z16\.d
+**	udot	z0\.h, z1\.b, \1\.b\[1\]
+**	ret
+*/
+TEST_DUAL_LANE_REG (dot_lane_z16_u16, svuint16_t, svuint8_t, z16,
+		    z0 = svdot_lane_u16_u8 (z0, z1, z16, 1),
+		    z0 = svdot_lane (z0, z1, z16, 1))
diff --git a/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_s16.c b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_s16.c
new file mode 100644
index 000000000000..be9883660939
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_s16.c
@@ -0,0 +1,47 @@
+/* { dg-do assemble { target aarch64_asm_sme2p3_ok } } */
+/* { dg-do compile { target { ! aarch64_asm_sme2p3_ok } } } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sme2_acle.h"
+#pragma GCC target "+sme2p3"
+
+/*
+** dot_s16_tied1:
+**	sdot	z0\.h, z4\.b, z5\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_s16_tied1, svint16_t, svint8_t,
+	     z0 = svdot_s16_s8 (z0, z4, z5),
+	     z0 = svdot (z0, z4, z5))
+
+/*
+** dot_s16_tied2:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	sdot	z0\.h, \1\.b, z1\.b
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_s16_tied2, svint16_t, svint8_t,
+		 z0_res = svdot_s16_s8 (z4, z0, z1),
+		 z0_res = svdot (z4, z0, z1))
+
+/*
+** dot_s16_tied3:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	sdot	z0\.h, z1\.b, \1\.b
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_s16_tied3, svint16_t, svint8_t,
+		 z0_res = svdot_s16_s8 (z4, z1, z0),
+		 z0_res = svdot (z4, z1, z0))
+
+/*
+** dot_s16_untied:
+**	movprfx	z0, z1
+**	sdot	z0\.h, z4\.b, z5\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_s16_untied, svint16_t, svint8_t,
+	     z0 = svdot_s16_s8 (z1, z4, z5),
+	     z0 = svdot (z1, z4, z5))
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_u16.c b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_u16.c
new file mode 100644
index 000000000000..c4168495a698
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sme2/acle-asm/dot_u16.c
@@ -0,0 +1,47 @@
+/* { dg-do assemble { target aarch64_asm_sme2p3_ok } } */
+/* { dg-do compile { target { ! aarch64_asm_sme2p3_ok } } } */
+/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */
+
+#include "test_sme2_acle.h"
+#pragma GCC target "+sme2p3"
+
+/*
+** dot_u16_tied1:
+**	udot	z0\.h, z4\.b, z5\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_u16_tied1, svuint16_t, svuint8_t,
+	     z0 = svdot_u16_u8 (z0, z4, z5),
+	     z0 = svdot (z0, z4, z5))
+
+/*
+** dot_u16_tied2:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	udot	z0\.h, \1\.b, z1\.b
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_u16_tied2, svuint16_t, svuint8_t,
+		 z0_res = svdot_u16_u8 (z4, z0, z1),
+		 z0_res = svdot (z4, z0, z1))
+
+/*
+** dot_u16_tied3:
+**	mov	(z[0-9]+)\.d, z0\.d
+**	movprfx	z0, z4
+**	udot	z0\.h, z1\.b, \1\.b
+**	ret
+*/
+TEST_DUAL_Z_REV (dot_u16_tied3, svuint16_t, svuint8_t,
+		 z0_res = svdot_u16_u8 (z4, z1, z0),
+		 z0_res = svdot (z4, z1, z0))
+
+/*
+** dot_u16_untied:
+**	movprfx	z0, z1
+**	udot	z0\.h, z4\.b, z5\.b
+**	ret
+*/
+TEST_DUAL_Z (dot_u16_untied, svuint16_t, svuint8_t,
+	     z0 = svdot_u16_u8 (z1, z4, z5),
+	     z0 = svdot (z1, z4, z5))
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/dotproduct_intrinsicless.c b/gcc/testsuite/gcc.target/aarch64/sve2/dotproduct_intrinsicless.c
new file mode 100644
index 000000000000..82e2c2596b63
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve2/dotproduct_intrinsicless.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=armv9-a+sve2p3 -mautovec-preference=sve-only --param=aarch64-vect-unroll-limit=1" } */
+
+#include <stdint.h>
+#include <stddef.h>
+int16_t dot_s8_s8_to_s16(const int8_t *restrict a,
+                          const int8_t *restrict b,
+                          unsigned n) {
+  int16_t acc = 0;
+
+
+  for (unsigned i = 0; i < n; ++i)
+    acc += (int16_t)a[i] * (int16_t)b[i];
+
+  return acc;
+}
+
+uint16_t dot_u8_u8_to_u16(const uint8_t *restrict a,
+                          const uint8_t *restrict b,
+                          unsigned n) {
+  uint16_t acc = 0;
+
+  for (unsigned i = 0; i < n; ++i)
+    acc += (uint16_t)a[i] * (uint16_t)b[i];
+
+  return acc;
+}
+
+/* { dg-final { scan-assembler-times {\tsdot\tz[0-9]+.h, z[0-9]+\.b, z[0-9]+\.b} 1 } } */
+/* { dg-final { scan-assembler-times {\tudot\tz[0-9]+.h, z[0-9]+\.b, z[0-9]+\.b} 1 } } */
\ No newline at end of file
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index ab6aab6f935d..c22033c47b8d 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -6815,6 +6815,23 @@ proc check_effective_target_aarch64_sve2p2_hw { } {
     }]
 }
 
+# Return true if this is an AArch64 target that can run SVE2.3 code.
+
+proc check_effective_target_aarch64_sve2p3_hw { } {
+    if { ![istarget aarch64*-*-*] } {
+	return 0
+    }
+    return [check_runtime aarch64_sve2p3_hw_available {
+	#pragma GCC target "+sve2p3"
+	int
+	main (void)
+	{
+	  asm volatile ("sdot z0.h,z0.b,z1.b");
+	  return 0;
+	}
+    }]
+}
+
 # Return true if this is an AArch64 target that can run SVE code and
 # if its SVE vectors have exactly BITS bits.
 
@@ -12991,6 +13008,7 @@ set exts {
     "sve-sha3" "f8f16mm" "f8f32mm" "sve-f16f32mm"
     "sme-f8f16" "sme-f8f32"
     "sme-b16b16" "sme-f16f16" "sme-i16i64" "sme" "sme2" "sme2p1" "sme2p2"
+    "sme2p3"
     "ssve-fp8dot2" "ssve-fp8dot4" "ssve-fp8fma" "sve-bfscale" "sme-lutv2"
     "ssve-fexpa" "ssve-bitperm" "ssve-aes"
 }
@@ -13039,6 +13057,16 @@ proc check_effective_target_aarch64_asm_sve2p2_ok { } {
     }
 }
 
+proc check_effective_target_aarch64_asm_sve2p3_ok { } {
+    if { [istarget aarch64*-*-*] } {
+	return [check_no_compiler_messages aarch64_sve2p3_assembler object {
+	    __asm__ (".arch_extension sve2p3; sdot z0.h,z0.b,z1.b");
+	} "-march=armv8-a+sve2p3"]
+    } else {
+	return 0
+    }
+}
+
 proc check_effective_target_aarch64_small { } {
     if { [istarget aarch64*-*-*] } {
 	return [check_no_compiler_messages aarch64_small object {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.