2014-10-08 Steve Ellcey <sellcey@mips.com>
* newlib/libc/machine/mips/strcmp.c: Remove. * newlib/libc/machine/mips/strcmp.S: New. * newlib/libc/machine/mips/Makefile.am (lib_a_SOURCES): Replace strcmp.c with strcmp.S * newlib/libc/machine/mips/Makefile.in: Regenerate.
This commit is contained in:
		| @@ -1,3 +1,11 @@ | ||||
| 2014-10-08  Steve Ellcey  <sellcey@mips.com> | ||||
|  | ||||
| 	* newlib/libc/machine/mips/strcmp.c: Remove. | ||||
| 	* newlib/libc/machine/mips/strcmp.S: New. | ||||
| 	* newlib/libc/machine/mips/Makefile.am (lib_a_SOURCES): | ||||
| 	Replace strcmp.c with strcmp.S | ||||
| 	* newlib/libc/machine/mips/Makefile.in: Regenerate. | ||||
|  | ||||
| 2014-10-08 Corinna Vinschen  <vinschen@redhat.com> | ||||
|  | ||||
| 	* libc/include/string.h (ffsl): Declare as GNU function. | ||||
|   | ||||
| @@ -8,7 +8,7 @@ AM_CCASFLAGS = $(INCLUDES) | ||||
|  | ||||
| noinst_LIBRARIES = lib.a | ||||
|  | ||||
| lib_a_SOURCES = setjmp.S strlen.c strcmp.c strncpy.c memset.S memcpy.S | ||||
| lib_a_SOURCES = setjmp.S strlen.c strcmp.S strncpy.c memset.S memcpy.S | ||||
| lib_a_CCASFLAGS=$(AM_CCASFLAGS) -D_COMPILING_NEWLIB | ||||
| lib_a_CFLAGS=$(AM_CFLAGS) -D_COMPILING_NEWLIB | ||||
|  | ||||
|   | ||||
| @@ -197,7 +197,7 @@ AUTOMAKE_OPTIONS = cygnus | ||||
| INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) | ||||
| AM_CCASFLAGS = $(INCLUDES) | ||||
| noinst_LIBRARIES = lib.a | ||||
| lib_a_SOURCES = setjmp.S strlen.c strcmp.c strncpy.c memset.S memcpy.S | ||||
| lib_a_SOURCES = setjmp.S strlen.c strcmp.S strncpy.c memset.S memcpy.S | ||||
| lib_a_CCASFLAGS = $(AM_CCASFLAGS) -D_COMPILING_NEWLIB | ||||
| lib_a_CFLAGS = $(AM_CFLAGS) -D_COMPILING_NEWLIB | ||||
| ACLOCAL_AMFLAGS = -I ../../.. -I ../../../.. | ||||
| @@ -266,6 +266,12 @@ lib_a-setjmp.o: setjmp.S | ||||
| lib_a-setjmp.obj: setjmp.S | ||||
| 	$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-setjmp.obj `if test -f 'setjmp.S'; then $(CYGPATH_W) 'setjmp.S'; else $(CYGPATH_W) '$(srcdir)/setjmp.S'; fi` | ||||
|  | ||||
| lib_a-strcmp.o: strcmp.S | ||||
| 	$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-strcmp.o `test -f 'strcmp.S' || echo '$(srcdir)/'`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-memset.o: memset.S | ||||
| 	$(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-memset.o `test -f 'memset.S' || echo '$(srcdir)/'`memset.S | ||||
|  | ||||
| @@ -290,12 +296,6 @@ lib_a-strlen.o: strlen.c | ||||
| lib_a-strlen.obj: strlen.c | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strlen.obj `if test -f 'strlen.c'; then $(CYGPATH_W) 'strlen.c'; else $(CYGPATH_W) '$(srcdir)/strlen.c'; fi` | ||||
|  | ||||
| lib_a-strcmp.o: strcmp.c | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strcmp.o `test -f 'strcmp.c' || echo '$(srcdir)/'`strcmp.c | ||||
|  | ||||
| lib_a-strcmp.obj: strcmp.c | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strcmp.obj `if test -f 'strcmp.c'; then $(CYGPATH_W) 'strcmp.c'; else $(CYGPATH_W) '$(srcdir)/strcmp.c'; fi` | ||||
|  | ||||
| lib_a-strncpy.o: strncpy.c | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-strncpy.o `test -f 'strncpy.c' || echo '$(srcdir)/'`strncpy.c | ||||
|  | ||||
|   | ||||
							
								
								
									
										261
									
								
								newlib/libc/machine/mips/strcmp.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										261
									
								
								newlib/libc/machine/mips/strcmp.S
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,261 @@ | ||||
| /* | ||||
|  * Copyright (c) 2014 | ||||
|  *      Imagination Technologies Limited. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions | ||||
|  * are met: | ||||
|  * 1. Redistributions of source code must retain the above copyright | ||||
|  *    notice, this list of conditions and the following disclaimer. | ||||
|  * 2. 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. | ||||
|  * 3. Neither the name of the MIPS Technologies, Inc., 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 IMAGINATION TECHNOLOGIES LIMITED ``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 IMAGINATION TECHNOLOGIES LIMITED 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. | ||||
|  */ | ||||
|  | ||||
| #ifdef ANDROID_CHANGES | ||||
| # include "machine/asm.h" | ||||
| # include "machine/regdef.h" | ||||
| #elif _LIBC | ||||
| # include <sysdep.h> | ||||
| # include <regdef.h> | ||||
| # include <sys/asm.h> | ||||
| #elif _COMPILING_NEWLIB | ||||
| # include "machine/asm.h" | ||||
| # include "machine/regdef.h" | ||||
| #else | ||||
| # include <regdef.h> | ||||
| # include <sys/asm.h> | ||||
| #endif | ||||
|  | ||||
| /* Technically strcmp should not read past the end of the strings being | ||||
|    compared.  We will read a full word that may contain excess bits beyond | ||||
|    the NULL string terminator but unless ENABLE_READAHEAD is set, we will not | ||||
|    read the next word after the end of string.  Setting ENABLE_READAHEAD will | ||||
|    improve performance but is technically illegal based on the definition of | ||||
|    strcmp.  */ | ||||
| #ifdef ENABLE_READAHEAD | ||||
| # define DELAY_READ | ||||
| #else | ||||
| # define DELAY_READ nop | ||||
| #endif | ||||
|  | ||||
| /* Testing on a little endian machine showed using CLZ was a | ||||
|    performance loss, so we are not turning it on by default.  */ | ||||
| #if defined(ENABLE_CLZ) && (__mips_isa_rev > 1) | ||||
| # define USE_CLZ | ||||
| #endif | ||||
|  | ||||
| /* Some asm.h files do not have the L macro definition.  */ | ||||
| #ifndef L | ||||
| # if _MIPS_SIM == _ABIO32 | ||||
| #  define L(label) $L ## label | ||||
| # else | ||||
| #  define L(label) .L ## label | ||||
| # endif | ||||
| #endif | ||||
|  | ||||
| /* Some asm.h files do not have the PTR_ADDIU macro definition.  */ | ||||
| #ifndef PTR_ADDIU | ||||
| # ifdef USE_DOUBLE | ||||
| #  define PTR_ADDIU       daddiu | ||||
| # else | ||||
| #  define PTR_ADDIU       addiu | ||||
| # endif | ||||
| #endif | ||||
|  | ||||
| /* Allow the routine to be named something else if desired.  */ | ||||
| #ifndef STRCMP_NAME | ||||
| # define STRCMP_NAME strcmp | ||||
| #endif | ||||
|  | ||||
| #ifdef ANDROID_CHANGES | ||||
| LEAF(STRCMP_NAME, 0) | ||||
| #else | ||||
| LEAF(STRCMP_NAME) | ||||
| #endif | ||||
| 	.set	nomips16 | ||||
| 	.set	noreorder | ||||
|  | ||||
| 	or	t0, a0, a1 | ||||
| 	andi	t0,0x3 | ||||
| 	bne	t0, zero, L(byteloop) | ||||
|  | ||||
| /* Both strings are 4 byte aligned at this point.  */ | ||||
|  | ||||
| 	lui	t8, 0x0101 | ||||
| 	ori	t8, t8, 0x0101 | ||||
| 	lui	t9, 0x7f7f | ||||
| 	ori	t9, 0x7f7f | ||||
|  | ||||
| #define STRCMP32(OFFSET) \ | ||||
| 	lw	v0, OFFSET(a0); \ | ||||
| 	lw	v1, OFFSET(a1); \ | ||||
| 	subu	t0, v0, t8; \ | ||||
| 	bne	v0, v1, L(worddiff); \ | ||||
| 	nor	t1, v0, t9; \ | ||||
| 	and	t0, t0, t1; \ | ||||
| 	bne	t0, zero, L(returnzero) | ||||
|  | ||||
| L(wordloop): | ||||
| 	STRCMP32(0) | ||||
| 	DELAY_READ | ||||
| 	STRCMP32(4) | ||||
| 	DELAY_READ | ||||
| 	STRCMP32(8) | ||||
| 	DELAY_READ | ||||
| 	STRCMP32(12) | ||||
| 	DELAY_READ | ||||
| 	STRCMP32(16) | ||||
| 	DELAY_READ | ||||
| 	STRCMP32(20) | ||||
| 	DELAY_READ | ||||
| 	STRCMP32(24) | ||||
| 	DELAY_READ | ||||
| 	STRCMP32(28) | ||||
| 	PTR_ADDIU a0, a0, 32 | ||||
| 	b	L(wordloop) | ||||
| 	PTR_ADDIU a1, a1, 32 | ||||
|  | ||||
| L(returnzero): | ||||
| 	j	ra | ||||
| 	move	v0, zero | ||||
|  | ||||
| L(worddiff): | ||||
| #ifdef USE_CLZ | ||||
| 	subu	t0, v0, t8 | ||||
| 	nor	t1, v0, t9 | ||||
| 	and	t1, t0, t1 | ||||
| 	xor	t0, v0, v1 | ||||
| 	or	t0, t0, t1 | ||||
| # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||||
| 	wsbh	t0, t0 | ||||
| 	rotr	t0, t0, 16 | ||||
| # endif | ||||
| 	clz	t1, t0 | ||||
| 	and	t1, 0xf8 | ||||
| # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | ||||
| 	neg	t1 | ||||
| 	addu	t1, 24 | ||||
| # endif | ||||
| 	rotrv	v0, v0, t1 | ||||
| 	rotrv	v1, v1, t1 | ||||
| 	and	v0, v0, 0xff | ||||
| 	and	v1, v1, 0xff | ||||
| 	j	ra | ||||
| 	subu	v0, v0, v1 | ||||
| #else /* USE_CLZ */ | ||||
| # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ | ||||
| 	andi	t0, v0, 0xff | ||||
| 	beq	t0, zero, L(wexit01) | ||||
| 	andi	t1, v1, 0xff | ||||
| 	bne	t0, t1, L(wexit01) | ||||
|  | ||||
| 	srl	t8, v0, 8 | ||||
| 	srl	t9, v1, 8 | ||||
| 	andi	t8, t8, 0xff | ||||
| 	beq	t8, zero, L(wexit89) | ||||
| 	andi	t9, t9, 0xff | ||||
| 	bne	t8, t9, L(wexit89) | ||||
|  | ||||
| 	srl	t0, v0, 16 | ||||
| 	srl	t1, v1, 16 | ||||
| 	andi	t0, t0, 0xff | ||||
| 	beq	t0, zero, L(wexit01) | ||||
| 	andi	t1, t1, 0xff | ||||
| 	bne	t0, t1, L(wexit01) | ||||
|  | ||||
| 	srl	t8, v0, 24 | ||||
| 	srl	t9, v1, 24 | ||||
| # else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ | ||||
| 	srl	t0, v0, 24 | ||||
| 	beq	t0, zero, L(wexit01) | ||||
| 	srl	t1, v1, 24 | ||||
| 	bne	t0, t1, L(wexit01) | ||||
|  | ||||
| 	srl	t8, v0, 16 | ||||
| 	srl	t9, v1, 16 | ||||
| 	andi	t8, t8, 0xff | ||||
| 	beq	t8, zero, L(wexit89) | ||||
| 	andi	t9, t9, 0xff | ||||
| 	bne	t8, t9, L(wexit89) | ||||
|  | ||||
| 	srl	t0, v0, 8 | ||||
| 	srl	t1, v1, 8 | ||||
| 	andi	t0, t0, 0xff | ||||
| 	beq	t0, zero, L(wexit01) | ||||
| 	andi	t1, t1, 0xff | ||||
| 	bne	t0, t1, L(wexit01) | ||||
|  | ||||
| 	andi	t8, v0, 0xff | ||||
| 	andi	t9, v1, 0xff | ||||
| # endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ | ||||
|  | ||||
| L(wexit89): | ||||
| 	j	ra | ||||
| 	subu	v0, t8, t9 | ||||
| L(wexit01): | ||||
| 	j	ra | ||||
| 	subu	v0, t0, t1 | ||||
| #endif /* USE_CLZ */ | ||||
|  | ||||
| /* It might seem better to do the 'beq' instruction between the two 'lbu' | ||||
|    instructions so that the nop is not needed but testing showed that this | ||||
|    code is actually faster (based on glibc strcmp test).  */ | ||||
| #define BYTECMP01(OFFSET) \ | ||||
| 	lbu	v0, OFFSET(a0); \ | ||||
| 	lbu	v1, OFFSET(a1); \ | ||||
| 	beq	v0, zero, L(bexit01); \ | ||||
| 	nop; \ | ||||
| 	bne	v0, v1, L(bexit01) | ||||
|  | ||||
| #define BYTECMP89(OFFSET) \ | ||||
| 	lbu	t8, OFFSET(a0); \ | ||||
| 	lbu	t9, OFFSET(a1); \ | ||||
| 	beq	t8, zero, L(bexit89); \ | ||||
| 	nop;	\ | ||||
| 	bne	t8, t9, L(bexit89) | ||||
|  | ||||
| L(byteloop): | ||||
| 	BYTECMP01(0) | ||||
| 	BYTECMP89(1) | ||||
| 	BYTECMP01(2) | ||||
| 	BYTECMP89(3) | ||||
| 	BYTECMP01(4) | ||||
| 	BYTECMP89(5) | ||||
| 	BYTECMP01(6) | ||||
| 	BYTECMP89(7) | ||||
| 	PTR_ADDIU a0, a0, 8 | ||||
| 	b	L(byteloop) | ||||
| 	PTR_ADDIU a1, a1, 8 | ||||
|  | ||||
| L(bexit01): | ||||
| 	j	ra | ||||
| 	subu	v0, v0, v1 | ||||
| L(bexit89): | ||||
| 	j	ra | ||||
| 	subu	v0, t8, t9 | ||||
|  | ||||
| 	.set	at | ||||
| 	.set	reorder | ||||
|  | ||||
| END(STRCMP_NAME) | ||||
| #ifndef ANDROID_CHANGES | ||||
| # ifdef _LIBC | ||||
| libc_hidden_builtin_def (STRCMP_NAME) | ||||
| # endif | ||||
| #endif | ||||
| @@ -1,71 +0,0 @@ | ||||
| /* | ||||
|  * strcmp.c -- strcmp function.  On at least some MIPS chips, a strcmp that is | ||||
|  * unrolled twice is faster than the 'optimized' C version in newlib. | ||||
|  * | ||||
|  * Copyright (c) 2001 Red Hat, Inc. | ||||
|  * | ||||
|  * The authors hereby grant permission to use, copy, modify, distribute, | ||||
|  * and license this software and its documentation for any purpose, provided | ||||
|  * that existing copyright notices are retained in all copies and that this | ||||
|  * notice is included verbatim in any distributions. No written agreement, | ||||
|  * license, or royalty fee is required for any of the authorized uses. | ||||
|  * Modifications to this software may be copyrighted by their authors | ||||
|  * and need not follow the licensing terms described here, provided that | ||||
|  * the new terms are clearly indicated on the first page of each file where | ||||
|  * they apply.  */ | ||||
|  | ||||
| #include <stddef.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| int | ||||
| strcmp (const char *s1, const char *s2) | ||||
| {  | ||||
|   unsigned const char *us1 = (unsigned const char *)s1; | ||||
|   unsigned const char *us2 = (unsigned const char *)s2; | ||||
|   int c1a, c1b; | ||||
|   int c2a, c2b; | ||||
|  | ||||
|   /* If the pointers aren't both aligned to a 16-byte boundary, do the | ||||
|      comparison byte by byte, so that we don't get an invalid page fault if we | ||||
|      are comparing a string whose null byte is at the last byte on the last | ||||
|      valid page.  */ | ||||
|   if (((((long)us1) | ((long)us2)) & 1) == 0) | ||||
|     { | ||||
|       c1a = *us1; | ||||
|       for (;;) | ||||
| 	{ | ||||
| 	  c1b = *us2; | ||||
| 	  us1 += 2; | ||||
| 	  if (c1a == '\0') | ||||
| 	    goto ret1; | ||||
|  | ||||
| 	  c2a = us1[-1]; | ||||
| 	  if (c1a != c1b) | ||||
| 	    goto ret1; | ||||
|  | ||||
| 	  c2b = us2[1]; | ||||
| 	  us2 += 2; | ||||
| 	  if (c2a == '\0') | ||||
| 	    break; | ||||
|  | ||||
| 	  c1a = *us1; | ||||
| 	  if (c2a != c2b) | ||||
| 	    break; | ||||
| 	} | ||||
|  | ||||
|       return c2a - c2b; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       do | ||||
| 	{ | ||||
| 	  c1a = *us1++; | ||||
| 	  c1b = *us2++; | ||||
| 	} | ||||
|       while (c1a != '\0' && c1a == c1b); | ||||
|     } | ||||
|  | ||||
|  ret1: | ||||
|   return c1a - c1b; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user