Blame sysdeps/alpha/stxncpy.S

Packit Service 82fcde
/* Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   Contributed by Richard Henderson (rth@tamu.edu)
Packit Service 82fcde
   This file is part of the GNU C Library.
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
/* Copy no more than COUNT bytes of the null-terminated string from
Packit Service 82fcde
   SRC to DST.
Packit Service 82fcde
Packit Service 82fcde
   This is an internal routine used by strncpy, stpncpy, and strncat.
Packit Service 82fcde
   As such, it uses special linkage conventions to make implementation
Packit Service 82fcde
   of these public functions more efficient.
Packit Service 82fcde
Packit Service 82fcde
   On input:
Packit Service 82fcde
	t9 = return address
Packit Service 82fcde
	a0 = DST
Packit Service 82fcde
	a1 = SRC
Packit Service 82fcde
	a2 = COUNT
Packit Service 82fcde
Packit Service 82fcde
   Furthermore, COUNT may not be zero.
Packit Service 82fcde
Packit Service 82fcde
   On output:
Packit Service 82fcde
	t0  = last word written
Packit Service 82fcde
	t8  = bitmask (with one bit set) indicating the last byte written
Packit Service 82fcde
	t10 = bitmask (with one bit set) indicating the byte position of
Packit Service 82fcde
	      the end of the range specified by COUNT
Packit Service 82fcde
	a0  = unaligned address of the last *word* written
Packit Service 82fcde
	a2  = the number of full words left in COUNT
Packit Service 82fcde
Packit Service 82fcde
   Furthermore, v0, a3-a5, t11, and t12 are untouched.
Packit Service 82fcde
*/
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* This is generally scheduled for the EV5, but should still be pretty
Packit Service 82fcde
   good for the EV4 too.  */
Packit Service 82fcde
Packit Service 82fcde
#include <sysdep.h>
Packit Service 82fcde
Packit Service 82fcde
	.set noat
Packit Service 82fcde
	.set noreorder
Packit Service 82fcde
Packit Service 82fcde
	.text
Packit Service 82fcde
	.type	__stxncpy, @function
Packit Service 82fcde
	.globl	__stxncpy
Packit Service 82fcde
	.usepv	__stxncpy, no
Packit Service 82fcde
Packit Service 82fcde
	cfi_startproc
Packit Service 82fcde
	cfi_return_column (t9)
Packit Service 82fcde
Packit Service 82fcde
	/* On entry to this basic block:
Packit Service 82fcde
	   t0 == the first destination word for masking back in
Packit Service 82fcde
	   t1 == the first source word.  */
Packit Service 82fcde
	.align 3
Packit Service 82fcde
stxncpy_aligned:
Packit Service 82fcde
	/* Create the 1st output word and detect 0's in the 1st input word.  */
Packit Service 82fcde
	lda	t2, -1		# e1    : build a mask against false zero
Packit Service 82fcde
	mskqh	t2, a1, t2	# e0    :   detection in the src word
Packit Service 82fcde
	mskqh	t1, a1, t3	# e0    :
Packit Service 82fcde
	ornot	t1, t2, t2	# .. e1 :
Packit Service 82fcde
	mskql	t0, a1, t0	# e0    : assemble the first output word
Packit Service 82fcde
	cmpbge	zero, t2, t7	# .. e1 : bits set iff null found
Packit Service 82fcde
	or	t0, t3, t0	# e0    :
Packit Service 82fcde
	beq	a2, $a_eoc	# .. e1 :
Packit Service 82fcde
	bne	t7, $a_eos	# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	/* On entry to this basic block:
Packit Service 82fcde
	   t0 == a source word not containing a null.  */
Packit Service 82fcde
$a_loop:
Packit Service 82fcde
	stq_u	t0, 0(a0)	# e0    :
Packit Service 82fcde
	addq	a0, 8, a0	# .. e1 :
Packit Service 82fcde
	ldq_u	t0, 0(a1)	# e0    :
Packit Service 82fcde
	addq	a1, 8, a1	# .. e1 :
Packit Service 82fcde
	subq	a2, 1, a2	# e0    :
Packit Service 82fcde
	cmpbge	zero, t0, t7	# .. e1 (stall)
Packit Service 82fcde
	beq	a2, $a_eoc      # e1    :
Packit Service 82fcde
	beq	t7, $a_loop	# e1    :
