Skip to contentSkip to conversation

arm64:lib: the optimized string library routines for armv8 processors

PATCH Superseded zhichang.yuan at linaro.org 2 participants 12 messages Apr 28, 2014 – May 23, 2014 arm64

lore
Share & tools
lore
#0 lore raw

v2 cover arm64:lib: the optimized string library routines for armv8 processors

From: "zhichang.yuan" <[email protected]>

In current aarch64 kernel,there are a few string library routines implemented in arm64/lib,such as memcpy,memset, memmove,strchr. Most string routines frequently used are provided by the architecture-independent string library. Those routines are not so efficient.

This patch set focus on improving the string routines' performance in ARMv8. It contains eight optimized functions.The work is based on the cortex-string project in Linaro toolchain.
The original cortex-string code can be found in this website:
https://code.launchpad.net/cortex-strings

Changes since v1:

* Use macro CPU_BE and CPU_LE to differentiate the instructions for different endianess. Do not use the #ifdef.

* Use .req instead of #define for aliases' definition.

* In patch-3 for memset, use DC ZVA unconditionally.

* Done LTP on big-endian and little-endian system according to maintianers' requirement. The test results can be found at https://wiki.linaro.org/WorkingGroups/Kernel/ARMv8/CortexStringsTests.

* Use macro L1_CAHCE_SHIFT to replace the constant number in .p2align.

* Rearrange the numeric labels in order.

* Modify the comments to be more readable.

Detail of the patches:

To obtain better performance,several ideas were utilized:
* Memory burst access;
For the long memory data operation,adopted the armv8 instruction pairs, ldp/stp,to transfer the bulk data.Try best to use continuous ldp/stp to trigger the burst access.
* Parallel processing
The current string routines mostly processed per-byte. This patch processes the data in parallel.Such as strlen, it will process eight string bytes each time.
* Aligned memory access
Classfy the process into several categories according to the input memory address parameters.For the non-alignment memory address,firstly process the begginning short-length data to make the memory address aligned,then start the remain processing on alignment address.

After the optimization,those routines have better performance than the current ones. Please refer to this website to get the test results:
https://wiki.linaro.org/WorkingGroups/Kernel/ARMv8/cortex-strings

--

zhichang.yuan (6):
arm64: lib: Implement optimized memcpy routine
arm64: lib: Implement optimized memmove routine
arm64: lib: Implement optimized memset routine
arm64: lib: Implement optimized memcmp routine
arm64: lib: Implement optimized string compare routines
arm64: lib: Implement optimized string length routines

 arch/arm64/include/asm/string.h |   15 ++
 arch/arm64/kernel/arm64ksyms.c  |    5 +
 arch/arm64/lib/Makefile         |    1 +
 arch/arm64/lib/memcmp.S         |  258 ++++++++++++++++++++++++++++++++
 arch/arm64/lib/memcpy.S         |  192 +++++++++++++++++++++---
 arch/arm64/lib/memmove.S        |  190 ++++++++++++++++++++----
 arch/arm64/lib/memset.S         |  207 +++++++++++++++++++++++---
 arch/arm64/lib/strcmp.S         |  234 +++++++++++++++++++++++++++++
 arch/arm64/lib/strlen.S         |  126 ++++++++++++++++
 arch/arm64/lib/strncmp.S        |  310 +++++++++++++++++++++++++++++++++++++++
 arch/arm64/lib/strnlen.S        |  171 +++++++++++++++++++++
 11 files changed, 1640 insertions(+), 69 deletions(-)
 create mode 100644 arch/arm64/lib/memcmp.S
 create mode 100644 arch/arm64/lib/strcmp.S
 create mode 100644 arch/arm64/lib/strlen.S
 create mode 100644 arch/arm64/lib/strncmp.S
 create mode 100644 arch/arm64/lib/strnlen.S
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH v2 1/6 arm64: lib: Implement optimized memcpy routine

From: "zhichang.yuan" <[email protected]>

This patch, based on Linaro's Cortex Strings library, improves the performance of the assembly optimized memcpy() function.

---
 arch/arm64/lib/memcpy.S |  192 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 170 insertions(+), 22 deletions(-)
arch/arm64/lib/memcpy.S +170 -22
index 27b5003..8a9a96d 100644
@@ -1,5 +1,13 @@
 /*
  * Copyright (C) 2013 ARM Ltd.
+ * Copyright (C) 2013 Linaro.
+ *
+ * This code is based on glibc cortex strings work originally authored by Linaro
+ * and re-licensed under GPLv2 for the Linux kernel. The original code can
+ * be found @
+ *
+ * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
+ * files/head:/src/aarch64/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +24,7 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/cache.h>
 
 /*
  * Copy a buffer from src to dest (alignment handled by the hardware)
@@ -27,27 +36,166 @@
  * Returns:
  *	x0 - dest
  */
