blob: 62600cd08d26a681dd7890a1381ace88d32d981f [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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#include "memcopy.h"
23
24
25#include <endian.h>
26
27#if __BYTE_ORDER == __BIG_ENDIAN
28# define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
29#else
30# define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
31#endif
32
33/* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */
34
35/* The strategy of this memcmp is:
36
37 1. Compare bytes until one of the block pointers is aligned.
38
39 2. Compare using memcmp_common_alignment or
40 memcmp_not_common_alignment, regarding the alignment of the other
41 block after the initial byte operations. The maximum number of
42 full words (of type op_t) are compared in this way.
43
44 3. Compare the few remaining bytes. */
45
46#if __BYTE_ORDER != __BIG_ENDIAN
47/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
48 A and B are known to be different.
49 This is needed only on little-endian machines. */
50
51static __inline__ int
52memcmp_bytes (op_t a, op_t b)
53{
54 long int srcp1 = (long int) &a;
55 long int srcp2 = (long int) &b;
56 op_t a0, b0;
57
58 do
59 {
60 a0 = ((byte *) srcp1)[0];
61 b0 = ((byte *) srcp2)[0];
62 srcp1 += 1;
63 srcp2 += 1;
64 }
65 while (a0 == b0);
66 return a0 - b0;
67}
68#endif
69
70/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
71 objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for
72 memory operations on `op_t's. */
73static int
74memcmp_common_alignment (long int srcp1, long int srcp2, size_t len)
75{
76 op_t a0, a1;
77 op_t b0, b1;
78
79 switch (len % 4)
80 {
81 default: /* Avoid warning about uninitialized local variables. */
82 case 2:
83 a0 = ((op_t *) srcp1)[0];
84 b0 = ((op_t *) srcp2)[0];
85 srcp1 -= 2 * OPSIZ;
86 srcp2 -= 2 * OPSIZ;
87 len += 2;
88 goto do1;
89 case 3:
90 a1 = ((op_t *) srcp1)[0];
91 b1 = ((op_t *) srcp2)[0];
92 srcp1 -= OPSIZ;
93 srcp2 -= OPSIZ;
94 len += 1;
95 goto do2;
96 case 0:
97 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
98 return 0;
99 a0 = ((op_t *) srcp1)[0];
100 b0 = ((op_t *) srcp2)[0];
101 goto do3;
102 case 1:
103 a1 = ((op_t *) srcp1)[0];
104 b1 = ((op_t *) srcp2)[0];
105 srcp1 += OPSIZ;
106 srcp2 += OPSIZ;
107 len -= 1;
108 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
109 goto do0;
110 /* Fall through. */
111 }
112
113 do
114 {
115 a0 = ((op_t *) srcp1)[0];
116 b0 = ((op_t *) srcp2)[0];
117 if (a1 != b1)
118 return CMP_LT_OR_GT (a1, b1);
119
120 do3:
121 a1 = ((op_t *) srcp1)[1];
122 b1 = ((op_t *) srcp2)[1];
123 if (a0 != b0)
124 return CMP_LT_OR_GT (a0, b0);
125
126 do2:
127 a0 = ((op_t *) srcp1)[2];
128 b0 = ((op_t *) srcp2)[2];
129 if (a1 != b1)
130 return CMP_LT_OR_GT (a1, b1);
131
132 do1:
133 a1 = ((op_t *) srcp1)[3];
134 b1 = ((op_t *) srcp2)[3];
135 if (a0 != b0)
136 return CMP_LT_OR_GT (a0, b0);
137
138 srcp1 += 4 * OPSIZ;
139 srcp2 += 4 * OPSIZ;
140 len -= 4;
141 }
142 while (len != 0);
143
144 /* This is the right position for do0. Please don't move
145 it into the loop. */
146 do0:
147 if (a1 != b1)
148 return CMP_LT_OR_GT (a1, b1);
149 return 0;
150}
151
152/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
153 `op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory
154 operations on `op_t', but SRCP1 *should be unaligned*. */
155static int
156memcmp_not_common_alignment (long int srcp1, long int srcp2, size_t len)
157{
158 op_t a0, a1, a2, a3;
159 op_t b0, b1, b2, b3;
160 op_t x;
161 int shl, shr;
162
163 /* Calculate how to shift a word read at the memory operation
164 aligned srcp1 to make it aligned for comparison. */
165
166 shl = 8 * (srcp1 % OPSIZ);
167 shr = 8 * OPSIZ - shl;
168
169 /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
170 it points in the middle of. */
171 srcp1 &= -OPSIZ;
172
173 switch (len % 4)
174 {
175 default: /* Avoid warning about uninitialized local variables. */
176 case 2:
177 a1 = ((op_t *) srcp1)[0];
178 a2 = ((op_t *) srcp1)[1];
179 b2 = ((op_t *) srcp2)[0];
180 srcp1 -= 1 * OPSIZ;
181 srcp2 -= 2 * OPSIZ;
182 len += 2;
183 goto do1;
184 case 3:
185 a0 = ((op_t *) srcp1)[0];
186 a1 = ((op_t *) srcp1)[1];
187 b1 = ((op_t *) srcp2)[0];
188 srcp2 -= 1 * OPSIZ;
189 len += 1;
190 goto do2;
191 case 0:
192 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
193 return 0;
194 a3 = ((op_t *) srcp1)[0];
195 a0 = ((op_t *) srcp1)[1];
196 b0 = ((op_t *) srcp2)[0];
197 srcp1 += 1 * OPSIZ;
198 goto do3;
199 case 1:
200 a2 = ((op_t *) srcp1)[0];
201 a3 = ((op_t *) srcp1)[1];
202 b3 = ((op_t *) srcp2)[0];
203 srcp1 += 2 * OPSIZ;
204 srcp2 += 1 * OPSIZ;
205 len -= 1;
206 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
207 goto do0;
208 /* Fall through. */
209 }
210
211 do
212 {
213 a0 = ((op_t *) srcp1)[0];
214 b0 = ((op_t *) srcp2)[0];
215 x = MERGE(a2, shl, a3, shr);
216 if (x != b3)
217 return CMP_LT_OR_GT (x, b3);
218
219 do3:
220 a1 = ((op_t *) srcp1)[1];
221 b1 = ((op_t *) srcp2)[1];
222 x = MERGE(a3, shl, a0, shr);
223 if (x != b0)
224 return CMP_LT_OR_GT (x, b0);
225
226 do2:
227 a2 = ((op_t *) srcp1)[2];
228 b2 = ((op_t *) srcp2)[2];
229 x = MERGE(a0, shl, a1, shr);
230 if (x != b1)
231 return CMP_LT_OR_GT (x, b1);
232
233 do1:
234 a3 = ((op_t *) srcp1)[3];
235 b3 = ((op_t *) srcp2)[3];
236 x = MERGE(a1, shl, a2, shr);
237 if (x != b2)
238 return CMP_LT_OR_GT (x, b2);
239
240 srcp1 += 4 * OPSIZ;
241 srcp2 += 4 * OPSIZ;
242 len -= 4;
243 }
244 while (len != 0);
245
246 /* This is the right position for do0. Please don't move
247 it into the loop. */
248 do0:
249 x = MERGE(a2, shl, a3, shr);
250 if (x != b3)
251 return CMP_LT_OR_GT (x, b3);
252 return 0;
253}
254
255int
256memcmp (const __ptr_t s1, const __ptr_t s2, size_t len)
257{
258 op_t a0;
259 op_t b0;
260 long int srcp1 = (long int) s1;
261 long int srcp2 = (long int) s2;
262 op_t res;
263
264 if (len >= OP_T_THRES)
265 {
266 /* There are at least some bytes to compare. No need to test
267 for LEN == 0 in this alignment loop. */
268 while (srcp2 % OPSIZ != 0)
269 {
270 a0 = ((byte *) srcp1)[0];
271 b0 = ((byte *) srcp2)[0];
272 srcp1 += 1;
273 srcp2 += 1;
274 res = a0 - b0;
275 if (res != 0)
276 return res;
277 len -= 1;
278 }
279
280 /* SRCP2 is now aligned for memory operations on `op_t'.
281 SRCP1 alignment determines if we can do a simple,
282 aligned compare or need to shuffle bits. */
283
284 if (srcp1 % OPSIZ == 0)
285 res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
286 else
287 res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
288 if (res != 0)
289 return res;
290
291 /* Number of bytes remaining in the interval [0..OPSIZ-1]. */
292 srcp1 += len & -OPSIZ;
293 srcp2 += len & -OPSIZ;
294 len %= OPSIZ;
295 }
296
297 /* There are just a few bytes to compare. Use byte memory operations. */
298 while (len != 0)
299 {
300 a0 = ((byte *) srcp1)[0];
301 b0 = ((byte *) srcp2)[0];
302 srcp1 += 1;
303 srcp2 += 1;
304 res = a0 - b0;
305 if (res != 0)
306 return res;
307 len -= 1;
308 }
309
310 return 0;
311}
312libc_hidden_weak(memcmp)
313#ifdef __UCLIBC_SUSV3_LEGACY__
314strong_alias(memcmp,bcmp)
315#endif