^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * arch/alpha/lib/strncat.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Contributed by Richard Henderson (rth@tamu.edu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Append no more than COUNT characters from the null-terminated string SRC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * to the null-terminated string DST. Always null-terminate the new DST.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * This differs slightly from the semantics in libc in that we never write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * past count, whereas libc may write to count+1. This follows the generic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * implementation in lib/string.c and is, IMHO, more sensible.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) .text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) .align 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) .globl strncat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) .ent strncat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) strncat:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) .frame $30, 0, $26
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) .prologue 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) mov $16, $0 # set up return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) beq $18, $zerocount
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) /* Find the end of the string. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) ldq_u $1, 0($16) # load first quadword ($16 may be misaligned)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) lda $2, -1($31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) insqh $2, $16, $2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) andnot $16, 7, $16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) or $2, $1, $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) cmpbge $31, $1, $2 # bits set iff byte == 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) bne $2, $found
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) $loop: ldq $1, 8($16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) addq $16, 8, $16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) cmpbge $31, $1, $2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) beq $2, $loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) $found: negq $2, $3 # clear all but least set bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) and $2, $3, $2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) and $2, 0xf0, $3 # binary search for that set bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) and $2, 0xcc, $4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) and $2, 0xaa, $5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) cmovne $3, 4, $3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) cmovne $4, 2, $4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) cmovne $5, 1, $5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) addq $3, $4, $3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) addq $16, $5, $16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) addq $16, $3, $16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* Now do the append. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) bsr $23, __stxncpy
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* Worry about the null termination. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) zapnot $1, $27, $2 # was last byte a null?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) bne $2, 0f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ret
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) 0: cmplt $27, $24, $2 # did we fill the buffer completely?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) or $2, $18, $2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) bne $2, 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) and $24, 0x80, $2 # no zero next byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) bne $2, 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* Here there are bytes left in the current word. Clear one. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) addq $24, $24, $24 # end-of-count bit <<= 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) 2: zap $1, $24, $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) stq_u $1, 0($16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ret
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) 1: /* Here we must read the next DST word and clear the first byte. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ldq_u $1, 8($16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) zap $1, 1, $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) stq_u $1, 8($16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) $zerocount:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) ret
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) .end strncat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) EXPORT_SYMBOL(strncat)