1/* 2 * Copyright (c) 2017 Imagination Technologies. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with 15 * the distribution. 16 * * Neither the name of Imagination Technologies nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#ifdef __ANDROID__ 34# include <private/bionic_asm.h> 35#elif _LIBC 36# include <sysdep.h> 37# include <regdef.h> 38# include <sys/asm.h> 39#elif _COMPILING_NEWLIB 40# include "machine/asm.h" 41# include "machine/regdef.h" 42#else 43# include <regdef.h> 44# include <sys/asm.h> 45#endif 46 47#if __mips64 48# define NSIZE 8 49# define LW ld 50# define EXT dext 51# define SRL dsrl 52# define SLL dsll 53# define SUBU dsubu 54#else 55# define NSIZE 4 56# define LW lw 57# define EXT ext 58# define SRL srl 59# define SLL sll 60# define SUBU subu 61#endif 62 63/* Technically strcmp should not read past the end of the strings being 64 compared. We will read a full word that may contain excess bits beyond 65 the NULL string terminator but unless ENABLE_READAHEAD is set, we will not 66 read the next word after the end of string. Setting ENABLE_READAHEAD will 67 improve performance but is technically illegal based on the definition of 68 strcmp. */ 69#ifdef ENABLE_READAHEAD 70# define DELAY_READ 71#else 72# define DELAY_READ nop 73#endif 74 75/* Testing on a little endian machine showed using CLZ was a 76 performance loss, so we are not turning it on by default. */ 77#if defined(ENABLE_CLZ) && (__mips_isa_rev > 1) 78# define USE_CLZ 79#endif 80 81/* Some asm.h files do not have the L macro definition. */ 82#ifndef L 83# if _MIPS_SIM == _ABIO32 84# define L(label) $L ## label 85# else 86# define L(label) .L ## label 87# endif 88#endif 89 90/* Some asm.h files do not have the PTR_ADDIU macro definition. */ 91#ifndef PTR_ADDIU 92# if _MIPS_SIM == _ABIO32 93# define PTR_ADDIU addiu 94# else 95# define PTR_ADDIU daddiu 96# endif 97#endif 98 99/* It might seem better to do the 'beq' instruction between the two 'lbu' 100 instructions so that the nop is not needed but testing showed that this 101 code is actually faster (based on glibc strcmp test). */ 102#define BYTECMP01(OFFSET) \ 103 lbu $v0, OFFSET($a0); \ 104 lbu $v1, OFFSET($a1); \ 105 beq $v0, $zero, L(bexit01); \ 106 nop; \ 107 bne $v0, $v1, L(bexit01) 108 109#define BYTECMP89(OFFSET) \ 110 lbu $t8, OFFSET($a0); \ 111 lbu $t9, OFFSET($a1); \ 112 beq $t8, $zero, L(bexit89); \ 113 nop; \ 114 bne $t8, $t9, L(bexit89) 115 116/* Allow the routine to be named something else if desired. */ 117#ifndef STRCMP_NAME 118# define STRCMP_NAME strcmp 119#endif 120 121#ifdef __ANDROID__ 122LEAF(STRCMP_NAME, 0) 123#else 124LEAF(STRCMP_NAME) 125#endif 126 .set nomips16 127 .set noreorder 128 129 andi $t1, $a1, (NSIZE - 1) 130 beqz $t1, L(exitalign) 131 or $t0, $zero, NSIZE 132 SUBU $t1, $t0, $t1 #process (NSIZE - 1) bytes at max 133 134L(alignloop): #do by bytes until a1 aligned 135 BYTECMP01(0) 136 SUBU $t1, $t1, 0x1 137 PTR_ADDIU $a0, $a0, 0x1 138 bnez $t1, L(alignloop) 139 PTR_ADDIU $a1, $a1, 0x1 140 141L(exitalign): 142 143/* string a1 is NSIZE byte aligned at this point. */ 144 145 lui $t8, 0x0101 146 ori $t8, 0x0101 147 lui $t9, 0x7f7f 148 ori $t9, 0x7f7f 149#if __mips64 150 dsll $t1, $t8, 32 151 or $t8, $t1 152 dsll $t1, $t9, 32 153 or $t9, $t1 154#endif 155 156 andi $t2, $a0, (NSIZE - 1) #check if a0 aligned 157 SUBU $t3, $t0, $t2 #t3 will be used as shifter 158 bnez $t2, L(uloopenter) 159 SUBU $a2, $a0, $t2 #bring back a0 to aligned position 160 161#define STRCMPW(OFFSET) \ 162 LW $v0, OFFSET($a0); \ 163 LW $v1, OFFSET($a1); \ 164 SUBU $t0, $v0, $t8; \ 165 bne $v0, $v1, L(worddiff); \ 166 nor $t1, $v0, $t9; \ 167 and $t0, $t0, $t1; \ 168 bne $t0, $zero, L(returnzero);\ 169 170L(wordloop): 171 STRCMPW(0 * NSIZE) 172 DELAY_READ 173 STRCMPW(1 * NSIZE) 174 DELAY_READ 175 STRCMPW(2 * NSIZE) 176 DELAY_READ 177 STRCMPW(3 * NSIZE) 178 DELAY_READ 179 STRCMPW(4 * NSIZE) 180 DELAY_READ 181 STRCMPW(5 * NSIZE) 182 DELAY_READ 183 STRCMPW(6 * NSIZE) 184 DELAY_READ 185 STRCMPW(7 * NSIZE) 186 PTR_ADDIU $a0, $a0, (8 * NSIZE) 187 b L(wordloop) 188 PTR_ADDIU $a1, $a1, (8 * NSIZE) 189 190#define USTRCMPW(OFFSET) \ 191 LW $v1, OFFSET($a1); \ 192 SUBU $t0, $v0, $t8; \ 193 nor $t1, $v0, $t9; \ 194 and $t0, $t0, $t1; \ 195 bne $t0, $zero, L(worddiff); \ 196 SRL $v0, $t2; \ 197 LW $a3, (OFFSET + NSIZE)($a2); \ 198 SUBU $t0, $v1, $t8; \ 199 SLL $t1, $a3, $t3; \ 200 or $v0, $v0, $t1; \ 201 bne $v0, $v1, L(worddiff); \ 202 nor $t1, $v1, $t9; \ 203 and $t0, $t0, $t1; \ 204 bne $t0, $zero, L(returnzero); \ 205 move $v0, $a3;\ 206 207L(uloopenter): 208 LW $v0, 0($a2) 209 SLL $t2, 3 #multiply by 8 210 SLL $t3, 3 #multiply by 8 211 li $a3, -1 #all 1s 212 SRL $a3, $t3 213 or $v0, $a3 #replace with all 1s if zeros in unintented read 214 215L(uwordloop): 216 USTRCMPW(0 * NSIZE) 217 USTRCMPW(1 * NSIZE) 218 USTRCMPW(2 * NSIZE) 219 USTRCMPW(3 * NSIZE) 220 USTRCMPW(4 * NSIZE) 221 USTRCMPW(5 * NSIZE) 222 USTRCMPW(6 * NSIZE) 223 USTRCMPW(7 * NSIZE) 224 PTR_ADDIU $a2, $a2, (8 * NSIZE) 225 b L(uwordloop) 226 PTR_ADDIU $a1, $a1, (8 * NSIZE) 227 228L(returnzero): 229 j $ra 230 move $v0, $zero 231 232#if __mips_isa_rev > 1 233#define EXT_COMPARE01(POS) \ 234 EXT $t0, $v0, POS, 8; \ 235 beq $t0, $zero, L(wexit01); \ 236 EXT $t1, $v1, POS, 8; \ 237 bne $t0, $t1, L(wexit01) 238#define EXT_COMPARE89(POS) \ 239 EXT $t8, $v0, POS, 8; \ 240 beq $t8, $zero, L(wexit89); \ 241 EXT $t9, $v1, POS, 8; \ 242 bne $t8, $t9, L(wexit89) 243#else 244#define EXT_COMPARE01(POS) \ 245 SRL $t0, $v0, POS; \ 246 SRL $t1, $v1, POS; \ 247 andi $t0, $t0, 0xff; \ 248 beq $t0, $zero, L(wexit01); \ 249 andi $t1, $t1, 0xff; \ 250 bne $t0, $t1, L(wexit01) 251#define EXT_COMPARE89(POS) \ 252 SRL $t8, $v0, POS; \ 253 SRL $t9, $v1, POS; \ 254 andi $t8, $t8, 0xff; \ 255 beq $t8, $zero, L(wexit89); \ 256 andi $t9, $t9, 0xff; \ 257 bne $t8, $t9, L(wexit89) 258#endif 259 260L(worddiff): 261#ifdef USE_CLZ 262 SUBU $t0, $v0, $t8 263 nor $t1, $v0, $t9 264 and $t1, $t0, $t1 265 xor $t0, $v0, $v1 266 or $t0, $t0, $t1 267# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 268 wsbh $t0, $t0 269 rotr $t0, $t0, 16 270# endif 271 clz $t1, $t0 272 and $t1, 0xf8 273# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 274 neg $t1 275 addu $t1, 24 276# endif 277 rotrv $v0, $v0, $t1 278 rotrv $v1, $v1, $t1 279 and $v0, $v0, 0xff 280 and $v1, $v1, 0xff 281 j $ra 282 SUBU $v0, $v0, $v1 283#else /* USE_CLZ */ 284# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 285 andi $t0, $v0, 0xff 286 beq $t0, $zero, L(wexit01) 287 andi $t1, $v1, 0xff 288 bne $t0, $t1, L(wexit01) 289 EXT_COMPARE89(8) 290 EXT_COMPARE01(16) 291#ifndef __mips64 292 SRL $t8, $v0, 24 293 SRL $t9, $v1, 24 294#else 295 EXT_COMPARE89(24) 296 EXT_COMPARE01(32) 297 EXT_COMPARE89(40) 298 EXT_COMPARE01(48) 299 SRL $t8, $v0, 56 300 SRL $t9, $v1, 56 301#endif 302 303# else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ 304#ifdef __mips64 305 SRL $t0, $v0, 56 306 beq $t0, $zero, L(wexit01) 307 SRL $t1, $v1, 56 308 bne $t0, $t1, L(wexit01) 309 EXT_COMPARE89(48) 310 EXT_COMPARE01(40) 311 EXT_COMPARE89(32) 312 EXT_COMPARE01(24) 313#else 314 SRL $t0, $v0, 24 315 beq $t0, $zero, L(wexit01) 316 SRL $t1, $v1, 24 317 bne $t0, $t1, L(wexit01) 318#endif 319 EXT_COMPARE89(16) 320 EXT_COMPARE01(8) 321 322 andi $t8, $v0, 0xff 323 andi $t9, $v1, 0xff 324# endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ 325 326L(wexit89): 327 j $ra 328 SUBU $v0, $t8, $t9 329L(wexit01): 330 j $ra 331 SUBU $v0, $t0, $t1 332#endif /* USE_CLZ */ 333 334L(byteloop): 335 BYTECMP01(0) 336 BYTECMP89(1) 337 BYTECMP01(2) 338 BYTECMP89(3) 339 BYTECMP01(4) 340 BYTECMP89(5) 341 BYTECMP01(6) 342 BYTECMP89(7) 343 PTR_ADDIU $a0, $a0, 8 344 b L(byteloop) 345 PTR_ADDIU $a1, $a1, 8 346 347L(bexit01): 348 j $ra 349 SUBU $v0, $v0, $v1 350L(bexit89): 351 j $ra 352 SUBU $v0, $t8, $t9 353 354 .set at 355 .set reorder 356 357END(STRCMP_NAME) 358#ifndef __ANDROID__ 359# ifdef _LIBC 360libc_hidden_builtin_def (STRCMP_NAME) 361# endif 362#endif 363