Blame sysdeps/m68k/memchr.S

Packit Service 82fcde
/* memchr (str, ch, n) -- Return pointer to first occurrence of CH in the
Packit Service 82fcde
   first N bytes of STR.
Packit Service 82fcde
   For Motorola 68000.
Packit Service 82fcde
   Copyright (C) 1999-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Andreas Schwab <schwab@gnu.org>.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library.  If not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <sysdep.h>
Packit Service 82fcde
#include "asm-syntax.h"
Packit Service 82fcde
Packit Service 82fcde
	TEXT
Packit Service 82fcde
ENTRY(__memchr)
Packit Service 82fcde
	/* Save the callee-saved registers we use.  */
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	movel	R(d2),MEM_PREDEC(sp)
Packit Service 82fcde
	cfi_adjust_cfa_offset (4)
Packit Service 82fcde
	movel	R(d3),MEM_PREDEC(sp)
Packit Service 82fcde
	cfi_adjust_cfa_offset (4)
Packit Service 82fcde
	movel	R(d4),MEM_PREDEC(sp)
Packit Service 82fcde
	cfi_adjust_cfa_offset (4)
Packit Service 82fcde
	cfi_rel_offset (R(d2), 8)
Packit Service 82fcde
	cfi_rel_offset (R(d3), 4)
Packit Service 82fcde
	cfi_rel_offset (R(d4), 0)
Packit Service 82fcde
#else
Packit Service 82fcde
	moveml	R(d2)-R(d4),MEM_PREDEC(sp)
Packit Service 82fcde
	cfi_adjust_cfa_offset (3*4)
Packit Service 82fcde
	cfi_rel_offset (R(d2), 0)
Packit Service 82fcde
	cfi_rel_offset (R(d3), 4)
Packit Service 82fcde
	cfi_rel_offset (R(d4), 8)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
	/* Get string pointer, character and length.  */
Packit Service 82fcde
	movel	MEM_DISP(sp,16),R(a0)
Packit Service 82fcde
	moveb	MEM_DISP(sp,23),R(d0)
Packit Service 82fcde
	movel	MEM_DISP(sp,24),R(d4)
Packit Service 82fcde
Packit Service 82fcde
	/* Check if at least four bytes left to search.  */
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	subql	#4,R(d4)
Packit Service 82fcde
	bcs	L(L6)
Packit Service 82fcde
	addql	#4,R(d4)
Packit Service 82fcde
#else
Packit Service 82fcde
	moveql	#4,R(d1)
Packit Service 82fcde
	cmpl	R(d1),R(d4)
Packit Service 82fcde
	bcs	L(L6)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
	/* Distribute the character to all bytes of a longword.  */
Packit Service 82fcde
	movel	R(d0),R(d1)
Packit Service 82fcde
	lsll	#8,R(d1)
Packit Service 82fcde
	moveb	R(d0),R(d1)
Packit Service 82fcde
	movel	R(d1),R(d0)
Packit Service 82fcde
	swap	R(d0)
Packit Service 82fcde
	movew	R(d1),R(d0)
Packit Service 82fcde
Packit Service 82fcde
	/* First search for the character one byte at a time until the
Packit Service 82fcde
	   pointer is aligned to a longword boundary.  */
Packit Service 82fcde
	movel	R(a0),R(d1)
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	andl	#3,R(d1)
Packit Service 82fcde
#else
Packit Service 82fcde
	andw	#3,R(d1)
Packit Service 82fcde
#endif
Packit Service 82fcde
	beq	L(L1)
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
	subql	#1,R(d4)
Packit Service 82fcde
	beq	L(L7)
Packit Service 82fcde
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	subql	#3,R(d1)
Packit Service 82fcde
#else
Packit Service 82fcde
	subqw	#3,R(d1)
Packit Service 82fcde
#endif
Packit Service 82fcde
	beq	L(L1)
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
	subql	#1,R(d4)
Packit Service 82fcde
	beq	L(L7)
Packit Service 82fcde
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	addql	#1,R(d1)
Packit Service 82fcde
#else
Packit Service 82fcde
	addqw	#1,R(d1)
Packit Service 82fcde
#endif
Packit Service 82fcde
	beq	L(L1)
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
	subql	#1,R(d4)
Packit Service 82fcde
	beq	L(L7)
Packit Service 82fcde
Packit Service 82fcde
L(L1:)
Packit Service 82fcde
	/* Load the magic bits.  Unlike the generic implementation we can
Packit Service 82fcde
	   use the carry bit as the fourth hole.  */
Packit Service 82fcde
	movel	#0xfefefeff,R(d3)
