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 LWR ldr 51# define LWL ldl 52# define EXT dext 53# define SRL dsrl 54# define SUBU dsubu 55#else 56# define NSIZE 4 57# define LW lw 58# define LWR lwr 59# define LWL lwl 60# define EXT ext 61# define SRL srl 62# define SUBU subu 63#endif 64 65/* Technically strcmp should not read past the end of the strings being 66 compared. We will read a full word that may contain excess bits beyond 67 the NULL string terminator but unless ENABLE_READAHEAD is set, we will not 68 read the next word after the end of string. Setting ENABLE_READAHEAD will 69 improve performance but is technically illegal based on the definition of 70 strcmp. */ 71#ifdef ENABLE_READAHEAD 72# define DELAY_READ 73#else 74# define DELAY_READ nop 75#endif 76 77/* Testing on a little endian machine showed using CLZ was a 78 performance loss, so we are not turning it on by default. */ 79#if defined(ENABLE_CLZ) && (__mips_isa_rev > 1) && (!__mips64) 80# define USE_CLZ 81#endif 82 83/* Some asm.h files do not have the L macro definition. */ 84#ifndef L 85# if _MIPS_SIM == _ABIO32 86# define L(label) $L ## label 87# else 88# define L(label) .L ## label 89# endif 90#endif 91 92/* Some asm.h files do not have the PTR_ADDIU macro definition. */ 93#ifndef PTR_ADDIU 94# if _MIPS_SIM == _ABIO32 95# define PTR_ADDIU addiu 96# else 97# define PTR_ADDIU daddiu 98# endif 99#endif 100 101/* It might seem better to do the 'beq' instruction between the two 'lbu' 102 instructions so that the nop is not needed but testing showed that this 103 code is actually faster (based on glibc strcmp test). */ 104#define BYTECMP01(OFFSET) \ 105 lbu $v0, OFFSET($a0); \ 106 lbu $v1, OFFSET($a1); \ 107 beq $v0, $zero, L(bexit01); \ 108 nop; \ 109 bne $v0, $v1, L(bexit01) 110 111#define BYTECMP89(OFFSET) \ 112 lbu $t8, OFFSET($a0); \ 113 lbu $t9, OFFSET($a1); \ 114 beq $t8, $zero, L(bexit89); \ 115 nop; \ 116 bne $t8, $t9, L(bexit89) 117 118/* Allow the routine to be named something else if desired. */ 119#ifndef STRNCMP_NAME 120# define STRNCMP_NAME strncmp 121#endif 122 123#ifdef __ANDROID__ 124LEAF(STRNCMP_NAME, 0) 125#else 126LEAF(STRNCMP_NAME) 127#endif 128 .set nomips16 129 .set noreorder 130 131 srl $t0, $a2, (2 + NSIZE / 4) 132 beqz $t0, L(byteloop) #process by bytes if less than (2 * NSIZE) 133 andi $t1, $a1, (NSIZE - 1) 134 beqz $t1, L(exitalign) 135 or $t0, $zero, NSIZE 136 SUBU $t1, $t0, $t1 #process (NSIZE - 1) bytes at max 137 SUBU $a2, $a2, $t1 #dec count by t1 138 139L(alignloop): #do by bytes until a1 aligned 140 BYTECMP01(0) 141 SUBU $t1, $t1, 0x1 142 PTR_ADDIU $a0, $a0, 0x1 143 bne $t1, $zero, L(alignloop) 144 PTR_ADDIU $a1, $a1, 0x1 145 146L(exitalign): 147 148/* string a1 is NSIZE byte aligned at this point. */ 149#ifndef __mips1 150 lui $t8, 0x0101 151 ori $t8, 0x0101 152 lui $t9, 0x7f7f 153 ori $t9, 0x7f7f 154#if __mips64 155 dsll $t0, $t8, 32 156 or $t8, $t0 157 dsll $t1, $t9, 32 158 or $t9, $t1 159#endif 160#endif 161 162/* hardware or software alignment not supported for mips1 163 rev6 archs have h/w unaligned support 164 remainings archs need to implemented with unaligned instructions */ 165 166#if __mips1 167 andi $t0, $a0, (NSIZE - 1) 168 bne $t0, $zero, L(byteloop) 169#elif __mips_isa_rev < 6 170 andi $t0, $a0, (NSIZE - 1) 171 bne $t0, $zero, L(uwordloop) 172#endif 173 174#define STRCMPW(OFFSET) \ 175 LW $v0, (OFFSET)($a0); \ 176 LW $v1, (OFFSET)($a1); \ 177 SUBU $t0, $v0, $t8; \ 178 bne $v0, $v1, L(worddiff); \ 179 nor $t1, $v0, $t9; \ 180 and $t0, $t0, $t1; \ 181 bne $t0, $zero, L(returnzero);\ 182 183L(wordloop): 184 SUBU $t1, $a2, (8 * NSIZE) 185 bltz $t1, L(onewords) 186 STRCMPW(0 * NSIZE) 187 DELAY_READ 188 STRCMPW(1 * NSIZE) 189 DELAY_READ 190 STRCMPW(2 * NSIZE) 191 DELAY_READ 192 STRCMPW(3 * NSIZE) 193 DELAY_READ 194 STRCMPW(4 * NSIZE) 195 DELAY_READ 196 STRCMPW(5 * NSIZE) 197 DELAY_READ 198 STRCMPW(6 * NSIZE) 199 DELAY_READ 200 STRCMPW(7 * NSIZE) 201 SUBU $a2, $a2, (8 * NSIZE) 202 PTR_ADDIU $a0, $a0, (8 * NSIZE) 203 b L(wordloop) 204 PTR_ADDIU $a1, $a1, (8 * NSIZE) 205 206L(onewords): 207 SUBU $t1, $a2, NSIZE 208 bltz $t1, L(byteloop) 209 STRCMPW(0) 210 SUBU $a2, $a2, NSIZE 211 PTR_ADDIU $a0, $a0, NSIZE 212 b L(onewords) 213 PTR_ADDIU $a1, $a1, NSIZE 214 215#if __mips_isa_rev < 6 && !__mips1 216#define USTRCMPW(OFFSET) \ 217 LWR $v0, (OFFSET)($a0); \ 218 LWL $v0, (OFFSET + NSIZE - 1)($a0); \ 219 LW $v1, (OFFSET)($a1); \ 220 SUBU $t0, $v0, $t8; \ 221 bne $v0, $v1, L(worddiff); \ 222 nor $t1, $v0, $t9; \ 223 and $t0, $t0, $t1; \ 224 bne $t0, $zero, L(returnzero);\ 225 226L(uwordloop): 227 SUBU $t1, $a2, (8 * NSIZE) 228 bltz $t1, L(uonewords) 229 USTRCMPW(0 * NSIZE) 230 DELAY_READ 231 USTRCMPW(1 * NSIZE) 232 DELAY_READ 233 USTRCMPW(2 * NSIZE) 234 DELAY_READ 235 USTRCMPW(3 * NSIZE) 236 DELAY_READ 237 USTRCMPW(4 * NSIZE) 238 DELAY_READ 239 USTRCMPW(5 * NSIZE) 240 DELAY_READ 241 USTRCMPW(6 * NSIZE) 242 DELAY_READ 243 USTRCMPW(7 * NSIZE) 244 SUBU $a2, $a2, (8 * NSIZE) 245 PTR_ADDIU $a0, $a0, (8 * NSIZE) 246 b L(uwordloop) 247 PTR_ADDIU $a1, $a1, (8 * NSIZE) 248 249L(uonewords): 250 SUBU $t1, $a2, NSIZE 251 bltz $t1, L(byteloop) 252 USTRCMPW(0) 253 SUBU $a2, $a2, NSIZE 254 PTR_ADDIU $a0, $a0, NSIZE 255 b L(uonewords) 256 PTR_ADDIU $a1, $a1, NSIZE 257 258#endif 259 260L(returnzero): 261 j $ra 262 move $v0, $zero 263 264#if __mips_isa_rev > 1 265#define EXT_COMPARE01(POS) \ 266 EXT $t0, $v0, POS, 8; \ 267 beq $t0, $zero, L(wexit01); \ 268 EXT $t1, $v1, POS, 8; \ 269 bne $t0, $t1, L(wexit01) 270#define EXT_COMPARE89(POS) \ 271 EXT $t8, $v0, POS, 8; \ 272 beq $t8, $zero, L(wexit89); \ 273 EXT $t9, $v1, POS, 8; \ 274 bne $t8, $t9, L(wexit89) 275#else 276#define EXT_COMPARE01(POS) \ 277 SRL $t0, $v0, POS; \ 278 SRL $t1, $v1, POS; \ 279 andi $t0, $t0, 0xff; \ 280 beq $t0, $zero, L(wexit01); \ 281 andi $t1, $t1, 0xff; \ 282 bne $t0, $t1, L(wexit01) 283#define EXT_COMPARE89(POS) \ 284 SRL $t8, $v0, POS; \ 285 SRL $t9, $v1, POS; \ 286 andi $t8, $t8, 0xff; \ 287 beq $t8, $zero, L(wexit89); \ 288 andi $t9, $t9, 0xff; \ 289 bne $t8, $t9, L(wexit89) 290#endif 291 292L(worddiff): 293#ifdef USE_CLZ 294 SUBU $t0, $v0, $t8 295 nor $t1, $v0, $t9 296 and $t1, $t0, $t1 297 xor $t0, $v0, $v1 298 or $t0, $t0, $t1 299# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 300 wsbh $t0, $t0 301 rotr $t0, $t0, 16 302# endif 303 clz $t1, $t0 304 and $t1, 0xf8 305# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 306 neg $t1 307 addu $t1, 24 308# endif 309 rotrv $v0, $v0, $t1 310 rotrv $v1, $v1, $t1 311 and $v0, $v0, 0xff 312 and $v1, $v1, 0xff 313 j $ra 314 SUBU $v0, $v0, $v1 315#else /* USE_CLZ */ 316# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 317 andi $t0, $v0, 0xff 318 beq $t0, $zero, L(wexit01) 319 andi $t1, $v1, 0xff 320 bne $t0, $t1, L(wexit01) 321 EXT_COMPARE89(8) 322 EXT_COMPARE01(16) 323#ifndef __mips64 324 SRL $t8, $v0, 24 325 SRL $t9, $v1, 24 326#else 327 EXT_COMPARE89(24) 328 EXT_COMPARE01(32) 329 EXT_COMPARE89(40) 330 EXT_COMPARE01(48) 331 SRL $t8, $v0, 56 332 SRL $t9, $v1, 56 333#endif 334 335# else /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ 336#ifdef __mips64 337 SRL $t0, $v0, 56 338 beq $t0, $zero, L(wexit01) 339 SRL $t1, $v1, 56 340 bne $t0, $t1, L(wexit01) 341 EXT_COMPARE89(48) 342 EXT_COMPARE01(40) 343 EXT_COMPARE89(32) 344 EXT_COMPARE01(24) 345#else 346 SRL $t0, $v0, 24 347 beq $t0, $zero, L(wexit01) 348 SRL $t1, $v1, 24 349 bne $t0, $t1, L(wexit01) 350#endif 351 EXT_COMPARE89(16) 352 EXT_COMPARE01(8) 353 354 andi $t8, $v0, 0xff 355 andi $t9, $v1, 0xff 356# endif /* __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ */ 357 358L(wexit89): 359 j $ra 360 SUBU $v0, $t8, $t9 361L(wexit01): 362 j $ra 363 SUBU $v0, $t0, $t1 364#endif /* USE_CLZ */ 365 366L(byteloop): 367 beq $a2, $zero, L(returnzero) 368 SUBU $a2, $a2, 1 369 BYTECMP01(0) 370 nop 371 beq $a2, $zero, L(returnzero) 372 SUBU $a2, $a2, 1 373 BYTECMP89(1) 374 nop 375 beq $a2, $zero, L(returnzero) 376 SUBU $a2, $a2, 1 377 BYTECMP01(2) 378 nop 379 beq $a2, $zero, L(returnzero) 380 SUBU $a2, $a2, 1 381 BYTECMP89(3) 382 PTR_ADDIU $a0, $a0, 4 383 b L(byteloop) 384 PTR_ADDIU $a1, $a1, 4 385 386L(bexit01): 387 j $ra 388 SUBU $v0, $v0, $v1 389L(bexit89): 390 j $ra 391 SUBU $v0, $t8, $t9 392 393 .set at 394 .set reorder 395 396END(STRNCMP_NAME) 397#ifndef __ANDROID__ 398# ifdef _LIBC 399libc_hidden_builtin_def (STRNCMP_NAME) 400# endif 401#endif 402