|
Packit |
6c4009 |
/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
|
|
Packit |
6c4009 |
This file is part of the GNU C Library.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit |
6c4009 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License as published by the Free Software Foundation; either
|
|
Packit |
6c4009 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit |
6c4009 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6c4009 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6c4009 |
Lesser General Public License for more details.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License along with the GNU C Library. If not, see
|
|
Packit |
6c4009 |
<http://www.gnu.org/licenses/>. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#ifdef ANDROID_CHANGES
|
|
Packit |
6c4009 |
# include "machine/asm.h"
|
|
Packit |
6c4009 |
# include "machine/regdef.h"
|
|
Packit |
6c4009 |
#elif _LIBC
|
|
Packit |
6c4009 |
# include <sysdep.h>
|
|
Packit |
6c4009 |
# include <regdef.h>
|
|
Packit |
6c4009 |
# include <sys/asm.h>
|
|
Packit |
6c4009 |
#elif defined _COMPILING_NEWLIB
|
|
Packit |
6c4009 |
# include "machine/asm.h"
|
|
Packit |
6c4009 |
# include "machine/regdef.h"
|
|
Packit |
6c4009 |
#else
|
|
Packit |
6c4009 |
# include <regdef.h>
|
|
Packit |
6c4009 |
# include <sys/asm.h>
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Technically strcmp should not read past the end of the strings being
|
|
Packit |
6c4009 |
compared. We will read a full word that may contain excess bits beyond
|
|
Packit |
6c4009 |
the NULL string terminator but unless ENABLE_READAHEAD is set, we will not
|
|
Packit |
6c4009 |
read the next word after the end of string. Setting ENABLE_READAHEAD will
|
|
Packit |
6c4009 |
improve performance but is technically illegal based on the definition of
|
|
Packit |
6c4009 |
strcmp. */
|
|
Packit |
6c4009 |
#ifdef ENABLE_READAHEAD
|
|
Packit |
6c4009 |
# define DELAY_READ
|
|
Packit |
6c4009 |
#else
|
|
Packit |
6c4009 |
# define DELAY_READ nop
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Testing on a little endian machine showed using CLZ was a
|
|
Packit |
6c4009 |
performance loss, so we are not turning it on by default. */
|
|
Packit |
6c4009 |
#if defined(ENABLE_CLZ) && (__mips_isa_rev > 1)
|
|
Packit |
6c4009 |
# define USE_CLZ
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Some asm.h files do not have the L macro definition. */
|
|
Packit |
6c4009 |
#ifndef L
|
|
Packit |
6c4009 |
# if _MIPS_SIM == _ABIO32
|
|
Packit |
6c4009 |
# define L(label) $L ## label
|
|
Packit |
6c4009 |
# else
|
|
Packit |
6c4009 |
# define L(label) .L ## label
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Some asm.h files do not have the PTR_ADDIU macro definition. */
|
|
Packit |
6c4009 |
#ifndef PTR_ADDIU
|
|
Packit |
6c4009 |
# ifdef USE_DOUBLE
|
|
Packit |
6c4009 |
# define PTR_ADDIU daddiu
|
|
Packit |
6c4009 |
# else
|
|
Packit |
6c4009 |
# define PTR_ADDIU addiu
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Allow the routine to be named something else if desired. */
|
|
Packit |
6c4009 |
#ifndef STRCMP_NAME
|
|
Packit |
6c4009 |
# define STRCMP_NAME strcmp
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#ifdef ANDROID_CHANGES
|
|
Packit |
6c4009 |
LEAF(STRCMP_NAME, 0)
|
|
Packit |
6c4009 |
#else
|
|
Packit |
6c4009 |
LEAF(STRCMP_NAME)
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
.set nomips16
|
|
Packit |
6c4009 |
.set noreorder
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
or t0, a0, a1
|
|
Packit |
6c4009 |
andi t0,0x3
|
|
Packit |
6c4009 |
bne t0, zero, L(byteloop)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Both strings are 4 byte aligned at this point. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
lui t8, 0x0101
|
|
Packit |
6c4009 |
ori t8, t8, 0x0101
|
|
Packit |
6c4009 |
lui t9, 0x7f7f
|
|
Packit |
6c4009 |
ori t9, 0x7f7f
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define STRCMP32(OFFSET) \
|
|
Packit |
6c4009 |
lw v0, OFFSET(a0); \
|
|
Packit |
6c4009 |
lw v1, OFFSET(a1); \
|
|
Packit |
6c4009 |
subu t0, v0, t8; \
|
|
Packit |
6c4009 |
bne v0, v1, L(worddiff); \
|
|
Packit |
6c4009 |
nor t1, v0, t9; \
|
|
Packit |
6c4009 |
and t0, t0, t1; \
|
|
Packit |
6c4009 |
bne t0, zero, L(returnzero)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
L(wordloop):
|
|
Packit |
6c4009 |
STRCMP32(0)
|
|
Packit |
6c4009 |
DELAY_READ
|
|
Packit |
6c4009 |
STRCMP32(4)
|
|
Packit |
6c4009 |
DELAY_READ
|
|
Packit |
6c4009 |
STRCMP32(8)
|
|
Packit |
6c4009 |
DELAY_READ
|
|
Packit |
6c4009 |
STRCMP32(12)
|
|
Packit |
6c4009 |
DELAY_READ
|
|
Packit |
6c4009 |
STRCMP32(16)
|
|
Packit |
6c4009 |
DELAY_READ
|
|
Packit |
6c4009 |
STRCMP32(20)
|
|
Packit |
6c4009 |
DELAY_READ
|
|
Packit |
6c4009 |
STRCMP32(24)
|
|
Packit |
6c4009 |
DELAY_READ
|
|
Packit |
6c4009 |
STRCMP32(28)
|
|
Packit |
6c4009 |
PTR_ADDIU a0, a0, 32
|
|
Packit |
6c4009 |
b L(wordloop)
|
|
Packit |
6c4009 |
PTR_ADDIU a1, a1, 32
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
L(returnzero):
|
|
Packit |
6c4009 |
j ra
|
|
Packit |
6c4009 |
move v0, zero
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
L(worddiff):
|
|
Packit |
6c4009 |
#ifdef USE_CLZ
|
|
Packit |
6c4009 |
subu t0, v0, t8
|
|
Packit |
6c4009 |
nor t1, v0, t9
|
|
Packit |
6c4009 |
and t1, t0, t1
|
|
Packit |
6c4009 |
xor t0, v0, v1
|
|
Packit |
6c4009 |
or t0, t0, t1
|
|
Packit |
6c4009 |
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
Packit |
6c4009 |
wsbh t0, t0
|
|
Packit |
6c4009 |
rotr t0, t0, 16
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
clz t1, t0
|
|
Packit |
6c4009 |
and t1, 0xf8
|
|
Packit |
6c4009 |
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
Packit |
6c4009 |
neg t1
|
|
Packit |
6c4009 |
addu t1, 24
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
rotrv v0, v0, t1
|
|
Packit |
6c4009 |
rotrv v1, v1, t1
|
|
Packit |
6c4009 |
and v0, v0, 0xff
|
|
Packit |
6c4009 |
and v1, v1, 0xff
|
|
Packit |
6c4009 |
j ra
|
|
Packit |
6c4009 |
subu v0, v0, v1
|
|
Packit |
6c4009 |
#else /* USE_CLZ */
|
|
Packit |
6c4009 |
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
Packit |
6c4009 |
andi t0, v0, 0xff
|
|
Packit |
6c4009 |
beq t0, zero, L(wexit01)
|
|
Packit |
6c4009 |
andi t1, v1, 0xff
|
|
Packit |
6c4009 |
bne t0, t1, L(wexit01)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
srl t8, v0, 8
|
|
Packit |
6c4009 |
srl t9, v1, 8
|
|
Packit |
6c4009 |
andi t8, t8, 0xff
|
|
Packit |
6c4009 |
beq t8, zero, L(wexit89)
|
|
Packit |
6c4009 |
andi t9, t9, 0xff
|
|
Packit |
6c4009 |
bne t8, t9, L(wexit89)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
srl t0, v0, 16
|
|
Packit |
6c4009 |
srl t1, v1, 16
|
|
Packit |
6c4009 |
andi t0, t0, 0xff
|
|
Packit |
6c4009 |
beq t0, zero, L(wexit01)
|
|
Packit |
6c4009 |
andi t1, t1, 0xff
|
|
Packit |
6c4009 |
bne t0, t1, L(wexit01)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
srl t8, v0, 24
|
|
Packit |
6c4009 |
srl t9, v1, 24
|
|
Packit |
6c4009 |
# else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
|
|
Packit |
6c4009 |
srl t0, v0, 24
|
|
Packit |
6c4009 |
beq t0, zero, L(wexit01)
|
|
Packit |
6c4009 |
srl t1, v1, 24
|
|
Packit |
6c4009 |
bne t0, t1, L(wexit01)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
srl t8, v0, 16
|
|
Packit |
6c4009 |
srl t9, v1, 16
|
|
Packit |
6c4009 |
andi t8, t8, 0xff
|
|
Packit |
6c4009 |
beq t8, zero, L(wexit89)
|
|
Packit |
6c4009 |
andi t9, t9, 0xff
|
|
Packit |
6c4009 |
bne t8, t9, L(wexit89)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
srl t0, v0, 8
|
|
Packit |
6c4009 |
srl t1, v1, 8
|
|
Packit |
6c4009 |
andi t0, t0, 0xff
|
|
Packit |
6c4009 |
beq t0, zero, L(wexit01)
|
|
Packit |
6c4009 |
andi t1, t1, 0xff
|
|
Packit |
6c4009 |
bne t0, t1, L(wexit01)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
andi t8, v0, 0xff
|
|
Packit |
6c4009 |
andi t9, v1, 0xff
|
|
Packit |
6c4009 |
# endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
L(wexit89):
|
|
Packit |
6c4009 |
j ra
|
|
Packit |
6c4009 |
subu v0, t8, t9
|
|
Packit |
6c4009 |
L(wexit01):
|
|
Packit |
6c4009 |
j ra
|
|
Packit |
6c4009 |
subu v0, t0, t1
|
|
Packit |
6c4009 |
#endif /* USE_CLZ */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* It might seem better to do the 'beq' instruction between the two 'lbu'
|
|
Packit |
6c4009 |
instructions so that the nop is not needed but testing showed that this
|
|
Packit |
6c4009 |
code is actually faster (based on glibc strcmp test). */
|
|
Packit |
6c4009 |
#define BYTECMP01(OFFSET) \
|
|
Packit |
6c4009 |
lbu v0, OFFSET(a0); \
|
|
Packit |
6c4009 |
lbu v1, OFFSET(a1); \
|
|
Packit |
6c4009 |
beq v0, zero, L(bexit01); \
|
|
Packit |
6c4009 |
nop; \
|
|
Packit |
6c4009 |
bne v0, v1, L(bexit01)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define BYTECMP89(OFFSET) \
|
|
Packit |
6c4009 |
lbu t8, OFFSET(a0); \
|
|
Packit |
6c4009 |
lbu t9, OFFSET(a1); \
|
|
Packit |
6c4009 |
beq t8, zero, L(bexit89); \
|
|
Packit |
6c4009 |
nop; \
|
|
Packit |
6c4009 |
bne t8, t9, L(bexit89)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
L(byteloop):
|
|
Packit |
6c4009 |
BYTECMP01(0)
|
|
Packit |
6c4009 |
BYTECMP89(1)
|
|
Packit |
6c4009 |
BYTECMP01(2)
|
|
Packit |
6c4009 |
BYTECMP89(3)
|
|
Packit |
6c4009 |
BYTECMP01(4)
|
|
Packit |
6c4009 |
BYTECMP89(5)
|
|
Packit |
6c4009 |
BYTECMP01(6)
|
|
Packit |
6c4009 |
BYTECMP89(7)
|
|
Packit |
6c4009 |
PTR_ADDIU a0, a0, 8
|
|
Packit |
6c4009 |
b L(byteloop)
|
|
Packit |
6c4009 |
PTR_ADDIU a1, a1, 8
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
L(bexit01):
|
|
Packit |
6c4009 |
j ra
|
|
Packit |
6c4009 |
subu v0, v0, v1
|
|
Packit |
6c4009 |
L(bexit89):
|
|
Packit |
6c4009 |
j ra
|
|
Packit |
6c4009 |
subu v0, t8, t9
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
.set at
|
|
Packit |
6c4009 |
.set reorder
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
END(STRCMP_NAME)
|
|
Packit |
6c4009 |
#ifndef ANDROID_CHANGES
|
|
Packit |
6c4009 |
# ifdef _LIBC
|
|
Packit |
6c4009 |
libc_hidden_builtin_def (STRCMP_NAME)
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
#endif
|