Blame sysdeps/m68k/strchr.S

Packit 6c4009
/* strchr (str, ch) -- Return pointer to first occurrence of CH in STR.
Packit 6c4009
   For Motorola 68000.
Packit 6c4009
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Andreas Schwab <schwab@gnu.org>.
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-syntax.h"
Packit 6c4009
Packit 6c4009
	TEXT
Packit 6c4009
ENTRY(strchr)
Packit 6c4009
	/* Save the callee-saved registers we use.  */
Packit 6c4009
	movel	R(d2),MEM_PREDEC(sp)
Packit 6c4009
	cfi_adjust_cfa_offset (4)
Packit 6c4009
	movel	R(d3),MEM_PREDEC(sp)
Packit 6c4009
	cfi_adjust_cfa_offset (4)
Packit 6c4009
	cfi_rel_offset (R(d2),4)
Packit 6c4009
	cfi_rel_offset (R(d3),0)
Packit 6c4009
Packit 6c4009
	/* Get string pointer and character.  */
Packit 6c4009
	movel	MEM_DISP(sp,12),R(a0)
Packit 6c4009
	moveb	MEM_DISP(sp,19),R(d0)
Packit 6c4009
Packit 6c4009
	/* Distribute the character to all bytes of a longword.  */
Packit 6c4009
	movel	R(d0),R(d1)
Packit 6c4009
	lsll	#8,R(d1)
Packit 6c4009
	moveb	R(d0),R(d1)
Packit 6c4009
	movel	R(d1),R(d0)
Packit 6c4009
	swap	R(d0)
Packit 6c4009
	movew	R(d1),R(d0)
Packit 6c4009
Packit 6c4009
	/* First search for the character one byte at a time until the
Packit 6c4009
	   pointer is aligned to a longword boundary.  */
Packit 6c4009
	movel	R(a0),R(d1)
Packit 6c4009
#ifdef __mcoldfire__
Packit 6c4009
	andl	#3,R(d1)
Packit 6c4009
#else
Packit 6c4009
	andw	#3,R(d1)
Packit 6c4009
#endif
Packit 6c4009
	beq	L(L1)
Packit 6c4009
	moveb	MEM(a0),R(d2)
Packit 6c4009
	cmpb	R(d0),R(d2)
Packit 6c4009
	beq	L(L9)
Packit 6c4009
	tstb	R(d2)
Packit 6c4009
	beq	L(L3)
Packit 6c4009
	addql	#1,R(a0)
Packit 6c4009
Packit 6c4009
#ifdef __mcoldfire__
Packit 6c4009
	subql	#3,R(d1)
Packit 6c4009
#else
Packit 6c4009
	subqw	#3,R(d1)
Packit 6c4009
#endif
Packit 6c4009
	beq	L(L1)
Packit 6c4009
	moveb	MEM(a0),R(d2)
Packit 6c4009
	cmpb	R(d0),R(d2)
Packit 6c4009
	beq	L(L9)
Packit 6c4009
	tstb	R(d2)
Packit 6c4009
	beq	L(L3)
Packit 6c4009
	addql	#1,R(a0)
Packit 6c4009
Packit 6c4009
#ifdef __mcoldfire__
Packit 6c4009
	addql	#1,R(d1)
Packit 6c4009
#else
Packit 6c4009
	addqw	#1,R(d1)
Packit 6c4009
#endif
Packit 6c4009
	beq	L(L1)
Packit 6c4009
	moveb	MEM(a0),R(d2)
Packit 6c4009
	cmpb	R(d0),R(d2)
Packit 6c4009
	beq	L(L9)
Packit 6c4009
	tstb	R(d2)
Packit 6c4009
	beq	L(L3)
Packit 6c4009
	addql	#1,R(a0)
Packit 6c4009
Packit 6c4009
L(L1:)
Packit 6c4009
	/* Load the magic bits.  Unlike the generic implementation we can
Packit 6c4009
	   use the carry bit as the fourth hole.  */
Packit 6c4009
	movel	#0xfefefeff,R(d3)
Packit 6c4009
Packit 6c4009
      /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
Packit 6c4009
	 change any of the hole bits of LONGWORD.
Packit 6c4009
Packit 6c4009
	 1) Is this safe?  Will it catch all the zero bytes?
Packit 6c4009
	 Suppose there is a byte with all zeros.  Any carry bits
Packit 6c4009
	 propagating from its left will fall into the hole at its
Packit 6c4009
	 least significant bit and stop.  Since there will be no
Packit 6c4009
	 carry from its most significant bit, the LSB of the
Packit 6c4009
	 byte to the left will be unchanged, and the zero will be
Packit 6c4009
	 detected.
