[PATCH v5] aarch64: Optimize memcpy for Kunpeng 950 processor

Weihong Ye yeweihong@huawei.com
Sat Jan 31 12:49:04 GMT 2026


For copies ≤64 bytes, the implementation remains consistent with memcpy_sve.
For 65–128 bytes, it removes the 96-byte branch and reorders instructions, improving performance by 18–32%.
For >128 bytes, it aligns the destination to a 32-byte boundary and uses Pre-indexed load/store instructions to reduce address-update overhead.

All benchmarks report execution time (lower is better). Geomean results
    (__memcpy_generic → this patch):
    - bench-memcpy:      16.74 → 12.11  (28% faster)
    - bench-memcpy-large: 24287 → 23302  (4% faster)
    - bench-memcpy-random: 107693 → 72153 (33% faster)
---
Hi Wilco,
Thanks for the review!
In response to your comments:
> Also do you intend to use DCO for this patch? If so, please use Signed-off-by like in v1 and add "Copyright The GNU Toolchain Authors." to patched files that don't already have it:
> sysdeps/unix/sysv/linux/aarch64/cpu-features.c
> sysdeps/aarch64/multiarch/memcpy_kunpeng950.S
> Or alternatively post from an email that has copyright assignment with FSF - it's up to you which you prefer.

I’ve switched from my personal QQ email (used in v1~v4) to my Huawei corporate email for this v5 submission.
Huawei has a valid copyright assignment agreement with the FSF, and I’m contributing this patch under that agreement.

> Are these registers an artifact from v1, or is it deliberate to avoid using E,F,G,H
> in the tail code? If it makes no difference, we don't need the above defines.

You’re right — those #defines (I_q through P_q) were redundant and have been removed in v5.

The patch also now includes an explicit assumption comment at the top:
/* Assumptions:
 *
 * ARMv8.2-a, AArch64, Advanced SIMD, SVE, unaligned accesses
 *
 */

Best regards,
Weihong

 sysdeps/aarch64/cpu-features.h                |   3 +
 sysdeps/aarch64/multiarch/Makefile            |   1 +
 sysdeps/aarch64/multiarch/ifunc-impl-list.c   |   1 +
 sysdeps/aarch64/multiarch/memcpy.c            |   4 +
 sysdeps/aarch64/multiarch/memcpy_kunpeng950.S | 115 ++++++++++++++++++
 .../unix/sysv/linux/aarch64/cpu-features.c    |   1 +
 6 files changed, 125 insertions(+)
 create mode 100644 sysdeps/aarch64/multiarch/memcpy_kunpeng950.S

diff --git a/sysdeps/aarch64/cpu-features.h b/sysdeps/aarch64/cpu-features.h
index ee139b0bf3..1fe35d986b 100644
--- a/sysdeps/aarch64/cpu-features.h
+++ b/sysdeps/aarch64/cpu-features.h
@@ -46,6 +46,9 @@
 #define IS_KUNPENG920(midr) (MIDR_IMPLEMENTOR(midr) == 'H'			   \
                         && MIDR_PARTNUM(midr) == 0xd01)
 
+#define IS_KUNPENG950(midr) (MIDR_IMPLEMENTOR(midr) == 'H'			   \
+                        && MIDR_PARTNUM(midr) == 0xd06)
+
 #define IS_A64FX(midr) (MIDR_IMPLEMENTOR(midr) == 'F'			      \
 			&& MIDR_PARTNUM(midr) == 0x001)
 
diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile
index 1c3c392513..deef7349fc 100644
--- a/sysdeps/aarch64/multiarch/Makefile
+++ b/sysdeps/aarch64/multiarch/Makefile
@@ -4,6 +4,7 @@ sysdep_routines += \
   memchr_nosimd \
   memcpy_a64fx \
   memcpy_generic \
+  memcpy_kunpeng950 \
   memcpy_mops \
   memcpy_oryon1 \
   memcpy_sve \
diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
index debd935ed6..2fddf58010 100644
--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
@@ -38,6 +38,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_oryon1)
 	      IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_a64fx)
 	      IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_sve)