Packit Service 82fcde
Packit Service 82fcde
	/* Take care of the final (partial) word store.  At this point
Packit Service 82fcde
	   the end-of-count bit is set in t7 iff it applies.
Packit Service 82fcde
Packit Service 82fcde
	   On entry to this basic block we have:
Packit Service 82fcde
	   t0 == the source word containing the null
Packit Service 82fcde
	   t7 == the cmpbge mask that found it.  */
Packit Service 82fcde
$a_eos:
Packit Service 82fcde
	negq	t7, t8		# e0    : find low bit set
Packit Service 82fcde
	and	t7, t8, t8	# e1 (stall)
Packit Service 82fcde
Packit Service 82fcde
	/* For the sake of the cache, don't read a destination word
Packit Service 82fcde
	   if we're not going to need it.  */
Packit Service 82fcde
	and	t8, 0x80, t6	# e0    :
Packit Service 82fcde
	bne	t6, 1f		# .. e1 (zdb)
Packit Service 82fcde
Packit Service 82fcde
	/* We're doing a partial word store and so need to combine
Packit Service 82fcde
	   our source and original destination words.  */
Packit Service 82fcde
	ldq_u	t1, 0(a0)	# e0    :
Packit Service 82fcde
	subq	t8, 1, t6	# .. e1 :
Packit Service 82fcde
	or	t8, t6, t7	# e0    :
Packit Service 82fcde
	unop			#
Packit Service 82fcde
	zapnot	t0, t7, t0	# e0    : clear src bytes > null
Packit Service 82fcde
	zap	t1, t7, t1	# .. e1 : clear dst bytes <= null
Packit Service 82fcde
	or	t0, t1, t0	# e1    :
Packit Service 82fcde
Packit Service 82fcde
1:	stq_u	t0, 0(a0)	# e0    :
Packit Service 82fcde
	ret	(t9)		# e1    :
Packit Service 82fcde
Packit Service 82fcde
	/* Add the end-of-count bit to the eos detection bitmask.  */
Packit Service 82fcde
$a_eoc:
Packit Service 82fcde
	or	t10, t7, t7
Packit Service 82fcde
	br	$a_eos
Packit Service 82fcde
Packit Service 82fcde
	.align 3
Packit Service 82fcde
__stxncpy:
Packit Service 82fcde
	/* Are source and destination co-aligned?  */
Packit Service 82fcde
	lda	t2, -1
Packit Service 82fcde
	xor	a0, a1, t1
Packit Service 82fcde
	srl	t2, 1, t2
Packit Service 82fcde
	and	a0, 7, t0		# find dest misalignment
Packit Service 82fcde
	cmovlt	a2, t2, a2		# bound neg count to LONG_MAX
Packit Service 82fcde
	and	t1, 7, t1
Packit Service 82fcde
	addq	a2, t0, a2		# bias count by dest misalignment
Packit Service 82fcde
	subq	a2, 1, a2
Packit Service 82fcde
	and	a2, 7, t2
Packit Service 82fcde
	srl	a2, 3, a2		# a2 = loop counter = (count - 1)/8
Packit Service 82fcde
	addq	zero, 1, t10
Packit Service 82fcde
	sll	t10, t2, t10		# t10 = bitmask of last count byte
Packit Service 82fcde
	bne	t1, $unaligned
Packit Service 82fcde
Packit Service 82fcde
	/* We are co-aligned; take care of a partial first word.  */
Packit Service 82fcde
Packit Service 82fcde
	ldq_u	t1, 0(a1)	# e0    : load first src word
Packit Service 82fcde
	addq	a1, 8, a1	# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	beq	t0, stxncpy_aligned     # avoid loading dest word if not needed
Packit Service 82fcde
	ldq_u	t0, 0(a0)	# e0    :
Packit Service 82fcde
	br	stxncpy_aligned	# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* The source and destination are not co-aligned.  Align the destination
Packit Service 82fcde
   and cope.  We have to be very careful about not reading too much and
Packit Service 82fcde
   causing a SEGV.  */
Packit Service 82fcde
Packit Service 82fcde
	.align 3
Packit Service 82fcde
$u_head:
Packit Service 82fcde
	/* We know just enough now to be able to assemble the first
Packit Service 82fcde
	   full source word.  We can still find a zero at the end of it
Packit Service 82fcde
	   that prevents us from outputting the whole thing.
Packit Service 82fcde
Packit Service 82fcde
	   On entry to this basic block:
Packit Service 82fcde
	   t0 == the first dest word, unmasked
Packit Service 82fcde
	   t1 == the shifted low bits of the first source word
Packit Service 82fcde
	   t6 == bytemask that is -1 in dest word bytes */
