123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /* Copyright (C) 2014-2019 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library. If not, see
- <http://www.gnu.org/licenses/>. */
- #ifdef ANDROID_CHANGES
- # include "machine/asm.h"
- # include "machine/regdef.h"
- #elif _LIBC
- # include <sysdep.h>
- # include <regdef.h>
- # include <sys/asm.h>
- #elif defined _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
|