Blame sysdeps/sparc/sparc64/strcmp.S

Packit 6c4009
/* Compare two strings for differences.
Packit 6c4009
   For SPARC v9.
Packit 6c4009
   Copyright (C) 2011-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by David S. Miller <davem@davemloft.net>
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
#include <sysdep.h>
Packit 6c4009
#include <asm/asi.h>
Packit 6c4009
Packit 6c4009
#ifndef XCC
Packit 6c4009
	.register	%g2, #scratch
Packit 6c4009
	.register	%g3, #scratch
Packit 6c4009
	.register	%g6, #scratch
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define rSTR1		%o0
Packit 6c4009
#define rSTR2		%o1
Packit 6c4009
#define r0101		%o2	/* 0x0101010101010101 */
Packit 6c4009
#define r8080		%o3	/* 0x8080808080808080 */
Packit 6c4009
#define rSTRXOR		%o4
Packit 6c4009
#define rWORD1		%o5
Packit 6c4009
#define rTMP1		%g1
Packit 6c4009
#define rTMP2		%g2
Packit 6c4009
#define rWORD2		%g3
Packit 6c4009
#define rSLL		%g4
Packit 6c4009
#define rSRL		%g5
Packit 6c4009
#define rBARREL		%g6
Packit 6c4009
Packit 6c4009
	/* There are two cases, either the two pointers are aligned
Packit 6c4009
	 * identically or they are not.  If they have the same
Packit 6c4009
	 * alignment we can use the normal full speed loop.  Otherwise
Packit 6c4009
	 * we have to use the barrel-shifter version.
Packit 6c4009
	 */
Packit 6c4009
Packit 6c4009
	.text
Packit 6c4009
	.align	32
Packit 6c4009
ENTRY(strcmp)
Packit 6c4009
	or	rSTR2, rSTR1, rTMP1
Packit 6c4009
	sethi	%hi(0x80808080), r8080
Packit 6c4009
Packit 6c4009
	andcc	rTMP1, 0x7, %g0
Packit 6c4009
	bne,pn	%icc, .Lmaybe_barrel_shift
Packit 6c4009
	 or	r8080, %lo(0x80808080), r8080
Packit 6c4009
	ldx	[rSTR1], rWORD1
Packit 6c4009
Packit 6c4009
	sub	rSTR2, rSTR1, rSTR2
Packit 6c4009
	sllx	r8080, 32, rTMP1
Packit 6c4009
Packit 6c4009
	ldx	[rSTR1 + rSTR2], rWORD2
Packit 6c4009
	or	r8080, rTMP1, r8080
Packit 6c4009
Packit 6c4009
	ba,pt	%xcc, .Laligned_loop_entry
Packit 6c4009
	 srlx	r8080, 7, r0101
Packit 6c4009
Packit 6c4009
	.align	32
Packit 6c4009
.Laligned_loop_entry:
Packit 6c4009
.Laligned_loop:
Packit 6c4009
	add	rSTR1, 8, rSTR1
Packit 6c4009
Packit 6c4009
	sub	rWORD1, r0101, rTMP2
Packit 6c4009
	xorcc	rWORD1, rWORD2, rSTRXOR
Packit 6c4009
	bne,pn	%xcc, .Lcommon_endstring
Packit 6c4009
Packit 6c4009
	 andn	r8080, rWORD1, rTMP1
Packit 6c4009
Packit 6c4009
	ldxa	[rSTR1] ASI_PNF, rWORD1
Packit 6c4009
	andcc	rTMP1, rTMP2, %g0
Packit 6c4009
	be,a,pt	%xcc, .Laligned_loop
Packit 6c4009
Packit 6c4009
	 ldxa	[rSTR1 + rSTR2] ASI_PNF, rWORD2
Packit 6c4009
Packit 6c4009
.Lcommon_equal:
Packit 6c4009
	retl
Packit 6c4009
	 mov	0, %o0