Packit Service 82fcde
Packit Service 82fcde
	ldq_u	t2, 8(a1)	# e0    : load second src word
Packit Service 82fcde
	addq	a1, 8, a1	# .. e1 :
Packit Service 82fcde
	mskql	t0, a0, t0	# e0    : mask trailing garbage in dst
Packit Service 82fcde
	extqh	t2, a1, t4	# e0    :
Packit Service 82fcde
	or	t1, t4, t1	# e1    : first aligned src word complete
Packit Service 82fcde
	mskqh	t1, a0, t1	# e0    : mask leading garbage in src
Packit Service 82fcde
	or	t0, t1, t0	# e0    : first output word complete
Packit Service 82fcde
	or	t0, t6, t6	# e1    : mask original data for zero test
Packit Service 82fcde
	cmpbge	zero, t6, t7	# e0    :
Packit Service 82fcde
	beq	a2, $u_eocfin	# .. e1 :
Packit Service 82fcde
	lda	t6, -1		# e0    :
Packit Service 82fcde
	bne	t7, $u_final	# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	mskql	t6, a1, t6		# e0    : mask out bits already seen
Packit Service 82fcde
	nop				# .. e1 :
Packit Service 82fcde
	stq_u	t0, 0(a0)		# e0    : store first output word
Packit Service 82fcde
	or      t6, t2, t2		# .. e1 :
Packit Service 82fcde
	cmpbge	zero, t2, t7		# e0    : find nulls in second partial
Packit Service 82fcde
	addq	a0, 8, a0		# .. e1 :
Packit Service 82fcde
	subq	a2, 1, a2		# e0    :
Packit Service 82fcde
	bne	t7, $u_late_head_exit	# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	/* Finally, we've got all the stupid leading edge cases taken care
Packit Service 82fcde
	   of and we can set up to enter the main loop.  */
Packit Service 82fcde
Packit Service 82fcde
	extql	t2, a1, t1	# e0    : position hi-bits of lo word
Packit Service 82fcde
	beq	a2, $u_eoc	# .. e1 :
Packit Service 82fcde
	ldq_u	t2, 8(a1)	# e0    : read next high-order source word
Packit Service 82fcde
	addq	a1, 8, a1	# .. e1 :
Packit Service 82fcde
	extqh	t2, a1, t0	# e0    : position lo-bits of hi word
Packit Service 82fcde
	cmpbge	zero, t2, t7	# .. e1 : test new word for eos
Packit Service 82fcde
	nop			# e0    :
Packit Service 82fcde
	bne	t7, $u_eos	# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	/* Unaligned copy main loop.  In order to avoid reading too much,
Packit Service 82fcde
	   the loop is structured to detect zeros in aligned source words.
Packit Service 82fcde
	   This has, unfortunately, effectively pulled half of a loop
Packit Service 82fcde
	   iteration out into the head and half into the tail, but it does
Packit Service 82fcde
	   prevent nastiness from accumulating in the very thing we want
Packit Service 82fcde
	   to run as fast as possible.
Packit Service 82fcde
Packit Service 82fcde
	   On entry to this basic block:
Packit Service 82fcde
	   t0 == the shifted low-order bits from the current source word
Packit Service 82fcde
	   t1 == the shifted high-order bits from the previous source word
Packit Service 82fcde
	   t2 == the unshifted current source word
Packit Service 82fcde
Packit Service 82fcde
	   We further know that t2 does not contain a null terminator.  */
Packit Service 82fcde
Packit Service 82fcde
	.align 3
Packit Service 82fcde
$u_loop:
Packit Service 82fcde
	or	t0, t1, t0	# e0    : current dst word now complete
Packit Service 82fcde
	subq	a2, 1, a2	# .. e1 : decrement word count
Packit Service 82fcde
	stq_u	t0, 0(a0)	# e0    : save the current word
Packit Service 82fcde
	addq	a0, 8, a0	# .. e1 :
Packit Service 82fcde
	extql	t2, a1, t1	# e0    : extract high bits for next time
Packit Service 82fcde
	beq	a2, $u_eoc	# .. e1 :
Packit Service 82fcde
	ldq_u	t2, 8(a1)	# e0    : load high word for next time
Packit Service 82fcde
	addq	a1, 8, a1	# .. e1 :