+	      IFUNC_IMPL_ADD (array, i, memcpy, sve, __memcpy_kunpeng950)
 	      IFUNC_IMPL_ADD (array, i, memcpy, mops, __memcpy_mops)
 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
   IFUNC_IMPL (i, name, memmove,
diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
index 06e5636c33..be5ca1d4da 100644
--- a/sysdeps/aarch64/multiarch/memcpy.c
+++ b/sysdeps/aarch64/multiarch/memcpy.c
@@ -34,6 +34,7 @@ extern __typeof (__redirect_memcpy) __memcpy_a64fx attribute_hidden;
 extern __typeof (__redirect_memcpy) __memcpy_sve attribute_hidden;
 extern __typeof (__redirect_memcpy) __memcpy_mops attribute_hidden;
 extern __typeof (__redirect_memcpy) __memcpy_oryon1 attribute_hidden;
+extern __typeof (__redirect_memcpy) __memcpy_kunpeng950 attribute_hidden;
 
 static inline __typeof (__redirect_memcpy) *
 select_memcpy_ifunc (void)
@@ -45,6 +46,9 @@ select_memcpy_ifunc (void)
 
   if (sve)
     {
+      if (IS_KUNPENG950 (midr))
+	return __memcpy_kunpeng950;
+
       if (IS_A64FX (midr))
 	return __memcpy_a64fx;
       return prefer_sve_ifuncs ? __memcpy_sve : __memcpy_generic;
diff --git a/sysdeps/aarch64/multiarch/memcpy_kunpeng950.S b/sysdeps/aarch64/multiarch/memcpy_kunpeng950.S
new file mode 100644
index 0000000000..82534f9c18
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memcpy_kunpeng950.S
@@ -0,0 +1,115 @@
+/* Optimized memcpy for Huawei Kupeng 950 processor.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+/* Assumptions:
+ *
+ * ARMv8.2-a, AArch64, Advanced SIMD, SVE, unaligned accesses
+ *
+ */
+
+#define dstin	x0
+#define src	x1
+#define count	x2
+#define dst	x3
+#define srcend	x4
+#define dstend	x5
+#define vlen	x6
+#define tmp1	x7
+
+#define A_q	q0
+#define B_q	q1
+#define C_q	q2
+#define D_q	q3
+#define E_q	q4
+#define F_q	q5
+#define G_q	q6
+#define H_q	q7
+
+.arch armv8.2-a+sve
+
+ENTRY (__memcpy_kunpeng950)
+	cmp	count, 128
+	b.hi	L(128_more)
+	cntb	vlen
+	cmp	count, vlen, lsl 1
+	b.hi	L(copy_2vl_more)
+L(copy_0_2vl):
+	whilelo p0.b, xzr, count
+	whilelo p1.b, vlen, count
+	ld1b	z0.b, p0/z, [src]
+	ld1b	z1.b, p1/z, [src, 1, mul vl]
+	st1b	z0.b, p0, [dstin]
+	st1b	z1.b, p1, [dstin, 1, mul vl]
+	ret
+
+	.p2align 4
+L(copy_2vl_more):
+	add	srcend, src, count
+	add	dstend, dstin, count
+	ldp	A_q, B_q, [src]
+	ldp	C_q, D_q, [srcend, -32]
+	cmp	count, 64
+	b.ls	L(copy0_64)
+	ldp	E_q, F_q, [src, 32]
+	ldp	G_q, H_q, [srcend, -64]
+	stp	A_q, B_q, [dstin]
+	stp	C_q, D_q, [dstend, -32]
+	stp	E_q, F_q, [dstin, 32]
+	stp	G_q, H_q, [dstend, -64]
+	ret
+L(copy0_64):
+	stp	A_q, B_q, [dstin]
+	stp	C_q, D_q, [dstend, -32]
+	ret
+
+	.p2align 4
+L(128_more):
+	ldp	E_q, F_q, [src]
+	add	srcend, src, count
+	add	dstend, dstin, count
+
+	and	tmp1, dstin, 31
+	bic	dst, dstin, 31
+	sub	src, src, tmp1
+	add	count, count, tmp1
+
+	ldp	A_q, B_q, [src, 32]
+	ldp	C_q, D_q, [src, 64]!
+	stp	E_q, F_q, [dstin]
+	subs	count, count, 64+64+32
+	b.ls	L(copy64_from_end)
+
+L(loop64):
+	stp	A_q, B_q, [dst, 32]
+	ldp	A_q, B_q, [src, 32]
+	stp	C_q, D_q, [dst, 64]!
+	ldp	C_q, D_q, [src, 64]!
+	subs	count, count, 64
+	b.hi	L(loop64)
+L(copy64_from_end):
+	ldp	E_q, F_q, [srcend, -64]
+	stp	A_q, B_q, [dst,32]
+	ldp	G_q, H_q, [srcend, -32]
+	stp	C_q, D_q, [dst, 64]
+	stp	E_q, F_q, [dstend, -64]
+	stp	G_q, H_q, [dstend, -32]
+	ret
+END (__memcpy_kunpeng950)
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index 297836d8aa..15aed15a66 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -50,6 +50,7 @@ static const struct cpu_list cpu_list[] =
   CPU_LIST_ENTRY ("ares",           0x411FD0C0),
   CPU_LIST_ENTRY ("emag",           0x503F0001),
   CPU_LIST_ENTRY ("kunpeng920",     0x481FD010),
+  CPU_LIST_ENTRY ("kunpeng950",     0x480FD060),
   CPU_LIST_ENTRY ("a64fx",          0x460F0010),
   CPU_LIST_ENTRY ("generic",        0x0),
 };
-- 
2.39.5



More information about the Libc-alpha mailing list