Packit 6c4009
Packit 6c4009
	 2) Is this worthwhile?  Will it ignore everything except
Packit 6c4009
	 zero bytes?  Suppose every byte of LONGWORD has a bit set
Packit 6c4009
	 somewhere.  There will be a carry into bit 8.	If bit 8
Packit 6c4009
	 is set, this will carry into bit 16.  If bit 8 is clear,
Packit 6c4009
	 one of bits 9-15 must be set, so there will be a carry
Packit 6c4009
	 into bit 16.  Similarly, there will be a carry into bit
Packit 6c4009
	 24.  If one of bits 24-31 is set, there will be a carry
Packit 6c4009
	 into bit 32 (=carry flag), so all of the hole bits will
Packit 6c4009
	 be changed.
Packit 6c4009
Packit 6c4009
	 3) But wait!  Aren't we looking for C, not zero?
Packit 6c4009
	 Good point.  So what we do is XOR LONGWORD with a longword,
Packit 6c4009
	 each of whose bytes is C.  This turns each byte that is C
Packit 6c4009
	 into a zero.  */
Packit 6c4009
Packit 6c4009
L(L2:)
Packit 6c4009
	/* Get the longword in question.  */
Packit 6c4009
	movel	MEM_POSTINC(a0),R(d1)
Packit 6c4009
	/* XOR with the byte we search for.  */
Packit 6c4009
	eorl	R(d0),R(d1)
Packit 6c4009
Packit 6c4009
	/* Add the magic value.  We get carry bits reported for each byte
Packit 6c4009
	   which is not C.  */
Packit 6c4009
	movel	R(d3),R(d2)
Packit 6c4009
	addl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Check the fourth carry bit before it is clobbered by the next
Packit 6c4009
	   XOR.  If it is not set we have a hit.  */
Packit 6c4009
	bcc	L(L8)
Packit 6c4009
Packit 6c4009
	/* We are only interested in carry bits that change due to the
Packit 6c4009
	   previous add, so remove original bits.  */
Packit 6c4009
	eorl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Now test for the other three overflow bits.
Packit 6c4009
	   Set all non-carry bits.  */
Packit 6c4009
	orl	R(d3),R(d2)
Packit 6c4009
	/* Add 1 to get zero if all carry bits were set.  */
Packit 6c4009
	addql	#1,R(d2)
Packit 6c4009
Packit 6c4009
	/* If we don't get zero then at least one byte of the word equals
Packit 6c4009
	   C.  */
Packit 6c4009
	bne	L(L8)
Packit 6c4009
Packit 6c4009
	/* Next look for a NUL byte.
Packit 6c4009
	   Restore original longword without reload.  */
Packit 6c4009
	eorl	R(d0),R(d1)
Packit 6c4009
	/* Add the magic value.  We get carry bits reported for each byte
Packit 6c4009
	   which is not NUL.  */
Packit 6c4009
	movel	R(d3),R(d2)
Packit 6c4009
	addl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Check the fourth carry bit before it is clobbered by the next
Packit 6c4009
	   XOR.  If it is not set we have a hit, and return NULL.  */
Packit 6c4009
	bcc	L(L3)
Packit 6c4009
Packit 6c4009
	/* We are only interested in carry bits that change due to the
Packit 6c4009
	   previous add, so remove original bits.  */
Packit 6c4009
	eorl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Now test for the other three overflow bits.
Packit 6c4009
	   Set all non-carry bits.  */
Packit 6c4009
	orl	R(d3),R(d2)
Packit 6c4009
	/* Add 1 to get zero if all carry bits were set.  */
Packit 6c4009
	addql	#1,R(d2)
Packit 6c4009
Packit 6c4009
	/* If we don't get zero then at least one byte of the word was NUL
Packit 6c4009
	   and we return NULL.  Otherwise continue with the next longword.  */
Packit 6c4009
	bne	L(L3)
Packit 6c4009
Packit 6c4009
	/* Get the longword in question.  */
Packit 6c4009
	movel	MEM_POSTINC(a0),R(d1)
Packit 6c4009
	/* XOR with the byte we search for.  */
Packit 6c4009
	eorl	R(d0),R(d1)
Packit 6c4009
Packit 6c4009
	/* Add the magic value.  We get carry bits reported for each byte
Packit 6c4009
	   which is not C.  */
Packit 6c4009
	movel	R(d3),R(d2)
Packit 6c4009
	addl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Check the fourth carry bit before it is clobbered by the next
Packit 6c4009
	   XOR.  If it is not set we have a hit.  */
Packit 6c4009
	bcc	L(L8)
Packit 6c4009
Packit 6c4009
	/* We are only interested in carry bits that change due to the
Packit 6c4009
	   previous add, so remove original bits */