Packit Service 82fcde
	nop			# e0    :
Packit Service 82fcde
	cmpbge	zero, t2, t7	# .. e1 : test new word for eos
Packit Service 82fcde
	extqh	t2, a1, t0	# e0    : extract low bits for current word
Packit Service 82fcde
	beq	t7, $u_loop	# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	/* We've found a zero somewhere in the source word we just read.
Packit Service 82fcde
	   If it resides in the lower half, we have one (probably partial)
Packit Service 82fcde
	   word to write out, and if it resides in the upper half, we
Packit Service 82fcde
	   have one full and one partial word left to write out.
Packit Service 82fcde
Packit Service 82fcde
	   On entry to this basic block:
Packit Service 82fcde
	   t0 == the shifted low-order bits from the current source word
Packit Service 82fcde
	   t1 == the shifted high-order bits from the previous source word
Packit Service 82fcde
	   t2 == the unshifted current source word.  */
Packit Service 82fcde
$u_eos:
Packit Service 82fcde
	or	t0, t1, t0	# e0    : first (partial) source word complete
Packit Service 82fcde
	cmpbge	zero, t0, t7	# e0    : is the null in this first bit?
Packit Service 82fcde
	bne	t7, $u_final	# .. e1 (zdb)
Packit Service 82fcde
Packit Service 82fcde
	stq_u	t0, 0(a0)	# e0    : the null was in the high-order bits
Packit Service 82fcde
	addq	a0, 8, a0	# .. e1 :
Packit Service 82fcde
	subq	a2, 1, a2	# e0    :
Packit Service 82fcde
Packit Service 82fcde
$u_late_head_exit:
Packit Service 82fcde
	extql	t2, a1, t0	# e0    :
Packit Service 82fcde
	cmpbge	zero, t0, t7	# e0    :
Packit Service 82fcde
	or	t7, t10, t6	# e1    :
Packit Service 82fcde
	cmoveq	a2, t6, t7	# e0    :
Packit Service 82fcde
Packit Service 82fcde
	/* Take care of a final (probably partial) result word.
Packit Service 82fcde
	   On entry to this basic block:
Packit Service 82fcde
	   t0 == assembled source word
Packit Service 82fcde
	   t7 == cmpbge mask that found the null.  */
Packit Service 82fcde
$u_final:
Packit Service 82fcde
	negq	t7, t6		# e0    : isolate low bit set
Packit Service 82fcde
	and	t6, t7, t8	# e1    :
Packit Service 82fcde
Packit Service 82fcde
	and	t8, 0x80, t6	# e0    : avoid dest word load if we can
Packit Service 82fcde
	bne	t6, 1f		# .. e1 (zdb)
Packit Service 82fcde
Packit Service 82fcde
	ldq_u	t1, 0(a0)	# e0    :
Packit Service 82fcde
	subq	t8, 1, t6	# .. e1 :
Packit Service 82fcde
	or	t6, t8, t7	# e0    :
Packit Service 82fcde
	zapnot	t0, t7, t0	# .. e1 : kill source bytes > null
Packit Service 82fcde
	zap	t1, t7, t1	# e0    : kill dest bytes <= null
Packit Service 82fcde
	or	t0, t1, t0	# e1    :
Packit Service 82fcde
Packit Service 82fcde
1:	stq_u	t0, 0(a0)	# e0    :
Packit Service 82fcde
	ret	(t9)		# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	/* Got to end-of-count before end of string.
Packit Service 82fcde
	   On entry to this basic block:
Packit Service 82fcde
	   t1 == the shifted high-order bits from the previous source word  */
Packit Service 82fcde
$u_eoc:
Packit Service 82fcde
	and	a1, 7, t6	# e1    :
Packit Service 82fcde
	sll	t10, t6, t6	# e0    :
Packit Service 82fcde
	and	t6, 0xff, t6	# e0	:
Packit Service 82fcde
	bne	t6, 1f		# e1    : avoid src word load if we can
Packit Service 82fcde
Packit Service 82fcde
	ldq_u	t2, 8(a1)	# e0    : load final src word
Packit Service 82fcde
	nop			# .. e1 :
Packit Service 82fcde
	extqh	t2, a1, t0	# e0    : extract high bits for last word
Packit Service 82fcde
	or	t1, t0, t1	# e1    :
Packit Service 82fcde
Packit Service 82fcde
1:	cmpbge	zero, t1, t7
Packit Service 82fcde
	mov	t1, t0
