You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
362 lines
8.6 KiB
362 lines
8.6 KiB
/* |
|
* Copyright (c) 2017 Imagination Technologies. |
|
* |
|
* 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 Imagination Technologies 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 |
|
* OWNER 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. |
|
*/ |
|
|
|
#ifdef __ANDROID__ |
|
# include <private/bionic_asm.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 |
|
|
|
#if __mips64 |
|
# define NSIZE 8 |
|
# define LW ld |
|
# define EXT dext |
|
# define SRL dsrl |
|
# define SLL dsll |
|
# define SUBU dsubu |
|
#else |
|
# define NSIZE 4 |
|
# define LW lw |
|
# define EXT ext |
|
# define SRL srl |
|
# define SLL sll |
|
# define SUBU subu |
|
#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 |
|
# if _MIPS_SIM == _ABIO32 |
|
# define PTR_ADDIU addiu |
|
# else |
|
# define PTR_ADDIU daddiu |
|
# endif |
|
#endif |
|
|
|
/* 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) |
|
|
|
/* Allow the routine to be named something else if desired. */ |
|
#ifndef STRCMP_NAME |
|
# define STRCMP_NAME strcmp |
|
#endif |
|
|
|
#ifdef __ANDROID__ |
|
LEAF(STRCMP_NAME, 0) |
|
#else |
|
LEAF(STRCMP_NAME) |
|
#endif |
|
.set nomips16 |
|
.set noreorder |
|
|
|
andi t1, a1, (NSIZE - 1) |
|
beqz t1, L(exitalign) |
|
or t0, zero, NSIZE |
|
SUBU t1, t0, t1 #process (NSIZE - 1) bytes at max |
|
|
|
L(alignloop): #do by bytes until a1 aligned |
|
BYTECMP01(0) |
|
SUBU t1, t1, 0x1 |
|
PTR_ADDIU a0, a0, 0x1 |
|
bnez t1, L(alignloop) |
|
PTR_ADDIU a1, a1, 0x1 |
|
|
|
L(exitalign): |
|
|
|
/* string a1 is NSIZE byte aligned at this point. */ |
|
|
|
lui t8, 0x0101 |
|
ori t8, 0x0101 |
|
lui t9, 0x7f7f |
|
ori t9, 0x7f7f |
|
#if __mips64 |
|
dsll t1, t8, 32 |
|
or t8, t1 |
|
dsll t1, t9, 32 |
|
or t9, t1 |
|
#endif |
|
|
|
andi t2, a0, (NSIZE - 1) #check if a0 aligned |
|
SUBU t3, t0, t2 #t3 will be used as shifter |
|
bnez t2, L(uloopenter) |
|
SUBU a2, a0, t2 #bring back a0 to aligned position |
|
|
|
#define STRCMPW(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): |
|
STRCMPW(0 * NSIZE) |
|
DELAY_READ |
|
STRCMPW(1 * NSIZE) |
|
DELAY_READ |
|
STRCMPW(2 * NSIZE) |
|
DELAY_READ |
|
STRCMPW(3 * NSIZE) |
|
DELAY_READ |
|
STRCMPW(4 * NSIZE) |
|
DELAY_READ |
|
STRCMPW(5 * NSIZE) |
|
DELAY_READ |
|
STRCMPW(6 * NSIZE) |
|
DELAY_READ |
|
STRCMPW(7 * NSIZE) |
|
PTR_ADDIU a0, a0, (8 * NSIZE) |
|
b L(wordloop) |
|
PTR_ADDIU a1, a1, (8 * NSIZE) |
|
|
|
#define USTRCMPW(OFFSET) \ |
|
LW v1, OFFSET(a1); \ |
|
SUBU t0, v0, t8; \ |
|
nor t1, v0, t9; \ |
|
and t0, t0, t1; \ |
|
bne t0, zero, L(worddiff); \ |
|
SRL v0, t2; \ |
|
LW a3, (OFFSET + NSIZE)(a2); \ |
|
SUBU t0, v1, t8; \ |
|
SLL t1, a3, t3; \ |
|
or v0, v0, t1; \ |
|
bne v0, v1, L(worddiff); \ |
|
nor t1, v1, t9; \ |
|
and t0, t0, t1; \ |
|
bne t0, zero, L(returnzero); \ |
|
move v0, a3;\ |
|
|
|
L(uloopenter): |
|
LW v0, 0(a2) |
|
SLL t2, 3 #multiply by 8 |
|
SLL t3, 3 #multiply by 8 |
|
li a3, -1 #all 1s |
|
SRL a3, t3 |
|
or v0, a3 #replace with all 1s if zeros in unintented read |
|
|
|
L(uwordloop): |
|
USTRCMPW(0 * NSIZE) |
|
USTRCMPW(1 * NSIZE) |
|
USTRCMPW(2 * NSIZE) |
|
USTRCMPW(3 * NSIZE) |
|
USTRCMPW(4 * NSIZE) |
|
USTRCMPW(5 * NSIZE) |
|
USTRCMPW(6 * NSIZE) |
|
USTRCMPW(7 * NSIZE) |
|
PTR_ADDIU a2, a2, (8 * NSIZE) |
|
b L(uwordloop) |
|
PTR_ADDIU a1, a1, (8 * NSIZE) |
|
|
|
L(returnzero): |
|
j ra |
|
move v0, zero |
|
|
|
#if __mips_isa_rev > 1 |
|
#define EXT_COMPARE01(POS) \ |
|
EXT t0, v0, POS, 8; \ |
|
beq t0, zero, L(wexit01); \ |
|
EXT t1, v1, POS, 8; \ |
|
bne t0, t1, L(wexit01) |
|
#define EXT_COMPARE89(POS) \ |
|
EXT t8, v0, POS, 8; \ |
|
beq t8, zero, L(wexit89); \ |
|
EXT t9, v1, POS, 8; \ |
|
bne t8, t9, L(wexit89) |
|
#else |
|
#define EXT_COMPARE01(POS) \ |
|
SRL t0, v0, POS; \ |
|
SRL t1, v1, POS; \ |
|
andi t0, t0, 0xff; \ |
|
beq t0, zero, L(wexit01); \ |
|
andi t1, t1, 0xff; \ |
|
bne t0, t1, L(wexit01) |
|
#define EXT_COMPARE89(POS) \ |
|
SRL t8, v0, POS; \ |
|
SRL t9, v1, POS; \ |
|
andi t8, t8, 0xff; \ |
|
beq t8, zero, L(wexit89); \ |
|
andi t9, t9, 0xff; \ |
|
bne t8, t9, L(wexit89) |
|
#endif |
|
|
|
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) |
|
EXT_COMPARE89(8) |
|
EXT_COMPARE01(16) |
|
#ifndef __mips64 |
|
SRL t8, v0, 24 |
|
SRL t9, v1, 24 |
|
#else |
|
EXT_COMPARE89(24) |
|
EXT_COMPARE01(32) |
|
EXT_COMPARE89(40) |
|
EXT_COMPARE01(48) |
|
SRL t8, v0, 56 |
|
SRL t9, v1, 56 |
|
#endif |
|
|
|
# else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ |
|
#ifdef __mips64 |
|
SRL t0, v0, 56 |
|
beq t0, zero, L(wexit01) |
|
SRL t1, v1, 56 |
|
bne t0, t1, L(wexit01) |
|
EXT_COMPARE89(48) |
|
EXT_COMPARE01(40) |
|
EXT_COMPARE89(32) |
|
EXT_COMPARE01(24) |
|
#else |
|
SRL t0, v0, 24 |
|
beq t0, zero, L(wexit01) |
|
SRL t1, v1, 24 |
|
bne t0, t1, L(wexit01) |
|
#endif |
|
EXT_COMPARE89(16) |
|
EXT_COMPARE01(8) |
|
|
|
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 */ |
|
|
|
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__ |
|
# ifdef _LIBC |
|
libc_hidden_builtin_def (STRCMP_NAME) |
|
# endif |
|
#endif
|
|
|