mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-20 16:01:10 +08:00
* libc/machine/aarch64/strcpy.S: New file.
* libc/machine/aarch64/strcpy-stub.S: New file. * libc/machine/aarch64/Makefile.am (lib_a_SOURCES): Add new files. * libc/machine/aarch64/Makefile.in: Regenerate.
This commit is contained in:
parent
9b41831e4c
commit
fbb8f1a2c7
@ -1,3 +1,10 @@
|
||||
2014-11-10 Richard Earnshaw <rearnsha@arm.com>
|
||||
|
||||
* libc/machine/aarch64/strcpy.S: New file.
|
||||
* libc/machine/aarch64/strcpy-stub.S: New file.
|
||||
* libc/machine/aarch64/Makefile.am (lib_a_SOURCES): Add new files.
|
||||
* libc/machine/aarch64/Makefile.in: Regenerate.
|
||||
|
||||
2014-11-06 Joel Sherrill <joel.sherrill@oarcorp.com>
|
||||
|
||||
* configure.in: Add autoconf test to determine size of uintptr_t.
|
||||
|
@ -26,6 +26,8 @@ lib_a_SOURCES += strchrnul-stub.c
|
||||
lib_a_SOURCES += strchrnul.S
|
||||
lib_a_SOURCES += strcmp-stub.c
|
||||
lib_a_SOURCES += strcmp.S
|
||||
lib_a_SOURCES += strcpy-stub.c
|
||||
lib_a_SOURCES += strcpy.S
|
||||
lib_a_SOURCES += strlen-stub.c
|
||||
lib_a_SOURCES += strlen.S
|
||||
lib_a_SOURCES += strncmp-stub.c
|
||||
|
@ -77,7 +77,8 @@ am_lib_a_OBJECTS = lib_a-memchr-stub.$(OBJEXT) lib_a-memchr.$(OBJEXT) \
|
||||
lib_a-setjmp.$(OBJEXT) lib_a-strchr-stub.$(OBJEXT) \
|
||||
lib_a-strchr.$(OBJEXT) lib_a-strchrnul-stub.$(OBJEXT) \
|
||||
lib_a-strchrnul.$(OBJEXT) lib_a-strcmp-stub.$(OBJEXT) \
|
||||
lib_a-strcmp.$(OBJEXT) lib_a-strlen-stub.$(OBJEXT) \
|
||||
lib_a-strcmp.$(OBJEXT) lib_a-strcpy-stub.$(OBJEXT) \
|
||||
lib_a-strcpy.$(OBJEXT) lib_a-strlen-stub.$(OBJEXT) \
|
||||
lib_a-strlen.$(OBJEXT) lib_a-strncmp-stub.$(OBJEXT) \
|
||||
lib_a-strncmp.$(OBJEXT) lib_a-strnlen-stub.$(OBJEXT) \
|
||||
lib_a-strnlen.$(OBJEXT)
|
||||
@ -209,8 +210,9 @@ noinst_LIBRARIES = lib.a
|
||||
lib_a_SOURCES = memchr-stub.c memchr.S memcmp-stub.c memcmp.S \
|
||||
memcpy-stub.c memcpy.S memmove-stub.c memmove.S memset-stub.c \
|
||||
memset.S setjmp.S strchr-stub.c strchr.S strchrnul-stub.c \
|
||||
strchrnul.S strcmp-stub.c strcmp.S strlen-stub.c strlen.S \
|
||||
strncmp-stub.c strncmp.S strnlen-stub.c strnlen.S
|
||||
strchrnul.S strcmp-stub.c strcmp.S strcpy-stub.c strcpy.S \
|
||||
strlen-stub.c strlen.S strncmp-stub.c strncmp.S strnlen-stub.c \
|
||||
strnlen.S
|
||||
lib_a_CCASFLAGS = $(AM_CCASFLAGS)
|
||||
lib_a_CFLAGS = $(AM_CFLAGS)
|
||||
ACLOCAL_AMFLAGS = -I ../../.. -I ../../../..
|
||||
@ -327,6 +329,12 @@ lib_a-strcmp.o: strcmp.S
|
||||
lib_a-strcmp.obj: strcmp.S
|
||||
$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-strcmp.obj `if test -f 'strcmp.S'; then $(CYGPATH_W) 'strcmp.S'; else $(CYGPATH_W) '$(srcdir)/strcmp.S'; fi`
|
||||
|
||||
lib_a-strcpy.o: strcpy.S
|
||||
$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-strcpy.o `test -f 'strcpy.S' || echo '$(srcdir)/'`strcpy.S
|
||||
|
||||
lib_a-strcpy.obj: strcpy.S
|
||||
$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-strcpy.obj `if test -f 'strcpy.S'; then $(CYGPATH_W) 'strcpy.S'; else $(CYGPATH_W) '$(srcdir)/strcpy.S'; fi`
|
||||
|
||||
lib_a-strlen.o: strlen.S
|
||||
$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-strlen.o `test -f 'strlen.S' || echo '$(srcdir)/'`strlen.S
|
||||
|
||||
@ -399,6 +407,12 @@ lib_a-strcmp-stub.o: strcmp-stub.c
|
||||
lib_a-strcmp-stub.obj: strcmp-stub.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strcmp-stub.obj `if test -f 'strcmp-stub.c'; then $(CYGPATH_W) 'strcmp-stub.c'; else $(CYGPATH_W) '$(srcdir)/strcmp-stub.c'; fi`
|
||||
|
||||
lib_a-strcpy-stub.o: strcpy-stub.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strcpy-stub.o `test -f 'strcpy-stub.c' || echo '$(srcdir)/'`strcpy-stub.c
|
||||
|
||||
lib_a-strcpy-stub.obj: strcpy-stub.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strcpy-stub.obj `if test -f 'strcpy-stub.c'; then $(CYGPATH_W) 'strcpy-stub.c'; else $(CYGPATH_W) '$(srcdir)/strcpy-stub.c'; fi`
|
||||
|
||||
lib_a-strlen-stub.o: strlen-stub.c
|
||||
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strlen-stub.o `test -f 'strlen-stub.c' || echo '$(srcdir)/'`strlen-stub.c
|
||||
|
||||
|
31
newlib/libc/machine/aarch64/strcpy-stub.c
Normal file
31
newlib/libc/machine/aarch64/strcpy-stub.c
Normal file
@ -0,0 +1,31 @@
|
||||
/* Copyright (c) 2014, ARM 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 the company 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. */
|
||||
|
||||
#if (defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED))
|
||||
# include "../../string/strcpy.c"
|
||||
#else
|
||||
/* See strcpy.S */
|
||||
#endif
|
224
newlib/libc/machine/aarch64/strcpy.S
Normal file
224
newlib/libc/machine/aarch64/strcpy.S
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
strcpy - copy a string.
|
||||
|
||||
Copyright (c) 2013, 2014, ARM 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 the company 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. */
|
||||
|
||||
#if (defined (__OPTIMIZE_SIZE__) || defined (PREFER_SIZE_OVER_SPEED))
|
||||
/* See strchr-stub.c */
|
||||
#else
|
||||
|
||||
/* Assumptions:
|
||||
*
|
||||
* ARMv8-a, AArch64, unaligned accesses
|
||||
*/
|
||||
|
||||
/* Arguments and results. */
|
||||
#define dstin x0
|
||||
#define src x1
|
||||
|
||||
/* Locals and temporaries. */
|
||||
#define dst x2
|
||||
#define data1 x3
|
||||
#define data1w w3
|
||||
#define data2 x4
|
||||
#define has_nul1 x5
|
||||
#define has_nul2 x6
|
||||
#define tmp1 x7
|
||||
#define tmp2 x8
|
||||
#define tmp3 x9
|
||||
#define tmp4 x10
|
||||
#define zeroones x11
|
||||
|
||||
.macro def_fn f p2align=0
|
||||
.text
|
||||
.p2align \p2align
|
||||
.global \f
|
||||
.type \f, %function
|
||||
\f:
|
||||
.endm
|
||||
|
||||
#define REP8_01 0x0101010101010101
|
||||
#define REP8_7f 0x7f7f7f7f7f7f7f7f
|
||||
#define REP8_80 0x8080808080808080
|
||||
|
||||
/* Start of critial section -- keep to one 64Byte cache line. */
|
||||
def_fn strcpy p2align=6
|
||||
mov zeroones, #REP8_01
|
||||
mov dst, dstin
|
||||
ands tmp1, src, #15
|
||||
b.ne .Lmisaligned
|
||||
/* NUL detection works on the principle that (X - 1) & (~X) & 0x80
|
||||
(=> (X - 1) & ~(X | 0x7f)) is non-zero iff a byte is zero, and
|
||||
can be done in parallel across the entire word. */
|
||||
/* The inner loop deals with two Dwords at a time. This has a
|
||||
slightly higher start-up cost, but we should win quite quickly,
|
||||
especially on cores with a high number of issue slots per
|
||||
cycle, as we get much better parallelism out of the operations. */
|
||||
b .Lfirst_pass
|
||||
.Lmain_loop:
|
||||
stp data1, data2, [dst], #16
|
||||
.Lstartloop_fast:
|
||||
ldp data1, data2, [src], #16
|
||||
sub tmp1, data1, zeroones
|
||||
orr tmp2, data1, #REP8_7f
|
||||
sub tmp3, data2, zeroones
|
||||
orr tmp4, data2, #REP8_7f
|
||||
bic has_nul1, tmp1, tmp2
|
||||
bics has_nul2, tmp3, tmp4
|
||||
ccmp has_nul1, #0, #0, eq /* NZCV = 0000 */
|
||||
b.eq .Lmain_loop
|
||||
/* End of critical section -- keep to one 64Byte cache line. */
|
||||
|
||||
cbnz has_nul1, .Lnul_in_data1_fast
|
||||
.Lnul_in_data2_fast:
|
||||
str data1, [dst], #8
|
||||
.Lnul_in_data2_fast_after_d1:
|
||||
/* For a NUL in data2, we always know that we've moved at least 8
|
||||
bytes, so no need for a slow path. */
|
||||
#ifdef __AARCH64EB__
|
||||
/* For big-endian only, carry propagation means we can't trust
|
||||
the MSB of the syndrome value calculated above (the byte
|
||||
sequence 01 00 will generate a syndrome of 80 80 rather than
|
||||
00 80). We get around this by byte-swapping the data and
|
||||
re-calculating. */
|
||||
rev data2, data2
|
||||
sub tmp1, data2, zeroones
|
||||
orr tmp2, data2, #REP8_7f
|
||||
bic has_nul2, tmp1, tmp2
|
||||
#endif
|
||||
rev has_nul2, has_nul2
|
||||
sub src, src, #(8+7)
|
||||
clz has_nul2, has_nul2
|
||||
lsr has_nul2, has_nul2, #3 /* Bits to bytes. */
|
||||
sub dst, dst, #7
|
||||
ldr data2, [src, has_nul2]
|
||||
str data2, [dst, has_nul2]
|
||||
ret
|
||||
|
||||
.Lnul_in_data1_fast:
|
||||
/* Since we know we've already copied at least 8 bytes, we can
|
||||
safely handle the tail with one misaligned dword move. To do this
|
||||
we calculate the location of the trailing NUL byte and go seven
|
||||
bytes back from that. */
|
||||
#ifdef __AARCH64EB__
|
||||
/* For big-endian only, carry propagation means we can't trust
|
||||
the MSB of the syndrome value calculated above (the byte
|
||||
sequence 01 00 will generate a syndrome of 80 80 rather than
|
||||
00 80). We get around this by byte-swapping the data and
|
||||
re-calculating. */
|
||||
rev data1, data1
|
||||
sub tmp1, data1, zeroones
|
||||
orr tmp2, data1, #REP8_7f
|
||||
bic has_nul1, tmp1, tmp2
|
||||
#endif
|
||||
rev has_nul1, has_nul1
|
||||
sub src, src, #(16+7)
|
||||
clz has_nul1, has_nul1
|
||||
lsr has_nul1, has_nul1, #3 /* Bits to bytes. */
|
||||
sub dst, dst, #7
|
||||
ldr data1, [src, has_nul1]
|
||||
str data1, [dst, has_nul1]
|
||||
ret
|
||||
|
||||
.Lfirst_pass:
|
||||
ldp data1, data2, [src], #16
|
||||
sub tmp1, data1, zeroones
|
||||
orr tmp2, data1, #REP8_7f
|
||||
sub tmp3, data2, zeroones
|
||||
orr tmp4, data2, #REP8_7f
|
||||
bic has_nul1, tmp1, tmp2
|
||||
bics has_nul2, tmp3, tmp4
|
||||
ccmp has_nul1, #0, #0, eq /* NZCV = 0000 */
|
||||
b.eq .Lmain_loop
|
||||
|
||||
cbz has_nul1, .Lnul_in_data2_fast
|
||||
.Lnul_in_data1:
|
||||
/* Slow path. We can't be sure we've moved at least 8 bytes, so
|
||||
fall back to a slow byte-by byte store of the bits already
|
||||
loaded.
|
||||
|
||||
The worst case when coming through this path is that we've had
|
||||
to copy seven individual bytes to get to alignment and we then
|
||||
have to copy another seven (eight for big-endian) again here.
|
||||
We could try to detect that case (and any case where more than
|
||||
eight bytes have to be copied), but it really doesn't seem
|
||||
worth it. */
|
||||
#ifdef __AARCH64EB__
|
||||
rev data1, data1
|
||||
#else
|
||||
/* On little-endian, we can easily check if the NULL byte was
|
||||
in the last byte of the Dword. For big-endian we'd have to
|
||||
recalculate the syndrome, which is unlikely to be worth it. */
|
||||
lsl has_nul1, has_nul1, #8
|
||||
cbnz has_nul1, 1f
|
||||
str data1, [dst]
|
||||
ret
|
||||
#endif
|
||||
1:
|
||||
strb data1w, [dst], #1
|
||||
tst data1, #0xff
|
||||
lsr data1, data1, #8
|
||||
b.ne 1b
|
||||
.Ldone:
|
||||
ret
|
||||
|
||||
.Lmisaligned:
|
||||
cmp tmp1, #8
|
||||
b.ge 2f
|
||||
/* There's at least one Dword before we reach alignment, so we can
|
||||
deal with that efficiently. */
|
||||
ldr data1, [src]
|
||||
bic src, src, #15
|
||||
sub tmp3, data1, zeroones
|
||||
orr tmp4, data1, #REP8_7f
|
||||
bics has_nul1, tmp3, tmp4
|
||||
b.ne .Lnul_in_data1
|
||||
str data1, [dst], #8
|
||||
ldr data2, [src, #8]
|
||||
add src, src, #16
|
||||
sub dst, dst, tmp1
|
||||
sub tmp3, data2, zeroones
|
||||
orr tmp4, data2, #REP8_7f
|
||||
bics has_nul2, tmp3, tmp4
|
||||
b.ne .Lnul_in_data2_fast_after_d1
|
||||
str data2, [dst], #8
|
||||
/* We can by-pass the first-pass version of the loop in this case
|
||||
since we know that at least 8 bytes have already been copied. */
|
||||
b .Lstartloop_fast
|
||||
|
||||
2:
|
||||
sub tmp1, tmp1, #16
|
||||
3:
|
||||
ldrb data1w, [src], #1
|
||||
strb data1w, [dst], #1
|
||||
cbz data1w, .Ldone
|
||||
add tmp1, tmp1, #1
|
||||
cbnz tmp1, 3b
|
||||
b .Lfirst_pass
|
||||
|
||||
.size strcpy, . - strcpy
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user