source: trunk/third/sed/lib/memcmp.c @ 17271

Revision 17271, 9.2 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17270, which included commits to RCS files with non-trunk default branches.
Line 
1/* Copyright (C) 1991, 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
2   Contributed by Torbjorn Granlund (tege@sics.se).
3
4   NOTE: The canonical source of this file is maintained with the GNU C Library.
5   Bugs can be reported to bug-glibc@gnu.org.
6
7   This program is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2, or (at your option) any
10   later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20   USA.  */
21
22#ifdef HAVE_CONFIG_H
23# include "config.h"
24#endif
25
26#undef  __ptr_t
27#if defined __cplusplus || (defined __STDC__ && __STDC__)
28# define __ptr_t        void *
29#else /* Not C++ or ANSI C.  */
30# undef const
31# define const
32# define __ptr_t        char *
33#endif /* C++ or ANSI C.  */
34
35#ifndef __P
36# if defined __GNUC__ || (defined __STDC__ && __STDC__)
37#  define __P(args) args
38# else
39#  define __P(args) ()
40# endif  /* GCC.  */
41#endif  /* Not __P.  */
42
43#if defined HAVE_STRING_H || defined _LIBC
44# include <string.h>
45#endif
46
47#undef memcmp
48
49#ifdef _LIBC
50
51# include <memcopy.h>
52# include <endian.h>
53
54# if __BYTE_ORDER == __BIG_ENDIAN
55#  define WORDS_BIGENDIAN
56# endif
57
58#else   /* Not in the GNU C library.  */
59
60# include <sys/types.h>
61
62/* Type to use for aligned memory operations.
63   This should normally be the biggest type supported by a single load
64   and store.  Must be an unsigned type.  */
65# define op_t   unsigned long int
66# define OPSIZ  (sizeof(op_t))
67
68/* Threshold value for when to enter the unrolled loops.  */
69# define OP_T_THRES     16
70
71/* Type to use for unaligned operations.  */
72typedef unsigned char byte;
73
74# ifndef WORDS_BIGENDIAN
75#  define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
76# else
77#  define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
78# endif
79
80#endif  /* In the GNU C library.  */
81
82#ifdef WORDS_BIGENDIAN
83# define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
84#else
85# define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
86#endif
87
88/* BE VERY CAREFUL IF YOU CHANGE THIS CODE!  */
89
90/* The strategy of this memcmp is:
91
92   1. Compare bytes until one of the block pointers is aligned.
93
94   2. Compare using memcmp_common_alignment or
95      memcmp_not_common_alignment, regarding the alignment of the other
96      block after the initial byte operations.  The maximum number of
97      full words (of type op_t) are compared in this way.
98
99   3. Compare the few remaining bytes.  */
100
101#ifndef WORDS_BIGENDIAN
102/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
103   A and B are known to be different.
104   This is needed only on little-endian machines.  */
105
106static int memcmp_bytes __P((op_t, op_t));
107
108# ifdef  __GNUC__
109__inline
110# endif
111static int
112memcmp_bytes (a, b)
113     op_t a, b;
114{
115  long int srcp1 = (long int) &a;
116  long int srcp2 = (long int) &b;
117  op_t a0, b0;
118
119  do
120    {
121      a0 = ((byte *) srcp1)[0];
122      b0 = ((byte *) srcp2)[0];
123      srcp1 += 1;
124      srcp2 += 1;
125    }
126  while (a0 == b0);
127  return a0 - b0;
128}
129#endif
130
131static int memcmp_common_alignment __P((long, long, size_t));
132
133/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
134   objects (not LEN bytes!).  Both SRCP1 and SRCP2 should be aligned for
135   memory operations on `op_t's.  */
136#ifdef  __GNUC__
137__inline
138#endif
139static int
140memcmp_common_alignment (srcp1, srcp2, len)
141     long int srcp1;
142     long int srcp2;
143     size_t len;
144{
145  op_t a0, a1;
146  op_t b0, b1;
147
148  switch (len % 4)
149    {
150    default: /* Avoid warning about uninitialized local variables.  */
151    case 2:
152      a0 = ((op_t *) srcp1)[0];
153      b0 = ((op_t *) srcp2)[0];
154      srcp1 -= 2 * OPSIZ;
155      srcp2 -= 2 * OPSIZ;
156      len += 2;
157      goto do1;
158    case 3:
159      a1 = ((op_t *) srcp1)[0];
160      b1 = ((op_t *) srcp2)[0];
161      srcp1 -= OPSIZ;
162      srcp2 -= OPSIZ;
163      len += 1;
164      goto do2;
165    case 0:
166      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
167        return 0;
168      a0 = ((op_t *) srcp1)[0];
169      b0 = ((op_t *) srcp2)[0];
170      goto do3;
171    case 1:
172      a1 = ((op_t *) srcp1)[0];
173      b1 = ((op_t *) srcp2)[0];
174      srcp1 += OPSIZ;
175      srcp2 += OPSIZ;
176      len -= 1;
177      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
178        goto do0;
179      /* Fall through.  */
180    }
181
182  do
183    {
184      a0 = ((op_t *) srcp1)[0];
185      b0 = ((op_t *) srcp2)[0];
186      if (a1 != b1)
187        return CMP_LT_OR_GT (a1, b1);
188
189    do3:
190      a1 = ((op_t *) srcp1)[1];
191      b1 = ((op_t *) srcp2)[1];
192      if (a0 != b0)
193        return CMP_LT_OR_GT (a0, b0);
194
195    do2:
196      a0 = ((op_t *) srcp1)[2];
197      b0 = ((op_t *) srcp2)[2];
198      if (a1 != b1)
199        return CMP_LT_OR_GT (a1, b1);
200
201    do1:
202      a1 = ((op_t *) srcp1)[3];
203      b1 = ((op_t *) srcp2)[3];
204      if (a0 != b0)
205        return CMP_LT_OR_GT (a0, b0);
206
207      srcp1 += 4 * OPSIZ;
208      srcp2 += 4 * OPSIZ;
209      len -= 4;
210    }
211  while (len != 0);
212
213  /* This is the right position for do0.  Please don't move
214     it into the loop.  */
215 do0:
216  if (a1 != b1)
217    return CMP_LT_OR_GT (a1, b1);
218  return 0;
219}
220
221static int memcmp_not_common_alignment __P((long, long, size_t));
222
223/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
224   `op_t' objects (not LEN bytes!).  SRCP2 should be aligned for memory
225   operations on `op_t', but SRCP1 *should be unaligned*.  */
226#ifdef  __GNUC__
227__inline
228#endif
229static int
230memcmp_not_common_alignment (srcp1, srcp2, len)
231     long int srcp1;
232     long int srcp2;
233     size_t len;
234{
235  op_t a0, a1, a2, a3;
236  op_t b0, b1, b2, b3;
237  op_t x;
238  int shl, shr;
239
240  /* Calculate how to shift a word read at the memory operation
241     aligned srcp1 to make it aligned for comparison.  */
242
243  shl = 8 * (srcp1 % OPSIZ);
244  shr = 8 * OPSIZ - shl;
245
246  /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
247     it points in the middle of.  */
248  srcp1 &= -OPSIZ;
249
250  switch (len % 4)
251    {
252    default: /* Avoid warning about uninitialized local variables.  */
253    case 2:
254      a1 = ((op_t *) srcp1)[0];
255      a2 = ((op_t *) srcp1)[1];
256      b2 = ((op_t *) srcp2)[0];
257      srcp1 -= 1 * OPSIZ;
258      srcp2 -= 2 * OPSIZ;
259      len += 2;
260      goto do1;
261    case 3:
262      a0 = ((op_t *) srcp1)[0];
263      a1 = ((op_t *) srcp1)[1];
264      b1 = ((op_t *) srcp2)[0];
265      srcp2 -= 1 * OPSIZ;
266      len += 1;
267      goto do2;
268    case 0:
269      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
270        return 0;
271      a3 = ((op_t *) srcp1)[0];
272      a0 = ((op_t *) srcp1)[1];
273      b0 = ((op_t *) srcp2)[0];
274      srcp1 += 1 * OPSIZ;
275      goto do3;
276    case 1:
277      a2 = ((op_t *) srcp1)[0];
278      a3 = ((op_t *) srcp1)[1];
279      b3 = ((op_t *) srcp2)[0];
280      srcp1 += 2 * OPSIZ;
281      srcp2 += 1 * OPSIZ;
282      len -= 1;
283      if (OP_T_THRES <= 3 * OPSIZ && len == 0)
284        goto do0;
285      /* Fall through.  */
286    }
287
288  do
289    {
290      a0 = ((op_t *) srcp1)[0];
291      b0 = ((op_t *) srcp2)[0];
292      x = MERGE(a2, shl, a3, shr);
293      if (x != b3)
294        return CMP_LT_OR_GT (x, b3);
295
296    do3:
297      a1 = ((op_t *) srcp1)[1];
298      b1 = ((op_t *) srcp2)[1];
299      x = MERGE(a3, shl, a0, shr);
300      if (x != b0)
301        return CMP_LT_OR_GT (x, b0);
302
303    do2:
304      a2 = ((op_t *) srcp1)[2];
305      b2 = ((op_t *) srcp2)[2];
306      x = MERGE(a0, shl, a1, shr);
307      if (x != b1)
308        return CMP_LT_OR_GT (x, b1);
309
310    do1:
311      a3 = ((op_t *) srcp1)[3];
312      b3 = ((op_t *) srcp2)[3];
313      x = MERGE(a1, shl, a2, shr);
314      if (x != b2)
315        return CMP_LT_OR_GT (x, b2);
316
317      srcp1 += 4 * OPSIZ;
318      srcp2 += 4 * OPSIZ;
319      len -= 4;
320    }
321  while (len != 0);
322
323  /* This is the right position for do0.  Please don't move
324     it into the loop.  */
325 do0:
326  x = MERGE(a2, shl, a3, shr);
327  if (x != b3)
328    return CMP_LT_OR_GT (x, b3);
329  return 0;
330}
331
332int
333memcmp (s1, s2, len)
334     const __ptr_t s1;
335     const __ptr_t s2;
336     size_t len;
337{
338  op_t a0;
339  op_t b0;
340  long int srcp1 = (long int) s1;
341  long int srcp2 = (long int) s2;
342  op_t res;
343
344  if (len >= OP_T_THRES)
345    {
346      /* There are at least some bytes to compare.  No need to test
347         for LEN == 0 in this alignment loop.  */
348      while (srcp2 % OPSIZ != 0)
349        {
350          a0 = ((byte *) srcp1)[0];
351          b0 = ((byte *) srcp2)[0];
352          srcp1 += 1;
353          srcp2 += 1;
354          res = a0 - b0;
355          if (res != 0)
356            return res;
357          len -= 1;
358        }
359
360      /* SRCP2 is now aligned for memory operations on `op_t'.
361         SRCP1 alignment determines if we can do a simple,
362         aligned compare or need to shuffle bits.  */
363
364      if (srcp1 % OPSIZ == 0)
365        res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
366      else
367        res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
368      if (res != 0)
369        return res;
370
371      /* Number of bytes remaining in the interval [0..OPSIZ-1].  */
372      srcp1 += len & -OPSIZ;
373      srcp2 += len & -OPSIZ;
374      len %= OPSIZ;
375    }
376
377  /* There are just a few bytes to compare.  Use byte memory operations.  */
378  while (len != 0)
379    {
380      a0 = ((byte *) srcp1)[0];
381      b0 = ((byte *) srcp2)[0];
382      srcp1 += 1;
383      srcp2 += 1;
384      res = a0 - b0;
385      if (res != 0)
386        return res;
387      len -= 1;
388    }
389
390  return 0;
391}
392
393#ifdef weak_alias
394# undef bcmp
395weak_alias (memcmp, bcmp)
396#endif
Note: See TracBrowser for help on using the repository browser.