arm64:lib: the optimized string library routines for armv8 processors
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
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
@@ -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
Catalin Marinas
maintainerPATCH 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
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, tmp2I 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.
PATCH v2 2/6 arm64: lib: Implement optimized memmove routine
In reply to zhichang.yuan at linaro.orgFrom: "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
@@ -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
PATCH v2 3/6 arm64: lib: Implement optimized memset routine
In reply to zhichang.yuan at linaro.orgFrom: "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
@@ -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
PATCH v2 4/6 arm64: lib: Implement optimized memcmp routine
In reply to zhichang.yuan at linaro.orgFrom: "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
@@ -34,4 +34,7 @@ extern void *memchr(const void *, int, __kernel_size_t);#define __HAVE_ARCH_MEMSETextern 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
@@ -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
@@ -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
PATCH v2 5/6 arm64: lib: Implement optimized string compare routines
In reply to zhichang.yuan at linaro.orgFrom: "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
@@ -22,6 +22,12 @@ extern char *strrchr(const char *, int c);#define __HAVE_ARCH_STRCHRextern 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_MEMCPYextern void *memcpy (void *,const void *,__kernel_size_t );
arch/arm64/kernel/arm64ksyms.c +2 -0
@@ -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
@@ -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
PATCH v2 6/6 arm64: lib: Implement optimized string length routines
In reply to zhichang.yuan at linaro.orgFrom: "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
@@ -28,6 +28,12 @@ extern int strcmp(const char *, const char *);#define __HAVE_ARCH_STRNCMPextern 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_MEMCPYextern void *memcpy (void *,const void *,__kernel_size_t );
arch/arm64/kernel/arm64ksyms.c +2 -0
@@ -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
@@ -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
Catalin Marinas
maintainerv2 cover arm64:lib: the optimized string library routines for armv8 processors
In reply to zhichang.yuan at linaro.orgQuoted 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
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
Catalin Marinas
maintainerv2 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