OSDN Git Service

90c418d12077629ce7ec074ce0d13a2dcd084cc4
[uclinux-h8/uClibc.git] / libc / string / xtensa / strcmp.S
1 /* Optimized strcmp for Xtensa.
2    Copyright (C) 2001, 2007 Free Software Foundation, Inc.
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
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
18    Boston, MA 02110-1301, USA.  */
19
20 #include "../../sysdeps/linux/xtensa/sysdep.h"
21 #include <bits/xtensa-config.h>
22
23 #ifdef __XTENSA_EB__
24 #define MASK0 0xff000000
25 #define MASK1 0x00ff0000
26 #define MASK2 0x0000ff00
27 #define MASK3 0x000000ff
28 #else
29 #define MASK0 0x000000ff
30 #define MASK1 0x0000ff00
31 #define MASK2 0x00ff0000
32 #define MASK3 0xff000000
33 #endif
34
35 #define MASK4 0x40404040
36
37         .literal .Lmask0, MASK0
38         .literal .Lmask1, MASK1
39         .literal .Lmask2, MASK2
40         .literal .Lmask3, MASK3
41         .literal .Lmask4, MASK4
42
43         .text
44 ENTRY (strcmp)
45         /* a2 = s1, a3 = s2 */
46
47         l8ui    a8, a2, 0       // byte 0 from s1
48         l8ui    a9, a3, 0       // byte 0 from s2
49         movi    a10, 3          // mask
50         bne     a8, a9, .Lretdiff
51
52         or      a11, a2, a3
53         bnone   a11, a10, .Laligned
54
55         xor     a11, a2, a3     // compare low two bits of s1 and s2
56         bany    a11, a10, .Lunaligned   // if they have different alignment
57
58         /* s1/s2 are not word-aligned.  */
59         addi    a2, a2, 1       // advance s1
60         beqz    a8, .Leq        // bytes equal, if zero, strings are equal
61         addi    a3, a3, 1       // advance s2
62         bnone   a2, a10, .Laligned // if s1/s2 now aligned
63         l8ui    a8, a2, 0       // byte 1 from s1
64         l8ui    a9, a3, 0       // byte 1 from s2
65         addi    a2, a2, 1       // advance s1
66         bne     a8, a9, .Lretdiff // if different, return difference
67         beqz    a8, .Leq        // bytes equal, if zero, strings are equal
68         addi    a3, a3, 1       // advance s2
69         bnone   a2, a10, .Laligned // if s1/s2 now aligned
70         l8ui    a8, a2, 0       // byte 2 from s1
71         l8ui    a9, a3, 0       // byte 2 from s2
72         addi    a2, a2, 1       // advance s1
73         bne     a8, a9, .Lretdiff // if different, return difference
74         beqz    a8, .Leq        // bytes equal, if zero, strings are equal
75         addi    a3, a3, 1       // advance s2
76         j       .Laligned
77
78 /* s1 and s2 have different alignment.
79
80    If the zero-overhead loop option is available, use an (almost)
81    infinite zero-overhead loop with conditional exits so we only pay
82    for taken branches when exiting the loop.
83
84    Note: It is important for this unaligned case to come before the
85    code for aligned strings, because otherwise some of the branches
86    above cannot reach and have to be transformed to branches around
87    jumps.  The unaligned code is smaller and the branches can reach
88    over it.  */
89
90         .align  4
91         /* (2 mod 4) alignment for loop instruction */
92 .Lunaligned:
93 #if XCHAL_HAVE_LOOPS
94         _movi.n a8, 0           // set up for the maximum loop count
95         loop    a8, .Lretdiff   // loop forever (almost anyway)
96 #endif
97 .Lnextbyte:
98         l8ui    a8, a2, 0
99         l8ui    a9, a3, 0
100         addi    a2, a2, 1
101         bne     a8, a9, .Lretdiff
102         addi    a3, a3, 1
103 #if XCHAL_HAVE_LOOPS
104         beqz    a8, .Lretdiff
105 #else
106         bnez    a8, .Lnextbyte
107 #endif
108 .Lretdiff:
109         sub     a2, a8, a9
110         retw
111
112 /* s1 is word-aligned; s2 is word-aligned.
113
114    If the zero-overhead loop option is available, use an (almost)
115    infinite zero-overhead loop with conditional exits so we only pay
116    for taken branches when exiting the loop.  */
117
118 /* New algorithm, relying on the fact that all normal ASCII is between
119    32 and 127.
120
121    Rather than check all bytes for zero:
122    Take one word (4 bytes).  Call it w1.
123    Shift w1 left by one into w1'.
124    Or w1 and w1'.  For all normal ASCII bit 6 will be 1; for zero it won't.
125    Check that all 4 bit 6's (one for each byte) are one:
126    If they are, we are definitely not done.
127    If they are not, we are probably done, but need to check for zero.  */
128
129         .align  4
130 #if XCHAL_HAVE_LOOPS
131 .Laligned:
132         .begin  no-transform
133         l32r    a4, .Lmask0     // mask for byte 0
134         l32r    a7, .Lmask4
135         /* Loop forever.  (a4 is more than than the maximum number
136            of iterations) */
137         loop    a4, .Laligned_done
138
139         /* First unrolled loop body.  */
140         l32i    a8, a2, 0       // get word from s1
141         l32i    a9, a3, 0       // get word from s2
142         slli    a5, a8, 1
143         bne     a8, a9, .Lwne2
144         or      a9, a8, a5
145         bnall   a9, a7, .Lprobeq
146
147         /* Second unrolled loop body.  */
148         l32i    a8, a2, 4       // get word from s1+4
149         l32i    a9, a3, 4       // get word from s2+4
150         slli    a5, a8, 1
151         bne     a8, a9, .Lwne2
152         or      a9, a8, a5
153         bnall   a9, a7, .Lprobeq2
154
155         addi    a2, a2, 8       // advance s1 pointer
156         addi    a3, a3, 8       // advance s2 pointer
157 .Laligned_done:
158         or      a1, a1, a1      // nop
159
160 .Lprobeq2:
161         /* Adjust pointers to account for the loop unrolling.  */
162         addi    a2, a2, 4
163         addi    a3, a3, 4
164
165 #else /* !XCHAL_HAVE_LOOPS */
166
167 .Laligned:
168         movi    a4, MASK0       // mask for byte 0
169         movi    a7, MASK4
170         j       .Lfirstword
171 .Lnextword:
172         addi    a2, a2, 4       // advance s1 pointer
173         addi    a3, a3, 4       // advance s2 pointer
174 .Lfirstword:
175         l32i    a8, a2, 0       // get word from s1
176         l32i    a9, a3, 0       // get word from s2
177         slli    a5, a8, 1
178         bne     a8, a9, .Lwne2
179         or      a9, a8, a5
180         ball    a9, a7, .Lnextword
181 #endif /* !XCHAL_HAVE_LOOPS */
182
183         /* align (0 mod 4) */
184 .Lprobeq:
185         /* Words are probably equal, but check for sure.
186            If not, loop over the rest of string using normal algorithm.  */
187
188         bnone   a8, a4, .Leq    // if byte 0 is zero
189         l32r    a5, .Lmask1     // mask for byte 1
190         l32r    a6, .Lmask2     // mask for byte 2
191         bnone   a8, a5, .Leq    // if byte 1 is zero
192         l32r    a7, .Lmask3     // mask for byte 3
193         bnone   a8, a6, .Leq    // if byte 2 is zero
194         bnone   a8, a7, .Leq    // if byte 3 is zero
195         addi.n  a2, a2, 4       // advance s1 pointer
196         addi.n  a3, a3, 4       // advance s2 pointer
197 #if XCHAL_HAVE_LOOPS
198
199         /* align (1 mod 4) */
200         loop    a4, .Leq        // loop forever (a4 is bigger than max iters)
201         .end    no-transform
202
203         l32i    a8, a2, 0       // get word from s1
204         l32i    a9, a3, 0       // get word from s2
205         addi    a2, a2, 4       // advance s1 pointer
206         bne     a8, a9, .Lwne
207         bnone   a8, a4, .Leq    // if byte 0 is zero
208         bnone   a8, a5, .Leq    // if byte 1 is zero
209         bnone   a8, a6, .Leq    // if byte 2 is zero
210         bnone   a8, a7, .Leq    // if byte 3 is zero
211         addi    a3, a3, 4       // advance s2 pointer
212
213 #else /* !XCHAL_HAVE_LOOPS */
214
215         j       .Lfirstword2
216 .Lnextword2:
217         addi    a3, a3, 4       // advance s2 pointer
218 .Lfirstword2:
219         l32i    a8, a2, 0       // get word from s1
220         l32i    a9, a3, 0       // get word from s2
221         addi    a2, a2, 4       // advance s1 pointer
222         bne     a8, a9, .Lwne
223         bnone   a8, a4, .Leq    // if byte 0 is zero
224         bnone   a8, a5, .Leq    // if byte 1 is zero
225         bnone   a8, a6, .Leq    // if byte 2 is zero
226         bany    a8, a7, .Lnextword2     // if byte 3 is zero
227 #endif /* !XCHAL_HAVE_LOOPS */
228
229         /* Words are equal; some byte is zero.  */
230 .Leq:   movi    a2, 0           // return equal
231         retw
232
233 .Lwne2: /* Words are not equal.  On big-endian processors, if none of the
234            bytes are zero, the return value can be determined by a simple
235            comparison.  */
236 #ifdef __XTENSA_EB__
237         or      a10, a8, a5
238         bnall   a10, a7, .Lsomezero
239         bgeu    a8, a9, .Lposreturn
240         movi    a2, -1
241         retw
242 .Lposreturn:
243         movi    a2, 1
244         retw
245 .Lsomezero:     // There is probably some zero byte.
246 #endif /* __XTENSA_EB__ */
247 .Lwne:  /* Words are not equal.  */
248         xor     a2, a8, a9      // get word with nonzero in byte that differs
249         bany    a2, a4, .Ldiff0 // if byte 0 differs
250         movi    a5, MASK1       // mask for byte 1
251         bnone   a8, a4, .Leq    // if byte 0 is zero
252         bany    a2, a5, .Ldiff1 // if byte 1 differs
253         movi    a6, MASK2       // mask for byte 2
254         bnone   a8, a5, .Leq    // if byte 1 is zero
255         bany    a2, a6, .Ldiff2 // if byte 2 differs
256         bnone   a8, a6, .Leq    // if byte 2 is zero
257 #ifdef __XTENSA_EB__
258 .Ldiff3:
259 .Ldiff2:
260 .Ldiff1:
261         /* Byte 0 is equal (at least) and there is a difference before a zero
262            byte.  Just subtract words to get the return value.
263            The high order equal bytes cancel, leaving room for the sign.  */
264         sub     a2, a8, a9
265         retw
266
267 .Ldiff0:
268         /* Need to make room for the sign, so can't subtract whole words.  */
269         extui   a10, a8, 24, 8
270         extui   a11, a9, 24, 8
271         sub     a2, a10, a11
272         retw
273
274 #else /* !__XTENSA_EB__ */
275         /* Little-endian is a little more difficult because can't subtract
276            whole words.  */
277 .Ldiff3:
278         /* Bytes 0-2 are equal; byte 3 is different.
279            For little-endian need to have a sign bit for the difference.  */
280         extui   a10, a8, 24, 8
281         extui   a11, a9, 24, 8
282         sub     a2, a10, a11
283         retw
284
285 .Ldiff0:
286         /* Byte 0 is different.  */
287         extui   a10, a8, 0, 8
288         extui   a11, a9, 0, 8
289         sub     a2, a10, a11
290         retw
291
292 .Ldiff1:
293         /* Byte 0 is equal; byte 1 is different.  */
294         extui   a10, a8, 8, 8
295         extui   a11, a9, 8, 8
296         sub     a2, a10, a11
297         retw
298
299 .Ldiff2:
300         /* Bytes 0-1 are equal; byte 2 is different.  */
301         extui   a10, a8, 16, 8
302         extui   a11, a9, 16, 8
303         sub     a2, a10, a11
304         retw
305
306 #endif /* !__XTENSA_EB */
307
308 libc_hidden_def (strcmp)
309
310 #ifndef __UCLIBC_HAS_LOCALE__
311 strong_alias (strcmp, strcoll)
312 libc_hidden_def (strcoll)
313 #endif