OSDN Git Service

libc: arm: add optimized memchr implementation
authorYingshiuan Pan <yingshiuan.pan@linaro.org>
Thu, 23 Apr 2015 03:07:59 +0000 (04:07 +0100)
committerSteve Kondik <steve@cyngn.com>
Sat, 31 Oct 2015 21:40:52 +0000 (14:40 -0700)
This optimization is extracted from cortex-strings and bionic-ized,
and applied to arm-v7a cpus (a7, a9, a15, a53, denver, krait).

I ran stringbench[1] on ARM Juno, this optimization could outperform
origin C implementation by 77%.

[1] https://android.git.linaro.org/gitweb/platform/external/stringbench.git

Change-Id: I1c3fb0c89ce2b3ee7e44f492367b6caf6db58ccf
Signed-off-by: Yingshiuan Pan <yingshiuan.pan@linaro.org>
libc/arch-arm/arm.mk
libc/arch-arm/cortex-a15/cortex-a15.mk
libc/arch-arm/cortex-a53/cortex-a53.mk
libc/arch-arm/cortex-a7/cortex-a7.mk
libc/arch-arm/cortex-a9/cortex-a9.mk
libc/arch-arm/denver/denver.mk
libc/arch-arm/generic/bionic/memchr.S [new file with mode: 0644]
libc/arch-arm/generic/generic.mk
libc/arch-arm/krait/krait.mk

index 18a9833..c2b80c5 100644 (file)
@@ -20,7 +20,6 @@ libc_freebsd_src_files_arm += \
     upstream-freebsd/lib/libc/string/wmemmove.c \
 
 libc_openbsd_src_files_arm += \
-    upstream-openbsd/lib/libc/string/memchr.c \
     upstream-openbsd/lib/libc/string/memrchr.c \
     upstream-openbsd/lib/libc/string/stpncpy.c \
     upstream-openbsd/lib/libc/string/strlcat.c \
index 6fa3270..202a3bf 100644 (file)
@@ -10,6 +10,7 @@ libc_bionic_src_files_arm += \
     arch-arm/cortex-a15/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memchr.S \
     arch-arm/generic/bionic/memcmp.S \
 
 libc_bionic_src_files_arm += \
index bb00433..14aaa71 100644 (file)
@@ -14,6 +14,7 @@ libc_bionic_src_files_arm += \
     arch-arm/cortex-a15/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memchr.S \
     arch-arm/generic/bionic/memcmp.S \
 
 libc_bionic_src_files_arm += \
index b6af4da..3629a57 100644 (file)
@@ -12,6 +12,7 @@ libc_bionic_src_files_arm += \
     arch-arm/cortex-a15/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memchr.S \
     arch-arm/generic/bionic/memcmp.S \
 
 libc_bionic_src_files_arm += \
index 7b38de1..db4bcc7 100644 (file)
@@ -10,6 +10,7 @@ libc_bionic_src_files_arm += \
     arch-arm/cortex-a9/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memchr.S \
     arch-arm/generic/bionic/memcmp.S \
 
 libc_bionic_src_files_arm += \
index 5fddf95..e81f8c7 100644 (file)
@@ -1,4 +1,5 @@
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memchr.S \
     arch-arm/generic/bionic/memcmp.S \
     arch-arm/denver/bionic/memcpy.S \
     arch-arm/denver/bionic/memmove.S \
