OSDN Git Service

hidden_def/hidden_proto: convert all users (I hope) termios split, add some missing...
[uclinux-h8/uClibc.git] / libc / string / generic / memcmp.c
1 /* Copyright (C) 1991,1993,1995,1997,1998,2003,2004
2    Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Torbjorn Granlund (tege@sics.se).
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <string.h>
22
23 #include "memcopy.h"
24
25 #include <endian.h>
26
27 #if __BYTE_ORDER == __BIG_ENDIAN
28 # define WORDS_BIGENDIAN
29 #endif
30
31 #ifdef WORDS_BIGENDIAN
32 # define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
33 #else
34 # define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
35 #endif
36
37 /* BE VERY CAREFUL IF YOU CHANGE THIS CODE!  */
38
39 /* The strategy of this memcmp is:
40
41    1. Compare bytes until one of the block pointers is aligned.
42
43    2. Compare using memcmp_common_alignment or
44       memcmp_not_common_alignment, regarding the alignment of the other
45       block after the initial byte operations.  The maximum number of
46       full words (of type op_t) are compared in this way.
47
48    3. Compare the few remaining bytes.  */
49
50 #ifndef WORDS_BIGENDIAN
51 /* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
52    A and B are known to be different.
53    This is needed only on little-endian machines.  */
54
55 static int memcmp_bytes __P((op_t, op_t));
56
57 # ifdef  __GNUC__
58 __inline
59 # endif
60 static int
61 memcmp_bytes (a, b)
62      op_t a, b;
63 {
64   long int srcp1 = (long int) &a;
65   long int srcp2 = (long int) &b;
66   op_t a0, b0;
67
68   do
69     {
70       a0 = ((byte *) srcp1)[0];
71       b0 = ((byte *) srcp2)[0];
72       srcp1 += 1;
73       srcp2 += 1;
74     }
75   while (a0 == b0);
76   return a0 - b0;
77 }
78 #endif
79
80 static int memcmp_common_alignment __P((long, long, size_t));
81
82 /* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
83    objects (not LEN bytes!).  Both SRCP1 and SRCP2 should be aligned for
84    memory operations on `op_t's.  */
85 static int
86 memcmp_common_alignment (srcp1, srcp2, len)
87      long int srcp1;
88      long int srcp2;
89      size_t len;
90 {
91   op_t a0, a1;
92   op_t b0, b1;
93
94   switch (len % 4)
95     {
96     default: /* Avoid warning about uninitialized local variables.  */
97     case 2:
98       a0 = ((op_t *) srcp1)[0];
99       b0 = ((op_t *) srcp2)[0];
100       srcp1 -= 2 * OPSIZ;
101       srcp2 -= 2 * OPSIZ;
102       len += 2;
103       goto do1;
104     case 3:
105       a1 = ((op_t *) srcp1)[0];
106       b1 = ((op_t *) srcp2)[0];
107       srcp1 -= OPSIZ;
108       srcp2 -= OPSIZ;
109       len += 1;
110       goto do2;
111     case 0:
112       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
113         return 0;
114       a0 = ((op_t *) srcp1)[0];
115       b0 = ((op_t *) srcp2)[0];
116       goto do3;
117     case 1:
118       a1 = ((op_t *) srcp1)[0];
119       b1 = ((op_t *) srcp2)[0];
120       srcp1 += OPSIZ;
121       srcp2 += OPSIZ;
122       len -= 1;
123       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
124         goto do0;
125       /* Fall through.  */
126     }
127
128   do
129     {
130       a0 = ((op_t *) srcp1)[0];
131       b0 = ((op_t *) srcp2)[0];
132       if (a1 != b1)
133         return CMP_LT_OR_GT (a1, b1);
134
135     do3:
136       a1 = ((op_t *) srcp1)[1];
137       b1 = ((op_t *) srcp2)[1];
138       if (a0 != b0)
139         return CMP_LT_OR_GT (a0, b0);
140
141     do2:
142       a0 = ((op_t *) srcp1)[2];
143       b0 = ((op_t *) srcp2)[2];
144       if (a1 != b1)
145         return CMP_LT_OR_GT (a1, b1);
146
147     do1:
148       a1 = ((op_t *) srcp1)[3];
149       b1 = ((op_t *) srcp2)[3];
150       if (a0 != b0)
151         return CMP_LT_OR_GT (a0, b0);
152
153       srcp1 += 4 * OPSIZ;
154       srcp2 += 4 * OPSIZ;
155       len -= 4;
156     }
157   while (len != 0);
158
159   /* This is the right position for do0.  Please don't move
160      it into the loop.  */
161  do0:
162   if (a1 != b1)
163     return CMP_LT_OR_GT (a1, b1);
164   return 0;
165 }
166
167 static int memcmp_not_common_alignment __P((long, long, size_t));
168
169 /* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
170    `op_t' objects (not LEN bytes!).  SRCP2 should be aligned for memory
171    operations on `op_t', but SRCP1 *should be unaligned*.  */
172 static int
173 memcmp_not_common_alignment (srcp1, srcp2, len)
174      long int srcp1;
175      long int srcp2;
176      size_t len;
177 {
178   op_t a0, a1, a2, a3;
179   op_t b0, b1, b2, b3;
180   op_t x;
181   int shl, shr;
182
183   /* Calculate how to shift a word read at the memory operation
184      aligned srcp1 to make it aligned for comparison.  */
185
186   shl = 8 * (srcp1 % OPSIZ);
187   shr = 8 * OPSIZ - shl;
188
189   /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
190      it points in the middle of.  */
191   srcp1 &= -OPSIZ;
192
193   switch (len % 4)
194     {
195     default: /* Avoid warning about uninitialized local variables.  */
196     case 2:
197       a1 = ((op_t *) srcp1)[0];
198       a2 = ((op_t *) srcp1)[1];
199       b2 = ((op_t *) srcp2)[0];
200       srcp1 -= 1 * OPSIZ;
201       srcp2 -= 2 * OPSIZ;
202       len += 2;
203       goto do1;
204     case 3:
205       a0 = ((op_t *) srcp1)[0];
206       a1 = ((op_t *) srcp1)[1];
207       b1 = ((op_t *) srcp2)[0];
208       srcp2 -= 1 * OPSIZ;
209       len += 1;
210       goto do2;
211     case 0:
212       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
213         return 0;
214       a3 = ((op_t *) srcp1)[0];
215       a0 = ((op_t *) srcp1)[1];
216       b0 = ((op_t *) srcp2)[0];
217       srcp1 += 1 * OPSIZ;
218       goto do3;
219     case 1:
220       a2 = ((op_t *) srcp1)[0];
221       a3 = ((op_t *) srcp1)[1];
222       b3 = ((op_t *) srcp2)[0];
223       srcp1 += 2 * OPSIZ;
224       srcp2 += 1 * OPSIZ;
225       len -= 1;
226       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
227         goto do0;
228       /* Fall through.  */
229     }
230
231   do
232     {
233       a0 = ((op_t *) srcp1)[0];
234       b0 = ((op_t *) srcp2)[0];
235       x = MERGE(a2, shl, a3, shr);
236       if (x != b3)
237         return CMP_LT_OR_GT (x, b3);
238
239     do3:
240       a1 = ((op_t *) srcp1)[1];
241       b1 = ((op_t *) srcp2)[1];
242       x = MERGE(a3, shl, a0, shr);
243       if (x != b0)
244         return CMP_LT_OR_GT (x, b0);
245
246     do2:
247       a2 = ((op_t *) srcp1)[2];
248       b2 = ((op_t *) srcp2)[2];
249       x = MERGE(a0, shl, a1, shr);
250       if (x != b1)
251         return CMP_LT_OR_GT (x, b1);
252
253     do1:
254       a3 = ((op_t *) srcp1)[3];
255       b3 = ((op_t *) srcp2)[3];
256       x = MERGE(a1, shl, a2, shr);
257       if (x != b2)
258         return CMP_LT_OR_GT (x, b2);
259
260       srcp1 += 4 * OPSIZ;
261       srcp2 += 4 * OPSIZ;
262       len -= 4;
263     }
264   while (len != 0);
265
266   /* This is the right position for do0.  Please don't move
267      it into the loop.  */
268  do0:
269   x = MERGE(a2, shl, a3, shr);
270   if (x != b3)
271     return CMP_LT_OR_GT (x, b3);
272   return 0;
273 }
274
275 int
276 memcmp (const __ptr_t s1, const __ptr_t s2, size_t len)
277 {
278   op_t a0;
279   op_t b0;
280   long int srcp1 = (long int) s1;
281   long int srcp2 = (long int) s2;
282   op_t res;
283
284   if (len >= OP_T_THRES)
285     {
286       /* There are at least some bytes to compare.  No need to test
287          for LEN == 0 in this alignment loop.  */
288       while (srcp2 % OPSIZ != 0)
289         {
290           a0 = ((byte *) srcp1)[0];
291           b0 = ((byte *) srcp2)[0];
292           srcp1 += 1;
293           srcp2 += 1;
294           res = a0 - b0;
295           if (res != 0)
296             return res;
297           len -= 1;
298         }
299
300       /* SRCP2 is now aligned for memory operations on `op_t'.
301          SRCP1 alignment determines if we can do a simple,
302          aligned compare or need to shuffle bits.  */
303
304       if (srcp1 % OPSIZ == 0)
305         res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
306       else
307         res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
308       if (res != 0)
309         return res;
310
311       /* Number of bytes remaining in the interval [0..OPSIZ-1].  */
312       srcp1 += len & -OPSIZ;
313       srcp2 += len & -OPSIZ;
314       len %= OPSIZ;
315     }
316
317   /* There are just a few bytes to compare.  Use byte memory operations.  */
318   while (len != 0)
319     {
320       a0 = ((byte *) srcp1)[0];
321       b0 = ((byte *) srcp2)[0];
322       srcp1 += 1;
323       srcp2 += 1;
324       res = a0 - b0;
325       if (res != 0)
326         return res;
327       len -= 1;
328     }
329
330   return 0;
331 }
332 libc_hidden_proto(memcmp)
333 libc_hidden_def(memcmp)
334 strong_alias(memcmp,bcmp)