Packit Service 82fcde
Packit Service 82fcde
      /* We exit the loop if adding MAGIC_BITS to LONGWORD fails to
Packit Service 82fcde
	 change any of the hole bits of LONGWORD.
Packit Service 82fcde
Packit Service 82fcde
	 1) Is this safe?  Will it catch all the zero bytes?
Packit Service 82fcde
	 Suppose there is a byte with all zeros.  Any carry bits
Packit Service 82fcde
	 propagating from its left will fall into the hole at its
Packit Service 82fcde
	 least significant bit and stop.  Since there will be no
Packit Service 82fcde
	 carry from its most significant bit, the LSB of the
Packit Service 82fcde
	 byte to the left will be unchanged, and the zero will be
Packit Service 82fcde
	 detected.
Packit Service 82fcde
Packit Service 82fcde
	 2) Is this worthwhile?  Will it ignore everything except
Packit Service 82fcde
	 zero bytes?  Suppose every byte of LONGWORD has a bit set
Packit Service 82fcde
	 somewhere.  There will be a carry into bit 8.	If bit 8
Packit Service 82fcde
	 is set, this will carry into bit 16.  If bit 8 is clear,
Packit Service 82fcde
	 one of bits 9-15 must be set, so there will be a carry
Packit Service 82fcde
	 into bit 16.  Similarly, there will be a carry into bit
Packit Service 82fcde
	 24.  If one of bits 24-31 is set, there will be a carry
Packit Service 82fcde
	 into bit 32 (=carry flag), so all of the hole bits will
Packit Service 82fcde
	 be changed.
Packit Service 82fcde
Packit Service 82fcde
	 3) But wait!  Aren't we looking for C, not zero?
Packit Service 82fcde
	 Good point.  So what we do is XOR LONGWORD with a longword,
Packit Service 82fcde
	 each of whose bytes is C.  This turns each byte that is C
Packit Service 82fcde
	 into a zero.  */
Packit Service 82fcde
Packit Service 82fcde
	/* Still at least 4 bytes to search?  */
Packit Service 82fcde
	subql	#4,R(d4)
Packit Service 82fcde
	bcs	L(L6)
Packit Service 82fcde
Packit Service 82fcde
L(L2:)
Packit Service 82fcde
	/* Get the longword in question.  */
Packit Service 82fcde
	movel	MEM_POSTINC(a0),R(d1)
Packit Service 82fcde
	/* XOR with the byte we search for.  */
Packit Service 82fcde
	eorl	R(d0),R(d1)
Packit Service 82fcde
Packit Service 82fcde
	/* Add the magic value.  We get carry bits reported for each byte
Packit Service 82fcde
	   which is not C.  */
Packit Service 82fcde
	movel	R(d3),R(d2)
Packit Service 82fcde
	addl	R(d1),R(d2)
Packit Service 82fcde
Packit Service 82fcde
	/* Check the fourth carry bit before it is clobbered by the next
Packit Service 82fcde
	   XOR.  If it is not set we have a hit.  */
Packit Service 82fcde
	bcc	L(L8)
Packit Service 82fcde
Packit Service 82fcde
	/* We are only interested in carry bits that change due to the
Packit Service 82fcde
	   previous add, so remove original bits.  */
Packit Service 82fcde
	eorl	R(d1),R(d2)
Packit Service 82fcde
Packit Service 82fcde
	/* Now test for the other three overflow bits.
Packit Service 82fcde
	   Set all non-carry bits.  */
Packit Service 82fcde
	orl	R(d3),R(d2)
Packit Service 82fcde
	/* Add 1 to get zero if all carry bits were set.  */
Packit Service 82fcde
	addql	#1,R(d2)
Packit Service 82fcde
Packit Service 82fcde
	/* If we don't get zero then at least one byte of the word equals
Packit Service 82fcde
	   C.  */
Packit Service 82fcde
	bne	L(L8)
Packit Service 82fcde
Packit Service 82fcde
	/* Still at least 4 bytes to search?  */
Packit Service 82fcde
	subql	#4,R(d4)
Packit Service 82fcde
	bcs	L(L6)
Packit Service 82fcde
Packit Service 82fcde
	/* Get the longword in question.  */
Packit Service 82fcde
	movel	MEM_POSTINC(a0),R(d1)
Packit Service 82fcde
	/* XOR with the byte we search for.  */
Packit Service 82fcde
	eorl	R(d0),R(d1)
Packit Service 82fcde
Packit Service 82fcde
	/* Add the magic value.  We get carry bits reported for each byte
Packit Service 82fcde
	   which is not C.  */
Packit Service 82fcde
	movel	R(d3),R(d2)
Packit Service 82fcde
	addl	R(d1),R(d2)
Packit Service 82fcde
Packit Service 82fcde
	/* Check the fourth carry bit before it is clobbered by the next
Packit Service 82fcde
	   XOR.  If it is not set we have a hit.  */
Packit Service 82fcde
	bcc	L(L8)
Packit Service 82fcde
Packit Service 82fcde
	/* We are only interested in carry bits that change due to the
Packit Service 82fcde
	   previous add, so remove original bits */
Packit Service 82fcde
	eorl	R(d1),R(d2)
Packit Service 82fcde
Packit Service 82fcde
	/* Now test for the other three overflow bits.
Packit Service 82fcde
	   Set all non-carry bits.  */
Packit Service 82fcde
	orl	R(d3),R(d2)
Packit Service 82fcde
	/* Add 1 to get zero if all carry bits were set.  */