Packit Service 82fcde
Packit Service 82fcde
$u_eocfin:			# end-of-count, final word
Packit Service 82fcde
	or	t10, t7, t7
Packit Service 82fcde
	br	$u_final
Packit Service 82fcde
Packit Service 82fcde
	/* Unaligned copy entry point.  */
Packit Service 82fcde
	.align 3
Packit Service 82fcde
$unaligned:
Packit Service 82fcde
Packit Service 82fcde
	ldq_u	t1, 0(a1)	# e0    : load first source word
Packit Service 82fcde
Packit Service 82fcde
	and	a0, 7, t4	# .. e1 : find dest misalignment
Packit Service 82fcde
	and	a1, 7, t5	# e0    : find src misalignment
Packit Service 82fcde
Packit Service 82fcde
	/* Conditionally load the first destination word and a bytemask
Packit Service 82fcde
	   with 0xff indicating that the destination byte is sacrosanct.  */
Packit Service 82fcde
Packit Service 82fcde
	mov	zero, t0	# .. e1 :
Packit Service 82fcde
	mov	zero, t6	# e0    :
Packit Service 82fcde
	beq	t4, 1f		# .. e1 :
Packit Service 82fcde
	ldq_u	t0, 0(a0)	# e0    :
Packit Service 82fcde
	lda	t6, -1		# .. e1 :
Packit Service 82fcde
	mskql	t6, a0, t6	# e0    :
Packit Service 82fcde
1:
Packit Service 82fcde
	subq	a1, t4, a1	# .. e1 : sub dest misalignment from src addr
Packit Service 82fcde
Packit Service 82fcde
	/* If source misalignment is larger than dest misalignment, we need
Packit Service 82fcde
	   extra startup checks to avoid SEGV.  */
Packit Service 82fcde
Packit Service 82fcde
	cmplt	t4, t5, t8	# e1    :
Packit Service 82fcde
	extql	t1, a1, t1	# .. e0 : shift src into place
Packit Service 82fcde
	lda	t2, -1		# e0    : for creating masks later
Packit Service 82fcde
	beq	t8, $u_head	# e1    :
Packit Service 82fcde
Packit Service 82fcde
	mskqh	t2, t5, t2	# e0    : begin src byte validity mask
Packit Service 82fcde
	cmpbge	zero, t1, t7	# .. e1 : is there a zero?
Packit Service 82fcde
	extql	t2, a1, t2	# e0    :
Packit Service 82fcde
	or	t7, t10, t5	# .. e1 : test for end-of-count too
Packit Service 82fcde
	cmpbge	zero, t2, t3	# e0    :
Packit Service 82fcde
	cmoveq	a2, t5, t7	# .. e1 :
Packit Service 82fcde
	andnot	t7, t3, t7	# e0    :
Packit Service 82fcde
	beq	t7, $u_head	# .. e1 (zdb)
Packit Service 82fcde
Packit Service 82fcde
	/* At this point we've found a zero in the first partial word of
Packit Service 82fcde
	   the source.  We need to isolate the valid source data and mask
Packit Service 82fcde
	   it into the original destination data.  (Incidentally, we know
Packit Service 82fcde
	   that we'll need at least one byte of that original dest word.) */
Packit Service 82fcde
Packit Service 82fcde
	ldq_u	t0, 0(a0)	# e0    :
Packit Service 82fcde
	negq	t7, t6		# .. e1 : build bitmask of bytes <= zero
Packit Service 82fcde
	mskqh	t1, t4, t1	# e0    :
Packit Service 82fcde
	and	t6, t7, t8	# .. e1 :
Packit Service 82fcde
	subq	t8, 1, t6	# e0    :
Packit Service 82fcde
	or	t6, t8, t7	# e1    :
Packit Service 82fcde
Packit Service 82fcde
	zapnot	t2, t7, t2	# e0    : prepare source word; mirror changes
Packit Service 82fcde
	zapnot	t1, t7, t1	# .. e1 : to source validity mask
Packit Service 82fcde
Packit Service 82fcde
	andnot	t0, t2, t0	# e0    : zero place for source to reside
Packit Service 82fcde
	or	t0, t1, t0	# e1    : and put it there
Packit Service 82fcde
	stq_u	t0, 0(a0)	# e0    :
Packit Service 82fcde
	ret	(t9)		# .. e1 :
Packit Service 82fcde
Packit Service 82fcde
	cfi_endproc