1/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <linux/linkage.h>
4#include <asm/asm.h>
5#include <asm/alternative-macros.h>
6#include <asm/hwcap.h>
7
8/* int strlen(const char *s) */
9SYM_FUNC_START(strlen)
10
11 ALTERNATIVE("nop", "j strlen_zbb", 0, RISCV_ISA_EXT_ZBB, CONFIG_RISCV_ISA_ZBB)
12
13 /*
14 * Returns
15 * a0 - string length
16 *
17 * Parameters
18 * a0 - String to measure
19 *
20 * Clobbers:
21 * t0, t1
22 */
23 mv t1, a0
241:
25 lbu t0, 0(t1)
26 beqz t0, 2f
27 addi t1, t1, 1
28 j 1b
292:
30 sub a0, t1, a0
31 ret
32
33/*
34 * Variant of strlen using the ZBB extension if available
35 */
36#ifdef CONFIG_RISCV_ISA_ZBB
37strlen_zbb:
38
39#ifdef CONFIG_CPU_BIG_ENDIAN
40# define CZ clz
41# define SHIFT sll
42#else
43# define CZ ctz
44# define SHIFT srl
45#endif
46
47.option push
48.option arch,+zbb
49
50 /*
51 * Returns
52 * a0 - string length
53 *
54 * Parameters
55 * a0 - String to measure
56 *
57 * Clobbers
58 * t0, t1, t2, t3
59 */
60
61 /* Number of irrelevant bytes in the first word. */
62 andi t2, a0, SZREG-1
63
64 /* Align pointer. */
65 andi t0, a0, -SZREG
66
67 li t3, SZREG
68 sub t3, t3, t2
69 slli t2, t2, 3
70
71 /* Get the first word. */
72 REG_L t1, 0(t0)
73
74 /*
75 * Shift away the partial data we loaded to remove the irrelevant bytes
76 * preceding the string with the effect of adding NUL bytes at the
77 * end of the string's first word.
78 */
79 SHIFT t1, t1, t2
80
81 /* Convert non-NUL into 0xff and NUL into 0x00. */
82 orc.b t1, t1
83
84 /* Convert non-NUL into 0x00 and NUL into 0xff. */
85 not t1, t1
86
87 /*
88 * Search for the first set bit (corresponding to a NUL byte in the
89 * original chunk).
90 */
91 CZ t1, t1
92
93 /*
94 * The first chunk is special: compare against the number
95 * of valid bytes in this chunk.
96 */
97 srli a0, t1, 3
98 bgtu t3, a0, 2f
99
100 /* Prepare for the word comparison loop. */
101 addi t2, t0, SZREG
102 li t3, -1
103
104 /*
105 * Our critical loop is 4 instructions and processes data in
106 * 4 byte or 8 byte chunks.
107 */
108 .p2align 3
1091:
110 REG_L t1, SZREG(t0)
111 addi t0, t0, SZREG
112 orc.b t1, t1
113 beq t1, t3, 1b
114
115 not t1, t1
116 CZ t1, t1
117 srli t1, t1, 3
118
119 /* Get number of processed bytes. */
120 sub t2, t0, t2
121
122 /* Add number of characters in the first word. */
123 add a0, a0, t2
124
125 /* Add number of characters in the last word. */
126 add a0, a0, t1
1272:
128 ret
129
130.option pop
131#endif
132SYM_FUNC_END(strlen)
133SYM_FUNC_ALIAS(__pi_strlen, strlen)
134

source code of linux/arch/riscv/lib/strlen.S