+dstin	.req	x0
+src	.req	x1
+count	.req	x2
+tmp1	.req	x3
+tmp1w	.req	w3
+tmp2	.req	x4
+tmp2w	.req	w4
+tmp3	.req	x5
+tmp3w	.req	w5
+dst	.req	x6
+
+A_l	.req	x7
+A_h	.req	x8
+B_l	.req	x9
+B_h	.req	x10
+C_l	.req	x11
+C_h	.req	x12
+D_l	.req	x13
+D_h	.req	x14
+
 ENTRY(memcpy)
-	mov	x4, x0
-	subs	x2, x2, #8
-	b.mi	2f
-1:	ldr	x3, [x1], #8
-	subs	x2, x2, #8
-	str	x3, [x4], #8
-	b.pl	1b
-2:	adds	x2, x2, #4
-	b.mi	3f
-	ldr	w3, [x1], #4
-	sub	x2, x2, #4
-	str	w3, [x4], #4
-3:	adds	x2, x2, #2
-	b.mi	4f
-	ldrh	w3, [x1], #2
-	sub	x2, x2, #2
-	strh	w3, [x4], #2
-4:	adds	x2, x2, #1
-	b.mi	5f
-	ldrb	w3, [x1]
-	strb	w3, [x4]
-5:	ret
+	mov	dst, dstin
+	cmp	count, #16
+	/*When memory length is less than 16, the accessed are not aligned.*/
+	b.lo	.Ltiny15
+
+	neg	tmp2, src
+	ands	tmp2, tmp2, #15/* Bytes to reach alignment. */
+	b.eq	.LSrcAligned
+	sub	count, count, tmp2
+	/*
+	* Copy the leading memory data from src to dst in an increasing
+	* address order.By this way,the risk of overwritting the source
+	* memory data is eliminated when the distance between src and
+	* dst is less than 16. The memory accesses here are alignment.
+	*/
+	tbz	tmp2, #0, 1f
+	ldrb	tmp1w, [src], #1
+	strb	tmp1w, [dst], #1
+1:
+	tbz	tmp2, #1, 2f
+	ldrh	tmp1w, [src], #2
+	strh	tmp1w, [dst], #2
+2:
+	tbz	tmp2, #2, 3f
+	ldr	tmp1w, [src], #4
+	str	tmp1w, [dst], #4
+3:
+	tbz	tmp2, #3, .LSrcAligned
+	ldr	tmp1, [src],#8
+	str	tmp1, [dst],#8
+
+.LSrcAligned:
+	cmp	count, #64
+	b.ge	.Lcpy_over64
+	/*
+	* Deal with small copies quickly by dropping straight into the
+	* exit block.
+	*/
+.Ltail63:
+	/*
+	* Copy up to 48 bytes of data. At this point we only need the
+	* bottom 6 bits of count to be accurate.
+	*/
+	ands	tmp1, count, #0x30
+	b.eq	.Ltiny15
+	cmp	tmp1w, #0x20
+	b.eq	1f
+	b.lt	2f
+	ldp	A_l, A_h, [src], #16
+	stp	A_l, A_h, [dst], #16
+1:
+	ldp	A_l, A_h, [src], #16
+	stp	A_l, A_h, [dst], #16
+2:
+	ldp	A_l, A_h, [src], #16
+	stp	A_l, A_h, [dst], #16
+.Ltiny15:
+	/*
+	* Prefer to break one ldp/stp into several load/store to access
+	* memory in an increasing address order,rather than to load/store 16
+	* bytes from (src-16) to (dst-16) and to backward the src to aligned
+	* address,which way is used in original cortex memcpy. If keeping
+	* the original memcpy process here, memmove need to satisfy the
+	* precondition that src address is at least 16 bytes bigger than dst
+	* address,otherwise some source data will be overwritten when memove
+	* call memcpy directly. To make memmove simpler and decouple the
+	* memcpy's dependency on memmove, withdrew the original process.
+	*/
+	tbz	count, #3, 1f
+	ldr	tmp1, [src], #8
+	str	tmp1, [dst], #8
+1:
+	tbz	count, #2, 2f
+	ldr	tmp1w, [src], #4
+	str	tmp1w, [dst], #4
+2:
+	tbz	count, #1, 3f
+	ldrh	tmp1w, [src], #2
+	strh	tmp1w, [dst], #2
+3:
+	tbz	count, #0, .Lexitfunc
+	ldrb	tmp1w, [src]
+	strb	tmp1w, [dst]
+
+.Lexitfunc:
+	ret
+
+.Lcpy_over64:
+	subs	count, count, #128
+	b.ge	.Lcpy_body_large
+	/*
+	* Less than 128 bytes to copy, so handle 64 here and then jump
+	* to the tail.
+	*/
+	ldp	A_l, A_h, [src],#16
+	stp	A_l, A_h, [dst],#16
+	ldp	B_l, B_h, [src],#16
+	ldp	C_l, C_h, [src],#16
+	stp	B_l, B_h, [dst],#16
+	stp	C_l, C_h, [dst],#16
+	ldp	D_l, D_h, [src],#16
+	stp	D_l, D_h, [dst],#16
+
+	tst	count, #0x3f
+	b.ne	.Ltail63
+	ret
+
+	/*
+	* Critical loop.  Start at a new cache line boundary.  Assuming
+	* 64 bytes per line this ensures the entire loop is in one line.
+	*/
+	.p2align	L1_CACHE_SHIFT
+.Lcpy_body_large:
+	/* pre-get 64 bytes data. */
+	ldp	A_l, A_h, [src],#16
+	ldp	B_l, B_h, [src],#16
+	ldp	C_l, C_h, [src],#16
+	ldp	D_l, D_h, [src],#16
+1:
+	/*
+	* interlace the load of next 64 bytes data block with store of the last
+	* loaded 64 bytes data.
+	*/
+	stp	A_l, A_h, [dst],#16
+	ldp	A_l, A_h, [src],#16
+	stp	B_l, B_h, [dst],#16
+	ldp	B_l, B_h, [src],#16
+	stp	C_l, C_h, [dst],#16
+	ldp	C_l, C_h, [src],#16
+	stp	D_l, D_h, [dst],#16
+	ldp	D_l, D_h, [src],#16
+	subs	count, count, #64
+	b.ge	1b
+	stp	A_l, A_h, [dst],#16
+	stp	B_l, B_h, [dst],#16
+	stp	C_l, C_h, [dst],#16
+	stp	D_l, D_h, [dst],#16
+
+	tst	count, #0x3f
+	b.ne	.Ltail63
+	ret
 ENDPROC(memcpy)
