18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * arch/alpha/lib/strncat.S
48c2ecf20Sopenharmony_ci * Contributed by Richard Henderson (rth@tamu.edu)
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Append no more than COUNT characters from the null-terminated string SRC
78c2ecf20Sopenharmony_ci * to the null-terminated string DST.  Always null-terminate the new DST.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This differs slightly from the semantics in libc in that we never write
108c2ecf20Sopenharmony_ci * past count, whereas libc may write to count+1.  This follows the generic
118c2ecf20Sopenharmony_ci * implementation in lib/string.c and is, IMHO, more sensible.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#include <asm/export.h>
148c2ecf20Sopenharmony_ci	.text
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci	.align 3
178c2ecf20Sopenharmony_ci	.globl strncat
188c2ecf20Sopenharmony_ci	.ent strncat
198c2ecf20Sopenharmony_cistrncat:
208c2ecf20Sopenharmony_ci	.frame $30, 0, $26
218c2ecf20Sopenharmony_ci	.prologue 0
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	mov	$16, $0		# set up return value
248c2ecf20Sopenharmony_ci	beq	$18, $zerocount
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	/* Find the end of the string.  */
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	ldq_u   $1, 0($16)	# load first quadword ($16 may be misaligned)
298c2ecf20Sopenharmony_ci	lda     $2, -1($31)
308c2ecf20Sopenharmony_ci	insqh   $2, $16, $2
318c2ecf20Sopenharmony_ci	andnot  $16, 7, $16
328c2ecf20Sopenharmony_ci	or      $2, $1, $1
338c2ecf20Sopenharmony_ci	cmpbge  $31, $1, $2	# bits set iff byte == 0
348c2ecf20Sopenharmony_ci	bne     $2, $found
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci$loop:	ldq     $1, 8($16)
378c2ecf20Sopenharmony_ci	addq    $16, 8, $16
388c2ecf20Sopenharmony_ci	cmpbge  $31, $1, $2
398c2ecf20Sopenharmony_ci	beq     $2, $loop
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci$found:	negq    $2, $3		# clear all but least set bit
428c2ecf20Sopenharmony_ci	and     $2, $3, $2
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	and     $2, 0xf0, $3	# binary search for that set bit
458c2ecf20Sopenharmony_ci	and	$2, 0xcc, $4
468c2ecf20Sopenharmony_ci	and	$2, 0xaa, $5
478c2ecf20Sopenharmony_ci	cmovne	$3, 4, $3
488c2ecf20Sopenharmony_ci	cmovne	$4, 2, $4
498c2ecf20Sopenharmony_ci	cmovne	$5, 1, $5
508c2ecf20Sopenharmony_ci	addq	$3, $4, $3
518c2ecf20Sopenharmony_ci	addq	$16, $5, $16
528c2ecf20Sopenharmony_ci	addq	$16, $3, $16
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	/* Now do the append.  */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	bsr	$23, __stxncpy
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* Worry about the null termination.  */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	zapnot	$1, $27, $2	# was last byte a null?
618c2ecf20Sopenharmony_ci	bne	$2, 0f
628c2ecf20Sopenharmony_ci	ret
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci0:	cmplt	$27, $24, $2	# did we fill the buffer completely?
658c2ecf20Sopenharmony_ci	or	$2, $18, $2
668c2ecf20Sopenharmony_ci	bne	$2, 2f
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	and	$24, 0x80, $2	# no zero next byte
698c2ecf20Sopenharmony_ci	bne	$2, 1f
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	/* Here there are bytes left in the current word.  Clear one.  */
728c2ecf20Sopenharmony_ci	addq	$24, $24, $24	# end-of-count bit <<= 1
738c2ecf20Sopenharmony_ci2:	zap	$1, $24, $1
748c2ecf20Sopenharmony_ci	stq_u	$1, 0($16)
758c2ecf20Sopenharmony_ci	ret
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci1:	/* Here we must read the next DST word and clear the first byte.  */
788c2ecf20Sopenharmony_ci	ldq_u	$1, 8($16)
798c2ecf20Sopenharmony_ci	zap	$1, 1, $1
808c2ecf20Sopenharmony_ci	stq_u	$1, 8($16)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci$zerocount:
838c2ecf20Sopenharmony_ci	ret
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	.end strncat
868c2ecf20Sopenharmony_ci	EXPORT_SYMBOL(strncat)
87