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