[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