Signature · 1 line
1.7.9.5
maintainer
#2 lore raw

PATCH v2 1/6 arm64: lib: Implement optimized memcpy routine

Quoted 2 lines · zhichang.yuan at linaro.org

This patch, based on Linaro's Cortex Strings library, improves the performance of the assembly optimized memcpy() function.

[...]

Quoted 2 lines
arch/arm64/lib/memcpy.S +0 -0

[...]

Quoted 1 line

ENTRY(memcpy)

[...]

arch/arm64/lib/memcpy.S line 68

Quoted 9 lines
arch/arm64/lib/memcpy.S +9 -0
+	mov	dst, dstin
+	cmp	count, #16
+	/*When memory length is less than 16, the accessed are not aligned.*/
+	b.lo	.Ltiny15
+
+	neg	tmp2, src
+	ands	tmp2, tmp2, #15/* Bytes to reach alignment. */
+	b.eq	.LSrcAligned
+	sub	count, count, tmp2

I started looking at this and comparing it to the original cortex strings library. Is there any reason why at least the first part has been rewritten? For example, the cortex strings starts with probably the most likely case, comparing the count with 64.

Signature · 1 line
Catalin
#3 lore raw

PATCH v2 1/6 arm64: lib: Implement optimized memcpy routine

Quoted 9 lines · Catalin Marinas
Quoted 2 lines · zhichang.yuan at linaro.org

This patch, based on Linaro's Cortex Strings library, improves the performance of the assembly optimized memcpy() function.

[...]

Quoted 2 lines
arch/arm64/lib/memcpy.S +0 -0

[...]

Quoted 1 line

ENTRY(memcpy)

[...]

Quoted 13 lines

arch/arm64/lib/memcpy.S line 68

Quoted 9 lines
arch/arm64/lib/memcpy.S +9 -0
+	mov	dst, dstin
+	cmp	count, #16
+	/*When memory length is less than 16, the accessed are not aligned.*/
+	b.lo	.Ltiny15
+
+	neg	tmp2, src
+	ands	tmp2, tmp2, #15/* Bytes to reach alignment. */
+	b.eq	.LSrcAligned
+	sub	count, count, tmp2

I started looking at this and comparing it to the original cortex strings library. Is there any reason why at least the first part has been rewritten? For example, the cortex strings starts with probably the most likely case, comparing the count with 64.

Yes. The original cortex-string starts with comparing the count of 64. But actually when the process for count 64 begins in label .Lcpy_not_short, it will firstly make the source address aligned with 16. It means that for count over 79, the data moving starts on the boundary aligned with 16 for better efficiency. Otherwise, data moving will starts at random source address, rather than the aligned source address. Since the aligned source address is needed for count over 63, i think it is not costly to move the alignment processing at the beginning. After this process, the data moving will start from aligned source address for most of count except when count is less than 16.
This is why current cortex-string begins with the alignment process.

In this patch, there is another change compared with original cortex-string. The original memcpy load/store memory in a decreasing address order from .Ltail63 to .Ltail15tiny. Of-course, this process will save several load/store operations when count is among [16,64). But it lead to memmove can not call memcpy directly when destination is less than source. We can found there are several branches in original memmove to grantee the call of memcpy is safe only when the destination is less than source at lease by 16. According to the program manual, memcpy can be used when the dest area is not overlapped with source area. But in the original cortex memcpy, it demands that the source address must be bigger than ( dst + 16 ). This limit breaks the condition when memcpy can be used.
So I change the process of memcpy, make all load/store operate only in a increasing address order. After that, i remove the .Ldownwards code segment from memmove and call memcpy directly for this case.