Packit 6c4009
	eorl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Now test for the other three overflow bits.
Packit 6c4009
	   Set all non-carry bits.  */
Packit 6c4009
	orl	R(d3),R(d2)
Packit 6c4009
	/* Add 1 to get zero if all carry bits were set.  */
Packit 6c4009
	addql	#1,R(d2)
Packit 6c4009
Packit 6c4009
	/* If we don't get zero then at least one byte of the word equals
Packit 6c4009
	   C.  */
Packit 6c4009
	bne	L(L8)
Packit 6c4009
Packit 6c4009
	/* Next look for a NUL byte.
Packit 6c4009
	   Restore original longword without reload.  */
Packit 6c4009
	eorl	R(d0),R(d1)
Packit 6c4009
	/* Add the magic value.  We get carry bits reported for each byte
Packit 6c4009
	   which is not NUL.  */
Packit 6c4009
	movel	R(d3),R(d2)
Packit 6c4009
	addl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Check the fourth carry bit before it is clobbered by the next
Packit 6c4009
	   XOR.  If it is not set we have a hit, and return NULL.  */
Packit 6c4009
	bcc	L(L3)
Packit 6c4009
Packit 6c4009
	/* We are only interested in carry bits that change due to the
Packit 6c4009
	   previous add, so remove original bits */
Packit 6c4009
	eorl	R(d1),R(d2)
Packit 6c4009
Packit 6c4009
	/* Now test for the other three overflow bits.
Packit 6c4009
	   Set all non-carry bits.  */
Packit 6c4009
	orl	R(d3),R(d2)
Packit 6c4009
	/* Add 1 to get zero if all carry bits were set.  */
Packit 6c4009
	addql	#1,R(d2)
Packit 6c4009
Packit 6c4009
	/* If we don't get zero then at least one byte of the word was NUL
Packit 6c4009
	   and we return NULL.  Otherwise continue with the next longword.  */
Packit 6c4009
	beq	L(L2)
Packit 6c4009
Packit 6c4009
L(L3:)
Packit 6c4009
	/* Return NULL.  */
Packit 6c4009
	clrl	R(d0)
Packit 6c4009
	movel	R(d0),R(a0)
Packit 6c4009
	movel	MEM_POSTINC(sp),R(d3)
Packit 6c4009
	cfi_remember_state
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	cfi_restore (R(d3))
Packit 6c4009
	movel	MEM_POSTINC(sp),R(d2)
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	cfi_restore (R(d2))
Packit 6c4009
	rts
Packit 6c4009
Packit 6c4009
	cfi_restore_state
Packit 6c4009
L(L8:)
Packit 6c4009
	/* We have a hit.  Check to see which byte it was.  First
Packit 6c4009
	   compensate for the autoincrement in the loop.  */
Packit 6c4009
	subql	#4,R(a0)
Packit 6c4009
Packit 6c4009
	moveb	MEM(a0),R(d1)
Packit 6c4009
	cmpb	R(d0),R(d1)
Packit 6c4009
	beq	L(L9)
Packit 6c4009
	tstb	R(d1)
Packit 6c4009
	beq	L(L3)
Packit 6c4009
	addql	#1,R(a0)
Packit 6c4009
Packit 6c4009
	moveb	MEM(a0),R(d1)
Packit 6c4009
	cmpb	R(d0),R(d1)
Packit 6c4009
	beq	L(L9)
Packit 6c4009
	tstb	R(d1)
Packit 6c4009
	beq	L(L3)
Packit 6c4009
	addql	#1,R(a0)
Packit 6c4009
Packit 6c4009
	moveb	MEM(a0),R(d1)
Packit 6c4009
	cmpb	R(d0),R(d1)
Packit 6c4009
	beq	L(L9)
Packit 6c4009
	tstb	R(d1)
Packit 6c4009
	beq	L(L3)
Packit 6c4009
	addql	#1,R(a0)
Packit 6c4009
Packit 6c4009
	/* Otherwise the fourth byte must equal C.  */
Packit 6c4009
L(L9:)
Packit 6c4009
	movel	R(a0),R(d0)
Packit 6c4009
	movel	MEM_POSTINC(sp),R(d3)
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	cfi_restore (R(d3))
Packit 6c4009
	movel	MEM_POSTINC(sp),R(d2)
Packit 6c4009
	cfi_adjust_cfa_offset (-4)
Packit 6c4009
	cfi_restore (R(d2))
Packit 6c4009
	rts
Packit 6c4009
END(strchr)
Packit 6c4009
Packit 6c4009
weak_alias (strchr, index)
Packit 6c4009
libc_hidden_builtin_def (strchr)