| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- /* SPDX-License-Identifier: GPL-2.0-only */
- #include <linux/linkage.h>
- #include <asm/asm.h>
- #include <asm/alternative-macros.h>
- #include <asm/hwcap.h>
- /* int strlen(const char *s) */
- SYM_FUNC_START(strlen)
- ALTERNATIVE("nop", "j strlen_zbb", 0, RISCV_ISA_EXT_ZBB, CONFIG_RISCV_ISA_ZBB)
- /*
- * Returns
- * a0 - string length
- *
- * Parameters
- * a0 - String to measure
- *
- * Clobbers:
- * t0, t1
- */
- mv t1, a0
- 1:
- lbu t0, 0(t1)
- beqz t0, 2f
- addi t1, t1, 1
- j 1b
- 2:
- sub a0, t1, a0
- ret
- /*
- * Variant of strlen using the ZBB extension if available
- */
- #ifdef CONFIG_RISCV_ISA_ZBB
- strlen_zbb:
- #ifdef CONFIG_CPU_BIG_ENDIAN
- # define CZ clz
- # define SHIFT sll
- #else
- # define CZ ctz
- # define SHIFT srl
- #endif
- .option push
- .option arch,+zbb
- /*
- * Returns
- * a0 - string length
- *
- * Parameters
- * a0 - String to measure
- *
- * Clobbers
- * t0, t1, t2, t3
- */
- /* Number of irrelevant bytes in the first word. */
- andi t2, a0, SZREG-1
- /* Align pointer. */
- andi t0, a0, -SZREG
- li t3, SZREG
- sub t3, t3, t2
- slli t2, t2, 3
- /* Get the first word. */
- REG_L t1, 0(t0)
- /*
- * Shift away the partial data we loaded to remove the irrelevant bytes
- * preceding the string with the effect of adding NUL bytes at the
- * end of the string's first word.
- */
- SHIFT t1, t1, t2
- /* Convert non-NUL into 0xff and NUL into 0x00. */
- orc.b t1, t1
- /* Convert non-NUL into 0x00 and NUL into 0xff. */
- not t1, t1
- /*
- * Search for the first set bit (corresponding to a NUL byte in the
- * original chunk).
- */
- CZ t1, t1
- /*
- * The first chunk is special: compare against the number
- * of valid bytes in this chunk.
- */
- srli a0, t1, 3
- bgtu t3, a0, 2f
- /* Prepare for the word comparison loop. */
- addi t2, t0, SZREG
- li t3, -1
- /*
- * Our critical loop is 4 instructions and processes data in
- * 4 byte or 8 byte chunks.
- */
- .p2align 3
- 1:
- REG_L t1, SZREG(t0)
- addi t0, t0, SZREG
- orc.b t1, t1
- beq t1, t3, 1b
- not t1, t1
- CZ t1, t1
- srli t1, t1, 3
- /* Get number of processed bytes. */
- sub t2, t0, t2
- /* Add number of characters in the first word. */
- add a0, a0, t2
- /* Add number of characters in the last word. */
- add a0, a0, t1
- 2:
- ret
- .option pop
- #endif
- SYM_FUNC_END(strlen)
- SYM_FUNC_ALIAS(__pi_strlen, strlen)
- EXPORT_SYMBOL(strlen)
|