xref: /openbmc/linux/arch/riscv/lib/strlen.S (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
156e0790cSHeiko Stuebner/* SPDX-License-Identifier: GPL-2.0-only */
256e0790cSHeiko Stuebner
356e0790cSHeiko Stuebner#include <linux/linkage.h>
456e0790cSHeiko Stuebner#include <asm/asm.h>
5b6fcdb19SHeiko Stuebner#include <asm/alternative-macros.h>
628ea374dSAndrew Jones#include <asm/hwcap.h>
756e0790cSHeiko Stuebner
856e0790cSHeiko Stuebner/* int strlen(const char *s) */
956e0790cSHeiko StuebnerSYM_FUNC_START(strlen)
10b6fcdb19SHeiko Stuebner
11d5a7fab7SSamuel Holland	ALTERNATIVE("nop", "j strlen_zbb", 0, RISCV_ISA_EXT_ZBB, CONFIG_RISCV_ISA_ZBB)
12b6fcdb19SHeiko Stuebner
1356e0790cSHeiko Stuebner	/*
1456e0790cSHeiko Stuebner	 * Returns
1556e0790cSHeiko Stuebner	 *   a0 - string length
1656e0790cSHeiko Stuebner	 *
1756e0790cSHeiko Stuebner	 * Parameters
1856e0790cSHeiko Stuebner	 *   a0 - String to measure
1956e0790cSHeiko Stuebner	 *
2056e0790cSHeiko Stuebner	 * Clobbers:
2156e0790cSHeiko Stuebner	 *   t0, t1
2256e0790cSHeiko Stuebner	 */
2356e0790cSHeiko Stuebner	mv	t1, a0
2456e0790cSHeiko Stuebner1:
2556e0790cSHeiko Stuebner	lbu	t0, 0(t1)
2656e0790cSHeiko Stuebner	beqz	t0, 2f
2756e0790cSHeiko Stuebner	addi	t1, t1, 1
2856e0790cSHeiko Stuebner	j	1b
2956e0790cSHeiko Stuebner2:
3056e0790cSHeiko Stuebner	sub	a0, t1, a0
3156e0790cSHeiko Stuebner	ret
32b6fcdb19SHeiko Stuebner
33b6fcdb19SHeiko Stuebner/*
34b6fcdb19SHeiko Stuebner * Variant of strlen using the ZBB extension if available
35b6fcdb19SHeiko Stuebner */
36b6fcdb19SHeiko Stuebner#ifdef CONFIG_RISCV_ISA_ZBB
37b6fcdb19SHeiko Stuebnerstrlen_zbb:
38b6fcdb19SHeiko Stuebner
39b6fcdb19SHeiko Stuebner#ifdef CONFIG_CPU_BIG_ENDIAN
40b6fcdb19SHeiko Stuebner# define CZ	clz
41b6fcdb19SHeiko Stuebner# define SHIFT	sll
42b6fcdb19SHeiko Stuebner#else
43b6fcdb19SHeiko Stuebner# define CZ	ctz
44b6fcdb19SHeiko Stuebner# define SHIFT	srl
45b6fcdb19SHeiko Stuebner#endif
46b6fcdb19SHeiko Stuebner
47b6fcdb19SHeiko Stuebner.option push
48b6fcdb19SHeiko Stuebner.option arch,+zbb
49b6fcdb19SHeiko Stuebner
50b6fcdb19SHeiko Stuebner	/*
51b6fcdb19SHeiko Stuebner	 * Returns
52b6fcdb19SHeiko Stuebner	 *   a0 - string length
53b6fcdb19SHeiko Stuebner	 *
54b6fcdb19SHeiko Stuebner	 * Parameters
55b6fcdb19SHeiko Stuebner	 *   a0 - String to measure
56b6fcdb19SHeiko Stuebner	 *
57b6fcdb19SHeiko Stuebner	 * Clobbers
58b6fcdb19SHeiko Stuebner	 *   t0, t1, t2, t3
59b6fcdb19SHeiko Stuebner	 */
60b6fcdb19SHeiko Stuebner
61b6fcdb19SHeiko Stuebner	/* Number of irrelevant bytes in the first word. */
62b6fcdb19SHeiko Stuebner	andi	t2, a0, SZREG-1
63b6fcdb19SHeiko Stuebner
64b6fcdb19SHeiko Stuebner	/* Align pointer. */
65b6fcdb19SHeiko Stuebner	andi	t0, a0, -SZREG
66b6fcdb19SHeiko Stuebner
67b6fcdb19SHeiko Stuebner	li	t3, SZREG
68b6fcdb19SHeiko Stuebner	sub	t3, t3, t2
69b6fcdb19SHeiko Stuebner	slli	t2, t2, 3
70b6fcdb19SHeiko Stuebner
71b6fcdb19SHeiko Stuebner	/* Get the first word.  */
72b6fcdb19SHeiko Stuebner	REG_L	t1, 0(t0)
73b6fcdb19SHeiko Stuebner
74b6fcdb19SHeiko Stuebner	/*
75b6fcdb19SHeiko Stuebner	 * Shift away the partial data we loaded to remove the irrelevant bytes
76b6fcdb19SHeiko Stuebner	 * preceding the string with the effect of adding NUL bytes at the
77b6fcdb19SHeiko Stuebner	 * end of the string's first word.
78b6fcdb19SHeiko Stuebner	 */
79b6fcdb19SHeiko Stuebner	SHIFT	t1, t1, t2
80b6fcdb19SHeiko Stuebner
81b6fcdb19SHeiko Stuebner	/* Convert non-NUL into 0xff and NUL into 0x00. */
82b6fcdb19SHeiko Stuebner	orc.b	t1, t1
83b6fcdb19SHeiko Stuebner
84b6fcdb19SHeiko Stuebner	/* Convert non-NUL into 0x00 and NUL into 0xff. */
85b6fcdb19SHeiko Stuebner	not	t1, t1
86b6fcdb19SHeiko Stuebner
87b6fcdb19SHeiko Stuebner	/*
88b6fcdb19SHeiko Stuebner	 * Search for the first set bit (corresponding to a NUL byte in the
89b6fcdb19SHeiko Stuebner	 * original chunk).
90b6fcdb19SHeiko Stuebner	 */
91b6fcdb19SHeiko Stuebner	CZ	t1, t1
92b6fcdb19SHeiko Stuebner
93b6fcdb19SHeiko Stuebner	/*
94b6fcdb19SHeiko Stuebner	 * The first chunk is special: compare against the number
95b6fcdb19SHeiko Stuebner	 * of valid bytes in this chunk.
96b6fcdb19SHeiko Stuebner	 */
97b6fcdb19SHeiko Stuebner	srli	a0, t1, 3
986934cf8aSHeiko Stuebner	bgtu	t3, a0, 2f
99b6fcdb19SHeiko Stuebner
100b6fcdb19SHeiko Stuebner	/* Prepare for the word comparison loop. */
101b6fcdb19SHeiko Stuebner	addi	t2, t0, SZREG
102b6fcdb19SHeiko Stuebner	li	t3, -1
103b6fcdb19SHeiko Stuebner
104b6fcdb19SHeiko Stuebner	/*
105b6fcdb19SHeiko Stuebner	 * Our critical loop is 4 instructions and processes data in
106b6fcdb19SHeiko Stuebner	 * 4 byte or 8 byte chunks.
107b6fcdb19SHeiko Stuebner	 */
108b6fcdb19SHeiko Stuebner	.p2align 3
109b6fcdb19SHeiko Stuebner1:
110b6fcdb19SHeiko Stuebner	REG_L	t1, SZREG(t0)
111b6fcdb19SHeiko Stuebner	addi	t0, t0, SZREG
112b6fcdb19SHeiko Stuebner	orc.b	t1, t1
113b6fcdb19SHeiko Stuebner	beq	t1, t3, 1b
1146934cf8aSHeiko Stuebner
115b6fcdb19SHeiko Stuebner	not	t1, t1
116b6fcdb19SHeiko Stuebner	CZ	t1, t1
1176934cf8aSHeiko Stuebner	srli	t1, t1, 3
118b6fcdb19SHeiko Stuebner
1196934cf8aSHeiko Stuebner	/* Get number of processed bytes. */
120b6fcdb19SHeiko Stuebner	sub	t2, t0, t2
121b6fcdb19SHeiko Stuebner
122b6fcdb19SHeiko Stuebner	/* Add number of characters in the first word.  */
123b6fcdb19SHeiko Stuebner	add	a0, a0, t2
124b6fcdb19SHeiko Stuebner
125b6fcdb19SHeiko Stuebner	/* Add number of characters in the last word.  */
126b6fcdb19SHeiko Stuebner	add	a0, a0, t1
1276934cf8aSHeiko Stuebner2:
128b6fcdb19SHeiko Stuebner	ret
129b6fcdb19SHeiko Stuebner
130b6fcdb19SHeiko Stuebner.option pop
131b6fcdb19SHeiko Stuebner#endif
13256e0790cSHeiko StuebnerSYM_FUNC_END(strlen)
133*26e7aacbSAlexandre GhitiSYM_FUNC_ALIAS(__pi_strlen, strlen)
134