]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/powerpc/powerpc32/power7/strchr.S
support: Fix typo in xgetsockname error message
[thirdparty/glibc.git] / sysdeps / powerpc / powerpc32 / power7 / strchr.S
CommitLineData
fe2f79db 1/* Optimized strchr implementation for PowerPC32/POWER7 using cmpb insn.
dff8da6b 2 Copyright (C) 2010-2024 Free Software Foundation, Inc.
fe2f79db
LM
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
fe2f79db
LM
18
19#include <sysdep.h>
fe2f79db
LM
20
21/* int [r3] strchr (char *s [r3], int c [r4]) */
22 .machine power7
b5510883 23ENTRY (strchr)
fe2f79db
LM
24 CALL_MCOUNT
25 dcbt 0,r3
26 clrrwi r8,r3,2 /* Align the address to word boundary. */
27 cmpwi cr7,r4,0
28 lwz r12,0(r8) /* Load word from memory. */
29 li r0,0 /* Word with null chars to use
30 with cmpb. */
31
32 rlwinm r6,r3,3,27,28 /* Calculate padding. */
33
34 beq cr7,L(null_match)
35
36 /* Replicate byte to word. */
d298c416
AZ
37 insrwi r4,r4,8,16
38 insrwi r4,r4,16,0
fe2f79db
LM
39
40 /* Now r4 has a word of c bytes and r0 has
41 a word of null bytes. */
42
43 cmpb r10,r12,r4 /* Compare each byte against c byte. */
44 cmpb r11,r12,r0 /* Compare each byte against null byte. */
45
46 /* Move the words left and right to discard the bits that are
47 not part of the string and to bring them back as zeros. */
664318c3
AM
48#ifdef __LITTLE_ENDIAN__
49 srw r10,r10,r6
50 srw r11,r11,r6
51 slw r10,r10,r6
52 slw r11,r11,r6
53#else
fe2f79db
LM
54 slw r10,r10,r6
55 slw r11,r11,r6
56 srw r10,r10,r6
57 srw r11,r11,r6
664318c3 58#endif
fe2f79db
LM
59 or r5,r10,r11 /* OR the results to speed things up. */
60 cmpwi cr7,r5,0 /* If r5 == 0, no c or null bytes
61 have been found. */
62 bne cr7,L(done)
63
64 mtcrf 0x01,r8
65
66 /* Are we now aligned to a doubleword boundary? If so, skip to
67 the main loop. Otherwise, go through the alignment code. */
68
69 bt 29,L(loop)
70
71 /* Handle WORD2 of pair. */
72 lwzu r12,4(r8)
664318c3 73 cmpb r10,r12,r4
fe2f79db
LM
74 cmpb r11,r12,r0
75 or r5,r10,r11
76 cmpwi cr7,r5,0
77 bne cr7,L(done)
78 b L(loop) /* We branch here (rather than falling through)
79 to skip the nops due to heavy alignment
80 of the loop below. */
81
82 .p2align 5
83L(loop):
84 /* Load two words, compare and merge in a
85 single register for speed. This is an attempt
86 to speed up the null-checking process for bigger strings. */
87 lwz r12,4(r8)
88 lwzu r9,8(r8)
89 cmpb r10,r12,r4
90 cmpb r11,r12,r0
91 cmpb r6,r9,r4
92 cmpb r7,r9,r0
93 or r12,r10,r11
94 or r9,r6,r7
95 or r5,r12,r9
96 cmpwi cr7,r5,0
97 beq cr7,L(loop)
98
99 /* OK, one (or both) of the words contains a c/null byte. Check
100 the first word and decrement the address in case the first
101 word really contains a c/null byte. */
102
103 cmpwi cr6,r12,0
104 addi r8,r8,-4
105 bne cr6,L(done)
106
107 /* The c/null byte must be in the second word. Adjust the address
664318c3
AM
108 again and move the result of cmpb to r10/r11 so we can calculate
109 the pointer. */
fe2f79db
LM
110
111 mr r10,r6
112 mr r11,r7
113 addi r8,r8,4
114
664318c3 115 /* r10/r11 have the output of the cmpb instructions, that is,
fe2f79db
LM
116 0xff in the same position as the c/null byte in the original
117 word from the string. Use that to calculate the pointer. */
118L(done):
664318c3
AM
119#ifdef __LITTLE_ENDIAN__
120 addi r3,r10,-1
121 andc r3,r3,r10
122 popcntw r0,r3
123 addi r4,r11,-1
124 andc r4,r4,r11
125 cmplw cr7,r3,r4
126 bgt cr7,L(no_match)
127#else
128 cntlzw r0,r10 /* Count leading zeros before c matches. */
129 cmplw cr7,r11,r10
fe2f79db 130 bgt cr7,L(no_match)
664318c3
AM
131#endif
132 srwi r0,r0,3 /* Convert leading zeros to bytes. */
fe2f79db
LM
133 add r3,r8,r0 /* Return address of the matching c byte
134 or null in case c was not found. */
135 blr
136
137 .align 4
138L(no_match):
139 li r3,0
140 blr
141
142/* We are here because strchr was called with a null byte. */
143 .align 4
144L(null_match):
145 /* r0 has a word of null bytes. */
146
147 cmpb r5,r12,r0 /* Compare each byte against null bytes. */
148
149 /* Move the words left and right to discard the bits that are
664318c3
AM
150 not part of the string and bring them back as zeros. */
151#ifdef __LITTLE_ENDIAN__
152 srw r5,r5,r6
153 slw r5,r5,r6
154#else
fe2f79db
LM
155 slw r5,r5,r6
156 srw r5,r5,r6
664318c3 157#endif
fe2f79db
LM
158 cmpwi cr7,r5,0 /* If r10 == 0, no c or null bytes
159 have been found. */
160 bne cr7,L(done_null)
161
162 mtcrf 0x01,r8
163
164 /* Are we now aligned to a doubleword boundary? If so, skip to
165 the main loop. Otherwise, go through the alignment code. */
166
167 bt 29,L(loop_null)
168
169 /* Handle WORD2 of pair. */
170 lwzu r12,4(r8)
171 cmpb r5,r12,r0
172 cmpwi cr7,r5,0
173 bne cr7,L(done_null)
174 b L(loop_null) /* We branch here (rather than falling through)
175 to skip the nops due to heavy alignment
176 of the loop below. */
177
178 /* Main loop to look for the end of the string. Since it's a
179 small loop (< 8 instructions), align it to 32-bytes. */
180 .p2align 5
181L(loop_null):
182 /* Load two words, compare and merge in a
183 single register for speed. This is an attempt
184 to speed up the null-checking process for bigger strings. */
185 lwz r12,4(r8)
186 lwzu r11,8(r8)
187 cmpb r5,r12,r0
188 cmpb r10,r11,r0
189 or r6,r5,r10
190 cmpwi cr7,r6,0
191 beq cr7,L(loop_null)
192
193 /* OK, one (or both) of the words contains a null byte. Check
194 the first word and decrement the address in case the first
195 word really contains a null byte. */
196
197 cmpwi cr6,r5,0
198 addi r8,r8,-4
199 bne cr6,L(done_null)
200
201 /* The null byte must be in the second word. Adjust the address
202 again and move the result of cmpb to r10 so we can calculate the
203 pointer. */
204
205 mr r5,r10
206 addi r8,r8,4
207
208 /* r5 has the output of the cmpb instruction, that is, it contains
209 0xff in the same position as the null byte in the original
210 word from the string. Use that to calculate the pointer. */
211L(done_null):
664318c3
AM
212#ifdef __LITTLE_ENDIAN__
213 addi r0,r5,-1
214 andc r0,r0,r5
215 popcntw r0,r0
216#else
fe2f79db 217 cntlzw r0,r5 /* Count leading zeros before the match. */
664318c3 218#endif
fe2f79db
LM
219 srwi r0,r0,3 /* Convert leading zeros to bytes. */
220 add r3,r8,r0 /* Return address of the matching null byte. */
221 blr
b5510883
JM
222END (strchr)
223weak_alias (strchr, index)
fe2f79db 224libc_hidden_builtin_def (strchr)