1 /* Copyright (C) 1991, 1993, 1995, 1997-1998, 2003, 2006, 2009-2024 Free
2 Software Foundation, Inc.
4 Contributed by Torbjorn Granlund (tege@sics.se).
6 NOTE: The canonical source of this file is maintained with the GNU C Library.
7 Bugs can be reported to bug-glibc@prep.ai.mit.edu.
9 This file is free software: you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
14 This file is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with this program. If not, see <https://www.gnu.org/licenses/>. */
37 # if __BYTE_ORDER == __BIG_ENDIAN
38 # define WORDS_BIGENDIAN
41 #else /* Not in the GNU C library. */
43 # include <sys/types.h>
45 /* Type to use for aligned memory operations.
46 This should normally be the biggest type supported by a single load
47 and store. Must be an unsigned type. */
48 # define op_t unsigned long int
49 # define OPSIZ (sizeof(op_t))
51 /* Threshold value for when to enter the unrolled loops. */
52 # define OP_T_THRES 16
54 /* Type to use for unaligned operations. */
55 typedef unsigned char byte
;
57 # ifndef WORDS_BIGENDIAN
58 # define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
60 # define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
63 #endif /* In the GNU C library. */
65 #ifdef WORDS_BIGENDIAN
66 # define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
68 # define CMP_LT_OR_GT(a, b) memcmp_bytes (a, b)
71 /* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */
73 /* The strategy of this memcmp is:
75 1. Compare bytes until one of the block pointers is aligned.
77 2. Compare using memcmp_common_alignment or
78 memcmp_not_common_alignment, regarding the alignment of the other
79 block after the initial byte operations. The maximum number of
80 full words (of type op_t) are compared in this way.
82 3. Compare the few remaining bytes. */
84 #ifndef WORDS_BIGENDIAN
85 /* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
86 A and B are known to be different.
87 This is needed only on little-endian machines. */
93 memcmp_bytes (op_t a
, op_t b
)
95 const byte
*srcp1
= (const byte
*) &a
;
96 const byte
*srcp2
= (const byte
*) &b
;
111 /* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN 'op_t'
112 objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for
113 memory operations on 'op_t's. */
118 memcmp_common_alignment (uintptr_t srcp1
, uintptr_t srcp2
, size_t len
)
125 default: /* Avoid warning about uninitialized local variables. */
127 a0
= ((op_t
*) srcp1
)[0];
128 b0
= ((op_t
*) srcp2
)[0];
134 a1
= ((op_t
*) srcp1
)[0];
135 b1
= ((op_t
*) srcp2
)[0];
141 if (OP_T_THRES
<= 3 * OPSIZ
&& len
== 0)
143 a0
= ((op_t
*) srcp1
)[0];
144 b0
= ((op_t
*) srcp2
)[0];
147 a1
= ((op_t
*) srcp1
)[0];
148 b1
= ((op_t
*) srcp2
)[0];
152 if (OP_T_THRES
<= 3 * OPSIZ
&& len
== 0)
159 a0
= ((op_t
*) srcp1
)[0];
160 b0
= ((op_t
*) srcp2
)[0];
162 return CMP_LT_OR_GT (a1
, b1
);
165 a1
= ((op_t
*) srcp1
)[1];
166 b1
= ((op_t
*) srcp2
)[1];
168 return CMP_LT_OR_GT (a0
, b0
);
171 a0
= ((op_t
*) srcp1
)[2];
172 b0
= ((op_t
*) srcp2
)[2];
174 return CMP_LT_OR_GT (a1
, b1
);
177 a1
= ((op_t
*) srcp1
)[3];
178 b1
= ((op_t
*) srcp2
)[3];
180 return CMP_LT_OR_GT (a0
, b0
);
188 /* This is the right position for do0. Please don't move
192 return CMP_LT_OR_GT (a1
, b1
);
196 /* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
197 'op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory
198 operations on 'op_t', but SRCP1 *should be unaligned*. */
203 memcmp_not_common_alignment (uintptr_t srcp1
, uintptr_t srcp2
, size_t len
)
210 /* Calculate how to shift a word read at the memory operation
211 aligned srcp1 to make it aligned for comparison. */
213 shl
= 8 * (srcp1
% OPSIZ
);
214 shr
= 8 * OPSIZ
- shl
;
216 /* Make SRCP1 aligned by rounding it down to the beginning of the 'op_t'
217 it points in the middle of. */
222 default: /* Avoid warning about uninitialized local variables. */
224 a1
= ((op_t
*) srcp1
)[0];
225 a2
= ((op_t
*) srcp1
)[1];
226 b2
= ((op_t
*) srcp2
)[0];
232 a0
= ((op_t
*) srcp1
)[0];
233 a1
= ((op_t
*) srcp1
)[1];
234 b1
= ((op_t
*) srcp2
)[0];
239 if (OP_T_THRES
<= 3 * OPSIZ
&& len
== 0)
241 a3
= ((op_t
*) srcp1
)[0];
242 a0
= ((op_t
*) srcp1
)[1];
243 b0
= ((op_t
*) srcp2
)[0];
247 a2
= ((op_t
*) srcp1
)[0];
248 a3
= ((op_t
*) srcp1
)[1];
249 b3
= ((op_t
*) srcp2
)[0];
253 if (OP_T_THRES
<= 3 * OPSIZ
&& len
== 0)
260 a0
= ((op_t
*) srcp1
)[0];
261 b0
= ((op_t
*) srcp2
)[0];
262 x
= MERGE (a2
, shl
, a3
, shr
);
264 return CMP_LT_OR_GT (x
, b3
);
267 a1
= ((op_t
*) srcp1
)[1];
268 b1
= ((op_t
*) srcp2
)[1];
269 x
= MERGE (a3
, shl
, a0
, shr
);
271 return CMP_LT_OR_GT (x
, b0
);
274 a2
= ((op_t
*) srcp1
)[2];
275 b2
= ((op_t
*) srcp2
)[2];
276 x
= MERGE (a0
, shl
, a1
, shr
);
278 return CMP_LT_OR_GT (x
, b1
);
281 a3
= ((op_t
*) srcp1
)[3];
282 b3
= ((op_t
*) srcp2
)[3];
283 x
= MERGE (a1
, shl
, a2
, shr
);
285 return CMP_LT_OR_GT (x
, b2
);
293 /* This is the right position for do0. Please don't move
296 x
= MERGE (a2
, shl
, a3
, shr
);
298 return CMP_LT_OR_GT (x
, b3
);
303 rpl_memcmp (const void *s1
, const void *s2
, size_t len
)
307 uintptr_t srcp1
= (uintptr_t) s1
;
308 uintptr_t srcp2
= (uintptr_t) s2
;
311 if (len
>= OP_T_THRES
)
313 /* There are at least some bytes to compare. No need to test
314 for LEN == 0 in this alignment loop. */
315 while (srcp2
% OPSIZ
!= 0)
317 a0
= ((byte
*) srcp1
)[0];
318 b0
= ((byte
*) srcp2
)[0];
327 /* SRCP2 is now aligned for memory operations on 'op_t'.
328 SRCP1 alignment determines if we can do a simple,
329 aligned compare or need to shuffle bits. */
331 if (srcp1
% OPSIZ
== 0)
332 res
= memcmp_common_alignment (srcp1
, srcp2
, len
/ OPSIZ
);
334 res
= memcmp_not_common_alignment (srcp1
, srcp2
, len
/ OPSIZ
);
338 /* Number of bytes remaining in the interval [0..OPSIZ-1]. */
339 srcp1
+= len
& -OPSIZ
;
340 srcp2
+= len
& -OPSIZ
;
344 /* There are just a few bytes to compare. Use byte memory operations. */
347 a0
= ((byte
*) srcp1
)[0];
348 b0
= ((byte
*) srcp2
)[0];
362 weak_alias (memcmp
, bcmp
)