The change in memcpy has a little time penalty when count is short, since several load/store are added. The current memmove is a little better than original one in performance.

#4 lore raw

PATCH v2 2/6 arm64: lib: Implement optimized memmove routine

In reply to zhichang.yuan at linaro.org

From: "zhichang.yuan" <[email protected]>

This patch, based on Linaro's Cortex Strings library, improves the performance of the assembly optimized memmove() function.

---
 arch/arm64/lib/memmove.S |  190 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 165 insertions(+), 25 deletions(-)
arch/arm64/lib/memmove.S +165 -25
index b79fdfa..57b19ea 100644
@@ -1,5 +1,13 @@
 /*
  * Copyright (C) 2013 ARM Ltd.
+ * Copyright (C) 2013 Linaro.
+ *
+ * This code is based on glibc cortex strings work originally authored by Linaro
+ * and re-licensed under GPLv2 for the Linux kernel. The original code can
+ * be found @
+ *
+ * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
+ * files/head:/src/aarch64/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +24,7 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/cache.h>
 
 /*
  * Move a buffer from src to test (alignment handled by the hardware).
@@ -28,30 +37,161 @@
  * Returns:
  *	x0 - dest
  */
+dstin	.req	x0
+src	.req	x1
+count	.req	x2
+tmp1	.req	x3
+tmp1w	.req	w3
+tmp2	.req	x4
+tmp2w	.req	w4
+tmp3	.req	x5
+tmp3w	.req	w5
+dst	.req	x6
+
+A_l	.req	x7
+A_h	.req	x8
+B_l	.req	x9
+B_h	.req	x10
+C_l	.req	x11
+C_h	.req	x12
+D_l	.req	x13
+D_h	.req	x14
+
 ENTRY(memmove)
