manual: clarify defintions of floating point exponent bounds (bug 31518)
[glibc.git] / sysdeps / powerpc / powerpc32 / power7 / strchr.S
blob345d86d4e38c8d34740ffc80581818d1ae1aa304
1 /* Optimized strchr implementation for PowerPC32/POWER7 using cmpb insn.
2    Copyright (C) 2010-2024 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
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.
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.
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
19 #include <sysdep.h>
21 /* int [r3] strchr (char *s [r3], int c [r4])  */
22         .machine  power7
23 ENTRY (strchr)
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.  */
32         rlwinm  r6,r3,3,27,28 /* Calculate padding.  */
34         beq     cr7,L(null_match)
36         /* Replicate byte to word.  */
37         insrwi  r4,r4,8,16
38         insrwi  r4,r4,16,0
40         /* Now r4 has a word of c bytes and r0 has
41            a word of null bytes.  */
43         cmpb    r10,r12,r4     /* Compare each byte against c byte.  */
44         cmpb    r11,r12,r0     /* Compare each byte against null byte.  */
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.  */
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
54         slw     r10,r10,r6
55         slw     r11,r11,r6
56         srw     r10,r10,r6
57         srw     r11,r11,r6
58 #endif
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)
64         mtcrf   0x01,r8
66         /* Are we now aligned to a doubleword boundary?  If so, skip to
67            the main loop.  Otherwise, go through the alignment code.  */
69         bt      29,L(loop)
71         /* Handle WORD2 of pair.  */
72         lwzu    r12,4(r8)
73         cmpb    r10,r12,r4
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.  */
82         .p2align  5
83 L(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)
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.  */
103         cmpwi   cr6,r12,0
104         addi    r8,r8,-4
105         bne     cr6,L(done)
107         /* The c/null byte must be in the second word.  Adjust the address
108            again and move the result of cmpb to r10/r11 so we can calculate
109            the pointer.  */
111         mr      r10,r6
112         mr      r11,r7
113         addi    r8,r8,4
115         /* r10/r11 have the output of the cmpb instructions, that is,
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.  */
118 L(done):
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
130         bgt     cr7,L(no_match)
131 #endif
132         srwi    r0,r0,3       /* Convert leading zeros to bytes.  */
133         add     r3,r8,r0      /* Return address of the matching c byte
134                                  or null in case c was not found.  */
135         blr
137         .align  4
138 L(no_match):
139         li      r3,0
140         blr
142 /* We are here because strchr was called with a null byte.  */
143         .align  4
144 L(null_match):
145         /* r0 has a word of null bytes.  */
147         cmpb    r5,r12,r0     /* Compare each byte against null bytes.  */
149         /* Move the words left and right to discard the bits that are
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
155         slw     r5,r5,r6
156         srw     r5,r5,r6
157 #endif
158         cmpwi   cr7,r5,0      /* If r10 == 0, no c or null bytes
159                                  have been found.  */
160         bne     cr7,L(done_null)
162         mtcrf   0x01,r8
164         /* Are we now aligned to a doubleword boundary?  If so, skip to
165            the main loop.  Otherwise, go through the alignment code.  */
167         bt      29,L(loop_null)
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.  */
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
181 L(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)
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.  */
197         cmpwi   cr6,r5,0
198         addi    r8,r8,-4
199         bne     cr6,L(done_null)
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.  */
205         mr      r5,r10
206         addi    r8,r8,4
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.  */
211 L(done_null):
212 #ifdef __LITTLE_ENDIAN__
213         addi    r0,r5,-1
214         andc    r0,r0,r5
215         popcntw r0,r0
216 #else
217         cntlzw  r0,r5         /* Count leading zeros before the match.  */
218 #endif
219         srwi    r0,r0,3       /* Convert leading zeros to bytes.  */
220         add     r3,r8,r0      /* Return address of the matching null byte.  */
221         blr
222 END (strchr)
223 weak_alias (strchr, index)
224 libc_hidden_builtin_def (strchr)