Blame sysdeps/mips/strcmp.S

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