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