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