-	cmp	x0, x1
-	b.ls	memcpy
-	add	x4, x0, x2
-	add	x1, x1, x2
-	subs	x2, x2, #8
-	b.mi	2f
-1:	ldr	x3, [x1, #-8]!
-	subs	x2, x2, #8
-	str	x3, [x4, #-8]!
-	b.pl	1b
-2:	adds	x2, x2, #4
-	b.mi	3f
-	ldr	w3, [x1, #-4]!
-	sub	x2, x2, #4
-	str	w3, [x4, #-4]!
-3:	adds	x2, x2, #2
-	b.mi	4f
-	ldrh	w3, [x1, #-2]!
-	sub	x2, x2, #2
-	strh	w3, [x4, #-2]!
-4:	adds	x2, x2, #1
-	b.mi	5f
-	ldrb	w3, [x1, #-1]
-	strb	w3, [x4, #-1]
-5:	ret
+	cmp	dstin, src
+	b.lo	memcpy
+	add	tmp1, src, count
+	cmp	dstin, tmp1
+	b.hs	memcpy		/* No overlap.  */
+
+	add	dst, dstin, count
+	add	src, src, count
+	cmp	count, #16
+	b.lo	.Ltail15  /*probably non-alignment accesses.*/
+
+	ands	tmp2, src, #15     /* Bytes to reach alignment.  */
+	b.eq	.LSrcAligned
+	sub	count, count, tmp2
+	/*
+	* process the aligned offset length to make the src aligned firstly.
+	* those extra instructions' cost is acceptable. It also make the
+	* coming accesses are based on aligned address.
+	*/
+	tbz	tmp2, #0, 1f
+	ldrb	tmp1w, [src, #-1]!
+	strb	tmp1w, [dst, #-1]!
+1:
+	tbz	tmp2, #1, 2f
+	ldrh	tmp1w, [src, #-2]!
+	strh	tmp1w, [dst, #-2]!
+2:
+	tbz	tmp2, #2, 3f
+	ldr	tmp1w, [src, #-4]!
+	str	tmp1w, [dst, #-4]!
+3:
+	tbz	tmp2, #3, .LSrcAligned
+	ldr	tmp1, [src, #-8]!
+	str	tmp1, [dst, #-8]!
+
+.LSrcAligned:
+	cmp	count, #64
+	b.ge	.Lcpy_over64
+
+	/*
+	* Deal with small copies quickly by dropping straight into the
+	* exit block.
+	*/
+.Ltail63:
+	/*
+	* Copy up to 48 bytes of data. At this point we only need the
+	* bottom 6 bits of count to be accurate.
+	*/
+	ands	tmp1, count, #0x30
+	b.eq	.Ltail15
+	cmp	tmp1w, #0x20
+	b.eq	1f
+	b.lt	2f
+	ldp	A_l, A_h, [src, #-16]!
+	stp	A_l, A_h, [dst, #-16]!
+1:
+	ldp	A_l, A_h, [src, #-16]!
+	stp	A_l, A_h, [dst, #-16]!
+2:
+	ldp	A_l, A_h, [src, #-16]!
+	stp	A_l, A_h, [dst, #-16]!
+
+.Ltail15:
+	tbz	count, #3, 1f
+	ldr	tmp1, [src, #-8]!
+	str	tmp1, [dst, #-8]!
+1:
+	tbz	count, #2, 2f
+	ldr	tmp1w, [src, #-4]!
+	str	tmp1w, [dst, #-4]!
+2:
+	tbz	count, #1, 3f
+	ldrh	tmp1w, [src, #-2]!
+	strh	tmp1w, [dst, #-2]!
+3:
+	tbz	count, #0, .Lexitfunc
+	ldrb	tmp1w, [src, #-1]
+	strb	tmp1w, [dst, #-1]
+
+.Lexitfunc:
+	ret
+
+.Lcpy_over64:
+	subs	count, count, #128
+	b.ge	.Lcpy_body_large
+	/*
+	* Less than 128 bytes to copy, so handle 64 bytes here and then jump
+	* to the tail.
+	*/
+	ldp	A_l, A_h, [src, #-16]
+	stp	A_l, A_h, [dst, #-16]
+	ldp	B_l, B_h, [src, #-32]
+	ldp	C_l, C_h, [src, #-48]
+	stp	B_l, B_h, [dst, #-32]
+	stp	C_l, C_h, [dst, #-48]
+	ldp	D_l, D_h, [src, #-64]!
+	stp	D_l, D_h, [dst, #-64]!
+
+	tst	count, #0x3f
+	b.ne	.Ltail63
+	ret
+
+	/*
+	* Critical loop. Start at a new cache line boundary. Assuming
+	* 64 bytes per line this ensures the entire loop is in one line.
+	*/
+	.p2align	L1_CACHE_SHIFT
+.Lcpy_body_large:
+	/* pre-load 64 bytes data. */
+	ldp	A_l, A_h, [src, #-16]
+	ldp	B_l, B_h, [src, #-32]
+	ldp	C_l, C_h, [src, #-48]
+	ldp	D_l, D_h, [src, #-64]!
+1:
+	/*
+	* interlace the load of next 64 bytes data block with store of the last
+	* loaded 64 bytes data.
+	*/
+	stp	A_l, A_h, [dst, #-16]
+	ldp	A_l, A_h, [src, #-16]
+	stp	B_l, B_h, [dst, #-32]
+	ldp	B_l, B_h, [src, #-32]
+	stp	C_l, C_h, [dst, #-48]
+	ldp	C_l, C_h, [src, #-48]
+	stp	D_l, D_h, [dst, #-64]!
+	ldp	D_l, D_h, [src, #-64]!
+	subs	count, count, #64
+	b.ge	1b
+	stp	A_l, A_h, [dst, #-16]
+	stp	B_l, B_h, [dst, #-32]
+	stp	C_l, C_h, [dst, #-48]
+	stp	D_l, D_h, [dst, #-64]!
+
+	tst	count, #0x3f
+	b.ne	.Ltail63
+	ret
 ENDPROC(memmove)
Signature · 1 line
1.7.9.5
#5 lore raw

PATCH v2 3/6 arm64: lib: Implement optimized memset routine

In reply to zhichang.yuan at linaro.org

From: "zhichang.yuan" <[email protected]>

This patch, based on Linaro's Cortex Strings library, improves the performance of the assembly optimized memset() function.

---
 arch/arm64/lib/memset.S |  207 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 185 insertions(+), 22 deletions(-)
arch/arm64/lib/memset.S +185 -22
index 87e4a68..7c72dfd 100644
@@ -1,5 +1,13 @@
 /*
  * Copyright (C) 2013 ARM Ltd.
+ * Copyright (C) 2013 Linaro.
+ *
+ * This code is based on glibc cortex strings work originally authored by Linaro
+ * and re-licensed under GPLv2 for the Linux kernel. The original code can
+ * be found @
+ *
+ * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/
+ * files/head:/src/aarch64/
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +24,7 @@
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/cache.h>
 
 /*
  * Fill in the buffer with character c (alignment handled by the hardware)
@@ -27,27 +36,181 @@
  * Returns:
  *	x0 - buf
  */
+
+dstin		.req	x0
+val		.req	w1
+count		.req	x2
+tmp1		.req	x3
+tmp1w		.req	w3
+tmp2		.req	x4
+tmp2w		.req	w4
+zva_len_x	.req	x5
+zva_len		.req	w5
+zva_bits_x	.req	x6
+
+A_l		.req	x7
+A_lw		.req	w7
+dst		.req	x8
+tmp3w		.req	w9
+tmp3		.req	x9
+
 ENTRY(memset)
-	mov	x4, x0
-	and	w1, w1, #0xff
-	orr	w1, w1, w1, lsl #8
-	orr	w1, w1, w1, lsl #16
-	orr	x1, x1, x1, lsl #32
-	subs	x2, x2, #8
-	b.mi	2f
-1:	str	x1, [x4], #8
-	subs	x2, x2, #8
-	b.pl	1b
-2:	adds	x2, x2, #4
-	b.mi	3f
-	sub	x2, x2, #4
-	str	w1, [x4], #4
-3:	adds	x2, x2, #2
-	b.mi	4f
-	sub	x2, x2, #2
-	strh	w1, [x4], #2
-4:	adds	x2, x2, #1
-	b.mi	5f
-	strb	w1, [x4]
-5:	ret
+	mov	dst, dstin	/* Preserve return value.  */
+	and	A_lw, val, #255
+	orr	A_lw, A_lw, A_lw, lsl #8
+	orr	A_lw, A_lw, A_lw, lsl #16
+	orr	A_l, A_l, A_l, lsl #32
+
+	cmp	count, #15
+	b.hi	.Lover16_proc
+	/*All store maybe are non-aligned..*/
+	tbz	count, #3, 1f
+	str	A_l, [dst], #8
+1:
+	tbz	count, #2, 2f
+	str	A_lw, [dst], #4
+2:
+	tbz	count, #1, 3f
+	strh	A_lw, [dst], #2
+3:
+	tbz	count, #0, 4f
+	strb	A_lw, [dst]
+4:
+	ret
+
+.Lover16_proc:
+	/*Whether  the start address is aligned with 16.*/
+	neg	tmp2, dst
+	ands	tmp2, tmp2, #15
+	b.eq	.Laligned
+/*
+* The count is not less than 16, we can use stp to store the start 16 bytes,
+* then adjust the dst aligned with 16.This process will make the current
+* memory address at alignment boundary.
+*/
+	stp	A_l, A_l, [dst] /*non-aligned store..*/
+	/*make the dst aligned..*/
+	sub	count, count, tmp2
+	add	dst, dst, tmp2
+
+.Laligned:
+	cbz	A_l, .Lzero_mem
+
+.Ltail_maybe_long:
+	cmp	count, #64
+	b.ge	.Lnot_short
+.Ltail63:
+	ands	tmp1, count, #0x30
+	b.eq	3f
+	cmp	tmp1w, #0x20
+	b.eq	1f
+	b.lt	2f
+	stp	A_l, A_l, [dst], #16
+1:
+	stp	A_l, A_l, [dst], #16
+2:
+	stp	A_l, A_l, [dst], #16
+/*
+* The last store length is less than 16,use stp to write last 16 bytes.
+* It will lead some bytes written twice and the access is non-aligned.
+*/
+3:
+	ands	count, count, #15
+	cbz	count, 4f
+	add	dst, dst, count
+	stp	A_l, A_l, [dst, #-16]	/* Repeat some/all of last store. */
+4:
+	ret
+
+	/*
+	* Critical loop. Start at a new cache line boundary. Assuming
+	* 64 bytes per line, this ensures the entire loop is in one line.
+	*/
+	.p2align	L1_CACHE_SHIFT
+.Lnot_short:
+	sub	dst, dst, #16/* Pre-bias.  */
+	sub	count, count, #64
+1:
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	stp	A_l, A_l, [dst, #48]
+	stp	A_l, A_l, [dst, #64]!
+	subs	count, count, #64
+	b.ge	1b
+	tst	count, #0x3f
+	add	dst, dst, #16
+	b.ne	.Ltail63
+.Lexitfunc:
+	ret
+
+	/*
+	* For zeroing memory, check to see if we can use the ZVA feature to
+	* zero entire 'cache' lines.
+	*/
+.Lzero_mem:
+	cmp	count, #63
+	b.le	.Ltail63
+	/*
+	* For zeroing small amounts of memory, it's not worth setting up
+	* the line-clear code.
+	*/
+	cmp	count, #128
+	b.lt	.Lnot_short /*count is at least  128 bytes*/
+
+	mrs	tmp1, dczid_el0
+	tbnz	tmp1, #4, .Lnot_short
+	mov	tmp3w, #4
+	and	zva_len, tmp1w, #15	/* Safety: other bits reserved.  */
+	lsl	zva_len, tmp3w, zva_len
+
+	ands	tmp3w, zva_len, #63
+	/*
+	* ensure the zva_len is not less than 64.
+	* It is not meaningful to use ZVA if the block size is less than 64.
+	*/
+	b.ne	.Lnot_short
+.Lzero_by_line:
+	/*
+	* Compute how far we need to go to become suitably aligned. We're
+	* already at quad-word alignment.
+	*/
+	cmp	count, zva_len_x
+	b.lt	.Lnot_short		/* Not enough to reach alignment.  */
+	sub	zva_bits_x, zva_len_x, #1
+	neg	tmp2, dst
+	ands	tmp2, tmp2, zva_bits_x
+	b.eq	2f			/* Already aligned.  */
+	/* Not aligned, check that there's enough to copy after alignment.*/
+	sub	tmp1, count, tmp2
+	/*
+	* grantee the remain length to be ZVA is bigger than 64,
+	* avoid to make the 2f's process over mem range.*/
+	cmp	tmp1, #64
+	ccmp	tmp1, zva_len_x, #8, ge	/* NZCV=0b1000 */
+	b.lt	.Lnot_short
+	/*
+	* We know that there's at least 64 bytes to zero and that it's safe
+	* to overrun by 64 bytes.
+	*/
+	mov	count, tmp1
+1:
+	stp	A_l, A_l, [dst]
+	stp	A_l, A_l, [dst, #16]
+	stp	A_l, A_l, [dst, #32]
+	subs	tmp2, tmp2, #64
+	stp	A_l, A_l, [dst, #48]
+	add	dst, dst, #64
+	b.ge	1b
+	/* We've overrun a bit, so adjust dst downwards.*/
+	add	dst, dst, tmp2
+2:
+	sub	count, count, zva_len_x
+3:
+	dc	zva, dst
+	add	dst, dst, zva_len_x
+	subs	count, count, zva_len_x
+	b.ge	3b
+	ands	count, count, zva_bits_x
+	b.ne	.Ltail_maybe_long
+	ret
 ENDPROC(memset)
Signature · 1 line
1.7.9.5
#6 lore raw

PATCH v2 4/6 arm64: lib: Implement optimized memcmp routine

In reply to zhichang.yuan at linaro.org

From: "zhichang.yuan" <[email protected]>

This patch, based on Linaro's Cortex Strings library, adds an assembly optimized memcmp() function.

---
 arch/arm64/include/asm/string.h |    3 +
 arch/arm64/kernel/arm64ksyms.c  |    1 +
 arch/arm64/lib/Makefile         |    2 +-
 arch/arm64/lib/memcmp.S         |  258 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 263 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/lib/memcmp.S
arch/arm64/include/asm/string.h +3 -0
index 3ee8b30..3a43305 100644
@@ -34,4 +34,7 @@ extern void *memchr(const void *, int, __kernel_size_t);
 #define __HAVE_ARCH_MEMSET
 extern void *memset(void *, int, __kernel_size_t);
 
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, size_t);
+
 #endif
arch/arm64/kernel/arm64ksyms.c +1 -0
index 338b568..909c18e 100644
@@ -48,6 +48,7 @@ EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
 EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(memcmp);
 
 	/* atomic bitops */
 EXPORT_SYMBOL(set_bit);
arch/arm64/lib/Makefile +1 -1
index 328ce1a..112c67f 100644
@@ -1,4 +1,4 @@
 lib-y		:= bitops.o clear_user.o delay.o copy_from_user.o	\
 		   copy_to_user.o copy_in_user.o copy_page.o		\
 		   clear_page.o memchr.o memcpy.o memmove.o memset.o	\
-		   strchr.o strrchr.o
+		   memcmp.o strchr.o strrchr.o
arch/arm64/lib/memcmp.S new file +258 -0

258 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#7 lore raw

PATCH v2 5/6 arm64: lib: Implement optimized string compare routines

In reply to zhichang.yuan at linaro.org

From: "zhichang.yuan" <[email protected]>

This patch, based on Linaro's Cortex Strings library, adds an assembly optimized strcmp() and strncmp() functions.

---
 arch/arm64/include/asm/string.h |    6 +
 arch/arm64/kernel/arm64ksyms.c  |    2 +
 arch/arm64/lib/Makefile         |    2 +-
 arch/arm64/lib/strcmp.S         |  234 +++++++++++++++++++++++++++++
 arch/arm64/lib/strncmp.S        |  310 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 553 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/lib/strcmp.S
 create mode 100644 arch/arm64/lib/strncmp.S
arch/arm64/include/asm/string.h +6 -0
index 3a43305..6133f49 100644
@@ -22,6 +22,12 @@ extern char *strrchr(const char *, int c);
 #define __HAVE_ARCH_STRCHR
 extern char *strchr(const char *, int c);
 
+#define __HAVE_ARCH_STRCMP
+extern int strcmp(const char *, const char *);
+
+#define __HAVE_ARCH_STRNCMP
+extern int strncmp(const char *, const char *, __kernel_size_t);
+
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *, const void *, __kernel_size_t);
 
arch/arm64/kernel/arm64ksyms.c +2 -0
index 909c18e..2784a79 100644
@@ -44,6 +44,8 @@ EXPORT_SYMBOL(memstart_addr);
 	/* string / mem functions */
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
arch/arm64/lib/Makefile +1 -1
index 112c67f..aaaf618 100644
@@ -1,4 +1,4 @@
 lib-y		:= bitops.o clear_user.o delay.o copy_from_user.o	\
 		   copy_to_user.o copy_in_user.o copy_page.o		\
 		   clear_page.o memchr.o memcpy.o memmove.o memset.o	\
-		   memcmp.o strchr.o strrchr.o
+		   memcmp.o strcmp.o strncmp.o strchr.o strrchr.o
arch/arm64/lib/strcmp.S new file +234 -0

234 lines not on this page · raw message

arch/arm64/lib/strncmp.S new file +310 -0

310 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#8 lore raw

PATCH v2 6/6 arm64: lib: Implement optimized string length routines

In reply to zhichang.yuan at linaro.org

From: "zhichang.yuan" <[email protected]>

This patch, based on Linaro's Cortex Strings library, adds an assembly optimized strlen() and strnlen() functions.

---
 arch/arm64/include/asm/string.h |    6 ++
 arch/arm64/kernel/arm64ksyms.c  |    2 +
 arch/arm64/lib/Makefile         |    3 +-
 arch/arm64/lib/strlen.S         |  126 +++++++++++++++++++++++++++++
 arch/arm64/lib/strnlen.S        |  171 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 307 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/lib/strlen.S
 create mode 100644 arch/arm64/lib/strnlen.S
arch/arm64/include/asm/string.h +6 -0
index 6133f49..64d2d48 100644
@@ -28,6 +28,12 @@ extern int strcmp(const char *, const char *);
 #define __HAVE_ARCH_STRNCMP
 extern int strncmp(const char *, const char *, __kernel_size_t);
 
+#define __HAVE_ARCH_STRLEN
+extern __kernel_size_t strlen(const char *);
+
+#define __HAVE_ARCH_STRNLEN
+extern __kernel_size_t strnlen(const char *, __kernel_size_t);
+
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *, const void *, __kernel_size_t);
 
arch/arm64/kernel/arm64ksyms.c +2 -0
index 2784a79..1edc792 100644
@@ -46,6 +46,8 @@ EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(memset);
 EXPORT_SYMBOL(memcpy);
 EXPORT_SYMBOL(memmove);
arch/arm64/lib/Makefile +2 -1
index aaaf618..d98d3e3 100644
@@ -1,4 +1,5 @@
 lib-y		:= bitops.o clear_user.o delay.o copy_from_user.o	\
 		   copy_to_user.o copy_in_user.o copy_page.o		\
 		   clear_page.o memchr.o memcpy.o memmove.o memset.o	\
-		   memcmp.o strcmp.o strncmp.o strchr.o strrchr.o
+		   memcmp.o strcmp.o strncmp.o strlen.o strnlen.o	\
+		   strchr.o strrchr.o
arch/arm64/lib/strlen.S new file +126 -0

126 lines not on this page · raw message

arch/arm64/lib/strnlen.S new file +171 -0

171 lines not on this page · raw message

Signature · 1 line
1.7.9.5
maintainer
#9 lore raw

v2 cover arm64:lib: the optimized string library routines for armv8 processors

In reply to zhichang.yuan at linaro.org
Quoted 3 lines · zhichang.yuan at linaro.org

* Done LTP on big-endian and little-endian system according to maintianers' requirement. The test results can be found at
https://wiki.linaro.org/WorkingGroups/Kernel/ARMv8/CortexStringsTests.

It's not clear to me from the above page but have you done a compat (AArch32) LTP test as well?

Thanks.

Signature · 1 line
Catalin
#10 lore raw

v2 cover arm64:lib: the optimized string library routines for armv8 processors

Quoted 8 lines · Catalin Marinas
Quoted 3 lines · zhichang.yuan at linaro.org

* Done LTP on big-endian and little-endian system according to maintianers' requirement. The test results can be found at
https://wiki.linaro.org/WorkingGroups/Kernel/ARMv8/CortexStringsTests.

It's not clear to me from the above page but have you done a compat (AArch32) LTP test as well?

Thanks.

Hi Catalin,

O, i missed the LTP test on compatible Aarch32 mode.
At the moment, i have supplement these LTP tests. The LTP tests were OK.

According to the new test result, I rewrote the test report at
https://wiki.linaro.org/WorkingGroups/Kernel/ARMv8/CortexStringsTests .

Thanks,
Zhichang

maintainer
#11 lore raw

v2 cover arm64:lib: the optimized string library routines for armv8 processors

Quoted 5 lines · zhichang.yuan
Quoted 4 lines · Catalin Marinas
Quoted 3 lines · zhichang.yuan at linaro.org

* Done LTP on big-endian and little-endian system according to maintianers' requirement. The test results can be found at
https://wiki.linaro.org/WorkingGroups/Kernel/ARMv8/CortexStringsTests.

Quoted 8 lines
Quoted 2 lines

It's not clear to me from the above page but have you done a compat (AArch32) LTP test as well?

O, i missed the LTP test on compatible Aarch32 mode.
At the moment, i have supplement these LTP tests. The LTP tests were OK.

According to the new test result, I rewrote the test report at
https://wiki.linaro.org/WorkingGroups/Kernel/ARMv8/CortexStringsTests .

Thanks. I merged the patches and should appear in -next in the following days. We'll run some tests as well to make sure.

BTW, I'm off for a week, so if there are any issues please talk to Will.

Signature · 1 line
Catalin