xref: /linux/arch/riscv/lib/strnlen.S (revision feff82eb5f4075d541990d0ba60dad14ea83ea9b)
1*5ba15d41SFeng Jiang/* SPDX-License-Identifier: GPL-2.0-only */
2*5ba15d41SFeng Jiang
3*5ba15d41SFeng Jiang/*
4*5ba15d41SFeng Jiang * Base on arch/riscv/lib/strlen.S
5*5ba15d41SFeng Jiang *
6*5ba15d41SFeng Jiang * Copyright (C) Feng Jiang <jiangfeng@kylinos.cn>
7*5ba15d41SFeng Jiang */
8*5ba15d41SFeng Jiang
9*5ba15d41SFeng Jiang#include <linux/linkage.h>
10*5ba15d41SFeng Jiang#include <asm/asm.h>
11*5ba15d41SFeng Jiang#include <asm/alternative-macros.h>
12*5ba15d41SFeng Jiang#include <asm/hwcap.h>
13*5ba15d41SFeng Jiang
14*5ba15d41SFeng Jiang/* size_t strnlen(const char *s, size_t count) */
15*5ba15d41SFeng JiangSYM_FUNC_START(strnlen)
16*5ba15d41SFeng Jiang
17*5ba15d41SFeng Jiang	__ALTERNATIVE_CFG("nop", "j strnlen_zbb", 0, RISCV_ISA_EXT_ZBB,
18*5ba15d41SFeng Jiang		IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZBB))
19*5ba15d41SFeng Jiang
20*5ba15d41SFeng Jiang
21*5ba15d41SFeng Jiang	/*
22*5ba15d41SFeng Jiang	 * Returns
23*5ba15d41SFeng Jiang	 *   a0 - String length
24*5ba15d41SFeng Jiang	 *
25*5ba15d41SFeng Jiang	 * Parameters
26*5ba15d41SFeng Jiang	 *   a0 - String to measure
27*5ba15d41SFeng Jiang	 *   a1 - Max length of string
28*5ba15d41SFeng Jiang	 *
29*5ba15d41SFeng Jiang	 * Clobbers
30*5ba15d41SFeng Jiang	 *   t0, t1, t2
31*5ba15d41SFeng Jiang	 */
32*5ba15d41SFeng Jiang	addi	t1, a0, -1
33*5ba15d41SFeng Jiang	add	t2, a0, a1
34*5ba15d41SFeng Jiang1:
35*5ba15d41SFeng Jiang	addi	t1, t1, 1
36*5ba15d41SFeng Jiang	beq	t1, t2, 2f
37*5ba15d41SFeng Jiang	lbu	t0, 0(t1)
38*5ba15d41SFeng Jiang	bnez	t0, 1b
39*5ba15d41SFeng Jiang2:
40*5ba15d41SFeng Jiang	sub	a0, t1, a0
41*5ba15d41SFeng Jiang	ret
42*5ba15d41SFeng Jiang
43*5ba15d41SFeng Jiang
44*5ba15d41SFeng Jiang/*
45*5ba15d41SFeng Jiang * Variant of strnlen using the ZBB extension if available
46*5ba15d41SFeng Jiang */
47*5ba15d41SFeng Jiang#if defined(CONFIG_RISCV_ISA_ZBB) && defined(CONFIG_TOOLCHAIN_HAS_ZBB)
48*5ba15d41SFeng Jiangstrnlen_zbb:
49*5ba15d41SFeng Jiang
50*5ba15d41SFeng Jiang#ifdef CONFIG_CPU_BIG_ENDIAN
51*5ba15d41SFeng Jiang# define CZ	clz
52*5ba15d41SFeng Jiang# define SHIFT	sll
53*5ba15d41SFeng Jiang#else
54*5ba15d41SFeng Jiang# define CZ	ctz
55*5ba15d41SFeng Jiang# define SHIFT	srl
56*5ba15d41SFeng Jiang#endif
57*5ba15d41SFeng Jiang
58*5ba15d41SFeng Jiang.option push
59*5ba15d41SFeng Jiang.option arch,+zbb
60*5ba15d41SFeng Jiang
61*5ba15d41SFeng Jiang	/*
62*5ba15d41SFeng Jiang	 * Returns
63*5ba15d41SFeng Jiang	 *   a0 - String length
64*5ba15d41SFeng Jiang	 *
65*5ba15d41SFeng Jiang	 * Parameters
66*5ba15d41SFeng Jiang	 *   a0 - String to measure
67*5ba15d41SFeng Jiang	 *   a1 - Max length of string
68*5ba15d41SFeng Jiang	 *
69*5ba15d41SFeng Jiang	 * Clobbers
70*5ba15d41SFeng Jiang	 *   t0, t1, t2, t3, t4
71*5ba15d41SFeng Jiang	 */
72*5ba15d41SFeng Jiang
73*5ba15d41SFeng Jiang	/* If maxlen is 0, return 0. */
74*5ba15d41SFeng Jiang	beqz	a1, 3f
75*5ba15d41SFeng Jiang
76*5ba15d41SFeng Jiang	/* Number of irrelevant bytes in the first word. */
77*5ba15d41SFeng Jiang	andi	t2, a0, SZREG-1
78*5ba15d41SFeng Jiang
79*5ba15d41SFeng Jiang	/* Align pointer. */
80*5ba15d41SFeng Jiang	andi	t0, a0, -SZREG
81*5ba15d41SFeng Jiang
82*5ba15d41SFeng Jiang	li	t3, SZREG
83*5ba15d41SFeng Jiang	sub	t3, t3, t2
84*5ba15d41SFeng Jiang	slli	t2, t2, 3
85*5ba15d41SFeng Jiang
86*5ba15d41SFeng Jiang	/* Aligned boundary. */
87*5ba15d41SFeng Jiang	add	t4, a0, a1
88*5ba15d41SFeng Jiang	andi	t4, t4, -SZREG
89*5ba15d41SFeng Jiang
90*5ba15d41SFeng Jiang	/* Get the first word.  */
91*5ba15d41SFeng Jiang	REG_L	t1, 0(t0)
92*5ba15d41SFeng Jiang
93*5ba15d41SFeng Jiang	/*
94*5ba15d41SFeng Jiang	 * Shift away the partial data we loaded to remove the irrelevant bytes
95*5ba15d41SFeng Jiang	 * preceding the string with the effect of adding NUL bytes at the
96*5ba15d41SFeng Jiang	 * end of the string's first word.
97*5ba15d41SFeng Jiang	 */
98*5ba15d41SFeng Jiang	SHIFT	t1, t1, t2
99*5ba15d41SFeng Jiang
100*5ba15d41SFeng Jiang	/* Convert non-NUL into 0xff and NUL into 0x00. */
101*5ba15d41SFeng Jiang	orc.b	t1, t1
102*5ba15d41SFeng Jiang
103*5ba15d41SFeng Jiang	/* Convert non-NUL into 0x00 and NUL into 0xff. */
104*5ba15d41SFeng Jiang	not	t1, t1
105*5ba15d41SFeng Jiang
106*5ba15d41SFeng Jiang	/*
107*5ba15d41SFeng Jiang	 * Search for the first set bit (corresponding to a NUL byte in the
108*5ba15d41SFeng Jiang	 * original chunk).
109*5ba15d41SFeng Jiang	 */
110*5ba15d41SFeng Jiang	CZ	t1, t1
111*5ba15d41SFeng Jiang
112*5ba15d41SFeng Jiang	/*
113*5ba15d41SFeng Jiang	 * The first chunk is special: compare against the number
114*5ba15d41SFeng Jiang	 * of valid bytes in this chunk.
115*5ba15d41SFeng Jiang	 */
116*5ba15d41SFeng Jiang	srli	a0, t1, 3
117*5ba15d41SFeng Jiang
118*5ba15d41SFeng Jiang	/* Limit the result by maxlen. */
119*5ba15d41SFeng Jiang	minu	a0, a0, a1
120*5ba15d41SFeng Jiang
121*5ba15d41SFeng Jiang	bgtu	t3, a0, 2f
122*5ba15d41SFeng Jiang
123*5ba15d41SFeng Jiang	/* Prepare for the word comparison loop. */
124*5ba15d41SFeng Jiang	addi	t2, t0, SZREG
125*5ba15d41SFeng Jiang	li	t3, -1
126*5ba15d41SFeng Jiang
127*5ba15d41SFeng Jiang	/*
128*5ba15d41SFeng Jiang	 * Our critical loop is 4 instructions and processes data in
129*5ba15d41SFeng Jiang	 * 4 byte or 8 byte chunks.
130*5ba15d41SFeng Jiang	 */
131*5ba15d41SFeng Jiang	.p2align 3
132*5ba15d41SFeng Jiang1:
133*5ba15d41SFeng Jiang	REG_L	t1, SZREG(t0)
134*5ba15d41SFeng Jiang	addi	t0, t0, SZREG
135*5ba15d41SFeng Jiang	orc.b	t1, t1
136*5ba15d41SFeng Jiang	bgeu	t0, t4, 4f
137*5ba15d41SFeng Jiang	beq	t1, t3, 1b
138*5ba15d41SFeng Jiang4:
139*5ba15d41SFeng Jiang	not	t1, t1
140*5ba15d41SFeng Jiang	CZ	t1, t1
141*5ba15d41SFeng Jiang	srli	t1, t1, 3
142*5ba15d41SFeng Jiang
143*5ba15d41SFeng Jiang	/* Get number of processed bytes. */
144*5ba15d41SFeng Jiang	sub	t2, t0, t2
145*5ba15d41SFeng Jiang
146*5ba15d41SFeng Jiang	/* Add number of characters in the first word.  */
147*5ba15d41SFeng Jiang	add	a0, a0, t2
148*5ba15d41SFeng Jiang
149*5ba15d41SFeng Jiang	/* Add number of characters in the last word.  */
150*5ba15d41SFeng Jiang	add	a0, a0, t1
151*5ba15d41SFeng Jiang
152*5ba15d41SFeng Jiang	/* Ensure the final result does not exceed maxlen. */
153*5ba15d41SFeng Jiang	minu	a0, a0, a1
154*5ba15d41SFeng Jiang2:
155*5ba15d41SFeng Jiang	ret
156*5ba15d41SFeng Jiang3:
157*5ba15d41SFeng Jiang	mv	a0, a1
158*5ba15d41SFeng Jiang	ret
159*5ba15d41SFeng Jiang
160*5ba15d41SFeng Jiang.option pop
161*5ba15d41SFeng Jiang#endif
162*5ba15d41SFeng JiangSYM_FUNC_END(strnlen)
163*5ba15d41SFeng JiangSYM_FUNC_ALIAS(__pi_strnlen, strnlen)
164*5ba15d41SFeng JiangEXPORT_SYMBOL(strnlen)
165