Packit 6c4009
Packit 6c4009
	/* All loops terminate here once they find an unequal word.
Packit 6c4009
	 * If a zero byte appears in the word before the first unequal
Packit 6c4009
	 * byte, we must report zero.  Otherwise we report '1' or '-1'
Packit 6c4009
	 * depending upon whether the first mis-matching byte is larger
Packit 6c4009
	 * in the first string or the second, respectively.
Packit 6c4009
	 *
Packit 6c4009
	 * First we compute a 64-bit mask value that has "0x01" in
Packit 6c4009
	 * each byte where a zero exists in rWORD1.  rSTRXOR holds the
Packit 6c4009
	 * value (rWORD1 ^ rWORD2).  Therefore, if considered as an
Packit 6c4009
	 * unsigned quantity, our "0x01" mask value is "greater than"
Packit 6c4009
	 * rSTRXOR then a zero terminating byte comes first and
Packit 6c4009
	 * therefore we report '0'.
Packit 6c4009
	 *
Packit 6c4009
	 * The formula for this mask is:
Packit 6c4009
	 *
Packit 6c4009
	 *    mask_tmp1 = ~rWORD1 & 0x8080808080808080;
Packit 6c4009
	 *    mask_tmp2 = ((rWORD1 & 0x7f7f7f7f7f7f7f7f) +
Packit 6c4009
	 *                 0x7f7f7f7f7f7f7f7f);
Packit 6c4009
	 *
Packit 6c4009
	 *    mask = ((mask_tmp1 & ~mask_tmp2) >> 7);
Packit 6c4009
	 */
Packit 6c4009
.Lcommon_endstring:
Packit 6c4009
	andn	rWORD1, r8080, rTMP2
Packit 6c4009
	or	r8080, 1, %o1
Packit 6c4009
Packit 6c4009
	mov	1, %o0
Packit 6c4009
	sub	rTMP2, %o1, rTMP2
Packit 6c4009
Packit 6c4009
	cmp	rWORD1, rWORD2
Packit 6c4009
	andn	rTMP1, rTMP2, rTMP1
Packit 6c4009
Packit 6c4009
	movleu	%xcc, -1, %o0
Packit 6c4009
	srlx	rTMP1, 7, rTMP1
Packit 6c4009
Packit 6c4009
	/* In order not to be influenced by bytes after the zero byte, we
Packit 6c4009
	 * have to retain only the highest bit in the mask for the comparison
Packit 6c4009
	 * with rSTRXOR to work properly.
Packit 6c4009
	 */
Packit 6c4009
	mov	0, rTMP2
Packit 6c4009
	andcc	rTMP1, 0x0100, %g0
Packit 6c4009
Packit 6c4009
	movne	%xcc, 8, rTMP2
Packit 6c4009
	sllx	rTMP1, 63 - 16, %o1
Packit 6c4009
Packit 6c4009
	movrlz	%o1, 16, rTMP2
Packit 6c4009
	sllx	rTMP1, 63 - 24, %o1
Packit 6c4009
Packit 6c4009
	movrlz	%o1, 24, rTMP2
Packit 6c4009
	sllx	rTMP1, 63 - 32, %o1
Packit 6c4009
Packit 6c4009
	movrlz	%o1, 32, rTMP2
Packit 6c4009
	sllx	rTMP1, 63 - 40, %o1
Packit 6c4009
Packit 6c4009
	movrlz	%o1, 40, rTMP2
Packit 6c4009
	sllx	rTMP1, 63 - 48, %o1
Packit 6c4009
Packit 6c4009
	movrlz	%o1, 48, rTMP2
Packit 6c4009
	sllx	rTMP1, 63 - 56, %o1
Packit 6c4009
Packit 6c4009
	movrlz	%o1, 56, rTMP2
Packit 6c4009
Packit 6c4009
	srlx	rTMP1, rTMP2, rTMP1
Packit 6c4009
Packit 6c4009
	sllx	rTMP1, rTMP2, rTMP1
Packit 6c4009
Packit 6c4009
	cmp	rTMP1, rSTRXOR
Packit 6c4009
	retl
Packit 6c4009
	 movgu	%xcc, 0, %o0
Packit 6c4009
Packit 6c4009
.Lmaybe_barrel_shift:
Packit 6c4009
	sub	rSTR2, rSTR1, rSTR2
Packit 6c4009
	sllx	r8080, 32, rTMP1
Packit 6c4009
Packit 6c4009
	or	r8080, rTMP1, r8080