Packit Service 82fcde
	addql	#1,R(d2)
Packit Service 82fcde
Packit Service 82fcde
	/* If we don't get zero then at least one byte of the word equals
Packit Service 82fcde
	   C.  */
Packit Service 82fcde
	bne	L(L8)
Packit Service 82fcde
Packit Service 82fcde
	/* Still at least 4 bytes to search?  */
Packit Service 82fcde
	subql	#4,R(d4)
Packit Service 82fcde
	bcc	L(L2)
Packit Service 82fcde
Packit Service 82fcde
L(L6:)
Packit Service 82fcde
	/* Search one byte at a time in the remaining less than 4 bytes.  */
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	addql	#4,R(d4)
Packit Service 82fcde
#else
Packit Service 82fcde
	andw	#3,R(d4)
Packit Service 82fcde
#endif
Packit Service 82fcde
	beq	L(L7)
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	subql	#1,R(d4)
Packit Service 82fcde
#else
Packit Service 82fcde
	subqw	#1,R(d4)
Packit Service 82fcde
#endif
Packit Service 82fcde
	beq	L(L7)
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	subql	#1,R(d4)
Packit Service 82fcde
#else
Packit Service 82fcde
	subqw	#1,R(d4)
Packit Service 82fcde
#endif
Packit Service 82fcde
	beq	L(L7)
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
Packit Service 82fcde
L(L7:)
Packit Service 82fcde
	/* Return NULL.  */
Packit Service 82fcde
	clrl	R(d0)
Packit Service 82fcde
	movel	R(d0),R(a0)
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	movel	MEM_POSTINC(sp),R(d4)
Packit Service 82fcde
	cfi_remember_state
Packit Service 82fcde
	cfi_adjust_cfa_offset (-4)
Packit Service 82fcde
	cfi_restore (R(d4))
Packit Service 82fcde
	movel	MEM_POSTINC(sp),R(d3)
Packit Service 82fcde
	cfi_adjust_cfa_offset (-4)
Packit Service 82fcde
	cfi_restore (R(d3))
Packit Service 82fcde
	movel	MEM_POSTINC(sp),R(d2)
Packit Service 82fcde
	cfi_adjust_cfa_offset (-4)
Packit Service 82fcde
	cfi_restore (R(d2))
Packit Service 82fcde
#else
Packit Service 82fcde
	moveml	MEM_POSTINC(sp),R(d2)-R(d4)
Packit Service 82fcde
	cfi_remember_state
Packit Service 82fcde
	cfi_adjust_cfa_offset (-3*4)
Packit Service 82fcde
	cfi_restore (R(d2))
Packit Service 82fcde
	cfi_restore (R(d3))
Packit Service 82fcde
	cfi_restore (R(d4))
Packit Service 82fcde
#endif
Packit Service 82fcde
	rts
Packit Service 82fcde
Packit Service 82fcde
	cfi_restore_state
Packit Service 82fcde
L(L8:)
Packit Service 82fcde
	/* We have a hit.  Check to see which byte it was.  First
Packit Service 82fcde
	   compensate for the autoincrement in the loop.  */
Packit Service 82fcde
	subql	#4,R(a0)
Packit Service 82fcde
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
Packit Service 82fcde
	cmpb	MEM(a0),R(d0)
Packit Service 82fcde
	beq	L(L9)
Packit Service 82fcde
	addql	#1,R(a0)
Packit Service 82fcde
Packit Service 82fcde
	/* Otherwise the fourth byte must equal C.  */
Packit Service 82fcde
L(L9:)
Packit Service 82fcde
	movel	R(a0),R(d0)
Packit Service 82fcde
#ifdef __mcoldfire__
Packit Service 82fcde
	movel	MEM_POSTINC(sp),R(d4)
Packit Service 82fcde
	cfi_adjust_cfa_offset (-4)
Packit Service 82fcde
	cfi_restore (R(d4))
Packit Service 82fcde
	movel	MEM_POSTINC(sp),R(d3)
Packit Service 82fcde
	cfi_adjust_cfa_offset (-4)
Packit Service 82fcde
	cfi_restore (R(d3))
Packit Service 82fcde
	movel	MEM_POSTINC(sp),R(d2)
Packit Service 82fcde
	cfi_adjust_cfa_offset (-4)
Packit Service 82fcde
	cfi_restore (R(d2))
Packit Service 82fcde
#else
Packit Service 82fcde
	moveml	MEM_POSTINC(sp),R(d2)-R(d4)
Packit Service 82fcde
	cfi_adjust_cfa_offset (-3*4)
Packit Service 82fcde
	cfi_restore (R(d2))
Packit Service 82fcde
	cfi_restore (R(d3))
Packit Service 82fcde
	cfi_restore (R(d4))
Packit Service 82fcde
#endif
Packit Service 82fcde
	rts
Packit Service 82fcde
END(__memchr)
Packit Service 82fcde
Packit Service 82fcde
weak_alias (__memchr, memchr)
Packit Service 82fcde
libc_hidden_builtin_def (memchr)