diff --git a/libc/arch-arm/generic/bionic/memchr.S b/libc/arch-arm/generic/bionic/memchr.S
new file mode 100644 (file)
index 0000000..cb00d82
--- /dev/null
@@ -0,0 +1,155 @@
+/* Copyright (c) 2010-2015, Linaro Limited
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+      * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+      * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+      * Neither the name of Linaro Limited nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+   Written by Dave Gilbert <david.gilbert@linaro.org>
+
+   This memchr routine is optimised on a Cortex-A9 and should work on
+   all ARMv7 processors.   It has a fast past for short sizes, and has
+   an optimised path for large data sets; the worst case is finding the
+   match early in a large data set.
+
+ */
+
+#include <private/bionic_asm.h>
+
+@ 2011-02-07 david.gilbert@linaro.org
+@    Extracted from local git a5b438d861
+@ 2011-07-14 david.gilbert@linaro.org
+@    Import endianness fix from local git ea786f1b
+@ 2011-12-07 david.gilbert@linaro.org
+@    Removed unneeded cbz from align loop
+
+       .syntax unified
+       .arch armv7-a
+
+@ this lets us check a flag in a 00/ff byte easily in either endianness
+#ifdef __ARMEB__
+#define CHARTSTMASK(c) 1<<(31-(c*8))
+#else
+#define CHARTSTMASK(c) 1<<(c*8)
+#endif
+       .text
+       .thumb
+
+@ ---------------------------------------------------------------------------
+       .thumb_func
+ENTRY(memchr)
+       .p2align 4,,15
+       @ r0 = start of memory to scan
+       @ r1 = character to look for
+       @ r2 = length
+       @ returns r0 = pointer to character or NULL if not found
+       and     r1,r1,#0xff     @ Don't think we can trust the caller to actually pass a char
+
+       cmp     r2,#16          @ If it's short don't bother with anything clever
+       blt     20f
+
+       tst     r0, #7          @ If it's already aligned skip the next bit
+       beq     10f
+
+       @ Work up to an aligned point
+5:
+       ldrb    r3, [r0],#1
+       subs    r2, r2, #1
+       cmp     r3, r1
+       beq     50f             @ If it matches exit found
+       tst     r0, #7
+       bne     5b              @ If not aligned yet then do next byte
+
+10:
+       @ At this point, we are aligned, we know we have at least 8 bytes to work with
+       push    {r4,r5,r6,r7}
+       orr     r1, r1, r1, lsl #8      @ expand the match word across to all bytes
+       orr     r1, r1, r1, lsl #16
+       bic     r4, r2, #7      @ Number of double words to work with
+       mvns    r7, #0          @ all F's
+       movs    r3, #0
+
+15:
+       ldrd    r5,r6,[r0],#8
+       subs    r4, r4, #8
+       eor     r5,r5, r1       @ Get it so that r5,r6 have 00's where the bytes match the target
+       eor     r6,r6, r1
+       uadd8   r5, r5, r7      @ Parallel add 0xff - sets the GE bits for anything that wasn't 0
+       sel     r5, r3, r7      @ bytes are 00 for none-00 bytes, or ff for 00 bytes - NOTE INVERSION
+       uadd8   r6, r6, r7      @ Parallel add 0xff - sets the GE bits for anything that wasn't 0
+       sel     r6, r5, r7      @ chained....bytes are 00 for none-00 bytes, or ff for 00 bytes - NOTE INVERSION
+       cbnz    r6, 60f
+       bne     15b             @ (Flags from the subs above) If not run out of bytes then go around again
+
+       pop     {r4,r5,r6,r7}
+       and     r1,r1,#0xff     @ Get r1 back to a single character from the expansion above
+       and     r2,r2,#7        @ Leave the count remaining as the number after the double words have been done
+
+20:
+       cbz     r2, 40f         @ 0 length or hit the end already then not found
+
+21:  @ Post aligned section, or just a short call
+       ldrb    r3,[r0],#1
+       subs    r2,r2,#1
+       eor     r3,r3,r1        @ r3 = 0 if match - doesn't break flags from sub
+       cbz     r3, 50f
+       bne     21b             @ on r2 flags
+
+40:
+       movs    r0,#0           @ not found
+       bx      lr
+
+50:
+       subs    r0,r0,#1        @ found
+       bx      lr
+
+60:  @ We're here because the fast path found a hit - now we have to track down exactly which word it was
+       @ r0 points to the start of the double word after the one that was tested
+       @ r5 has the 00/ff pattern for the first word, r6 has the chained value
+       cmp     r5, #0
+       itte    eq
+       moveq   r5, r6          @ the end is in the 2nd word
+       subeq   r0,r0,#3        @ Points to 2nd byte of 2nd word
+       subne   r0,r0,#7        @ or 2nd byte of 1st word
+
+       @ r0 currently points to the 3rd byte of the word containing the hit
+       tst     r5, # CHARTSTMASK(0)    @ 1st character
+       bne     61f
+       adds    r0,r0,#1
+       tst     r5, # CHARTSTMASK(1)    @ 2nd character
+       ittt    eq
+       addeq   r0,r0,#1
+       tsteq   r5, # (3<<15)           @ 2nd & 3rd character
+       @ If not the 3rd must be the last one
+       addeq   r0,r0,#1
+
+61:
+       pop     {r4,r5,r6,r7}
+       subs    r0,r0,#1
+       bx      lr
+END(memchr)
index e49d6d2..016c882 100644 (file)
@@ -1,4 +1,5 @@
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memchr.S \
     arch-arm/generic/bionic/memcmp.S \
     arch-arm/generic/bionic/memcpy.S \
     arch-arm/generic/bionic/memset.S \
index 7580332..5f5b414 100644 (file)
@@ -23,6 +23,7 @@ libc_bionic_src_files_arm += \
     arch-arm/cortex-a15/bionic/strlen.S \
 
 libc_bionic_src_files_arm += \
+    arch-arm/generic/bionic/memchr.S \
     arch-arm/generic/bionic/memcmp.S \