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