Packit 6c4009
	and	rSTR1, 0x7, rTMP2
Packit 6c4009
Packit 6c4009
	srlx	r8080, 7, r0101
Packit 6c4009
	andn	rSTR1, 0x7, rSTR1
Packit 6c4009
Packit 6c4009
	ldxa	[rSTR1] ASI_PNF, rWORD1
Packit 6c4009
	andcc	rSTR2, 0x7, rSLL
Packit 6c4009
	sll	rTMP2, 3, rSTRXOR
Packit 6c4009
Packit 6c4009
	bne,pn	%icc, .Lneed_barrel_shift
Packit 6c4009
	 mov	-1, rTMP1
Packit 6c4009
	ldxa	[rSTR1 + rSTR2] ASI_PNF, rBARREL
Packit 6c4009
Packit 6c4009
	srlx	rTMP1, rSTRXOR, rTMP2
Packit 6c4009
Packit 6c4009
	orn	rWORD1, rTMP2, rWORD1
Packit 6c4009
	ba,pt	%xcc, .Laligned_loop_entry
Packit 6c4009
	 orn	rBARREL, rTMP2, rWORD2
Packit 6c4009
Packit 6c4009
.Lneed_barrel_shift:
Packit 6c4009
	sllx	rSLL, 3, rSLL
Packit 6c4009
	andn	rSTR2, 0x7, rSTR2
Packit 6c4009
Packit 6c4009
	ldxa	[rSTR1 + rSTR2] ASI_PNF, rBARREL
Packit 6c4009
	mov	64, rTMP2
Packit 6c4009
	sub	rTMP2, rSLL, rSRL
Packit 6c4009
Packit 6c4009
	srlx	rTMP1, rSTRXOR, rTMP1
Packit 6c4009
	add	rSTR2, 8, rSTR2
Packit 6c4009
Packit 6c4009
	orn	rWORD1, rTMP1, rWORD1
Packit 6c4009
	sllx	rBARREL, rSLL, rWORD2
Packit 6c4009
	ldxa	[rSTR1 + rSTR2] ASI_PNF, rBARREL
Packit 6c4009
Packit 6c4009
	add	rSTR1, 8, rSTR1
Packit 6c4009
	sub	rWORD1, r0101, rTMP2
Packit 6c4009
Packit 6c4009
	srlx	rBARREL, rSRL, rSTRXOR
Packit 6c4009
Packit 6c4009
	or	rWORD2, rSTRXOR, rWORD2
Packit 6c4009
Packit 6c4009
	orn	rWORD2, rTMP1, rWORD2
Packit 6c4009
	ba,pt	%xcc, .Lbarrel_shift_loop_entry
Packit 6c4009
	 andn	r8080, rWORD1, rTMP1
Packit 6c4009
Packit 6c4009
.Lbarrel_shift_loop:
Packit 6c4009
	sllx	rBARREL, rSLL, rWORD2
Packit 6c4009
	ldxa	[rSTR1 + rSTR2] ASI_PNF, rBARREL
Packit 6c4009
Packit 6c4009
	add	rSTR1, 8, rSTR1
Packit 6c4009
	sub	rWORD1, r0101, rTMP2
Packit 6c4009
Packit 6c4009
	srlx	rBARREL, rSRL, rSTRXOR
Packit 6c4009
	andn	r8080, rWORD1, rTMP1
Packit 6c4009
Packit 6c4009
	or	rWORD2, rSTRXOR, rWORD2
Packit 6c4009
Packit 6c4009
.Lbarrel_shift_loop_entry:
Packit 6c4009
	xorcc	rWORD1, rWORD2, rSTRXOR
Packit 6c4009
	bne,pn	%xcc, .Lcommon_endstring
Packit 6c4009
Packit 6c4009
	 andcc	rTMP1, rTMP2, %g0
Packit 6c4009
	be,a,pt	%xcc, .Lbarrel_shift_loop
Packit 6c4009
	 ldxa	[rSTR1] ASI_PNF, rWORD1
Packit 6c4009
Packit 6c4009
	retl
Packit 6c4009
	 mov	0, %o0
Packit 6c4009
END(strcmp)
Packit 6c4009
libc_hidden_builtin_def (strcmp)