xref: /linux/arch/riscv/lib/strlen.S (revision ca220141fa8ebae09765a242076b2b77338106b0)
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_CFG("nop", "j strlen_zbb", 0, RISCV_ISA_EXT_ZBB,
12		IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_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	addi	t1, a0, -1
251:
26	addi	t1, t1, 1
27	lbu	t0, 0(t1)
28	bnez	t0, 1b
29	sub	a0, t1, a0
30	ret
31
32/*
33 * Variant of strlen using the ZBB extension if available
34 */
35#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB)
36strlen_zbb:
37
38#ifdef CONFIG_CPU_BIG_ENDIAN
39# define CZ	clz
40# define SHIFT	sll
41#else
42# define CZ	ctz
43# define SHIFT	srl
44#endif
45
46.option push
47.option arch,+zbb
48
49	/*
50	 * Returns
51	 *   a0 - string length
52	 *
53	 * Parameters
54	 *   a0 - String to measure
55	 *
56	 * Clobbers
57	 *   t0, t1, t2, t3
58	 */
59
60	/* Number of irrelevant bytes in the first word. */
61	andi	t2, a0, SZREG-1
62
63	/* Align pointer. */
64	andi	t0, a0, -SZREG
65
66	li	t3, SZREG
67	sub	t3, t3, t2
68	slli	t2, t2, 3
69
70	/* Get the first word.  */
71	REG_L	t1, 0(t0)
72
73	/*
74	 * Shift away the partial data we loaded to remove the irrelevant bytes
75	 * preceding the string with the effect of adding NUL bytes at the
76	 * end of the string's first word.
77	 */
78	SHIFT	t1, t1, t2
79
80	/* Convert non-NUL into 0xff and NUL into 0x00. */
81	orc.b	t1, t1
82
83	/* Convert non-NUL into 0x00 and NUL into 0xff. */
84	not	t1, t1
85
86	/*
87	 * Search for the first set bit (corresponding to a NUL byte in the
88	 * original chunk).
89	 */
90	CZ	t1, t1
91
92	/*
93	 * The first chunk is special: compare against the number
94	 * of valid bytes in this chunk.
95	 */
96	srli	a0, t1, 3
97	bgtu	t3, a0, 2f
98
99	/* Prepare for the word comparison loop. */
100	addi	t2, t0, SZREG
101	li	t3, -1
102
103	/*
104	 * Our critical loop is 4 instructions and processes data in
105	 * 4 byte or 8 byte chunks.
106	 */
107	.p2align 3
1081:
109	REG_L	t1, SZREG(t0)
110	addi	t0, t0, SZREG
111	orc.b	t1, t1
112	beq	t1, t3, 1b
113
114	not	t1, t1
115	CZ	t1, t1
116	srli	t1, t1, 3
117
118	/* Get number of processed bytes. */
119	sub	t2, t0, t2
120
121	/* Add number of characters in the first word.  */
122	add	a0, a0, t2
123
124	/* Add number of characters in the last word.  */
125	add	a0, a0, t1
1262:
127	ret
128
129.option pop
130#endif
131SYM_FUNC_END(strlen)
132SYM_FUNC_ALIAS(__pi_strlen, strlen)
133EXPORT_SYMBOL(strlen)
134