| /* 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) |