1/* _memcopy.c -- subroutines for memory copy functions.
2 Copyright (C) 1991-2024 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, see
17 <https://www.gnu.org/licenses/>. */
18
19/* BE VERY CAREFUL IF YOU CHANGE THIS CODE...! */
20
21#include <stddef.h>
22#include <libc-diag.h>
23/* Compiling with -O1 might warn that 'a2' and 'a3' may be used
24 uninitialized. There are only two ways to arrive at labels 'do4', 'do3'
25 or 'do1', all of which use 'a2' or 'a3' in the MERGE macro: either from
26 the earlier switch case statement or via a loop iteration. In all cases
27 the switch statement or previous loop sets both 'a2' and 'a3'.
28
29 Since the usage is within the MERGE macro we disable the
30 warning in the definition, but only in this file. */
31DIAG_PUSH_NEEDS_COMMENT;
32DIAG_IGNORE_NEEDS_COMMENT (6, "-Wmaybe-uninitialized");
33#include <memcopy.h>
34DIAG_POP_NEEDS_COMMENT;
35
36/* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to
37 block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
38 Both SRCP and DSTP should be aligned for memory operations on `op_t's. */
39
40#ifndef WORDCOPY_FWD_ALIGNED
41# define WORDCOPY_FWD_ALIGNED _wordcopy_fwd_aligned
42#endif
43
44void
45WORDCOPY_FWD_ALIGNED (long int dstp, long int srcp, size_t len)
46{
47 op_t a0, a1;
48
49 switch (len % 8)
50 {
51 case 2:
52 a0 = ((op_t *) srcp)[0];
53 srcp -= 6 * OPSIZ;
54 dstp -= 7 * OPSIZ;
55 len += 6;
56 goto do1;
57 case 3:
58 a1 = ((op_t *) srcp)[0];
59 srcp -= 5 * OPSIZ;
60 dstp -= 6 * OPSIZ;
61 len += 5;
62 goto do2;
63 case 4:
64 a0 = ((op_t *) srcp)[0];
65 srcp -= 4 * OPSIZ;
66 dstp -= 5 * OPSIZ;
67 len += 4;
68 goto do3;
69 case 5:
70 a1 = ((op_t *) srcp)[0];
71 srcp -= 3 * OPSIZ;
72 dstp -= 4 * OPSIZ;
73 len += 3;
74 goto do4;
75 case 6:
76 a0 = ((op_t *) srcp)[0];
77 srcp -= 2 * OPSIZ;
78 dstp -= 3 * OPSIZ;
79 len += 2;
80 goto do5;
81 case 7:
82 a1 = ((op_t *) srcp)[0];
83 srcp -= 1 * OPSIZ;
84 dstp -= 2 * OPSIZ;
85 len += 1;
86 goto do6;
87
88 case 0:
89 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
90 return;
91 a0 = ((op_t *) srcp)[0];
92 srcp -= 0 * OPSIZ;
93 dstp -= 1 * OPSIZ;
94 goto do7;
95 case 1:
96 a1 = ((op_t *) srcp)[0];
97 srcp -=-1 * OPSIZ;
98 dstp -= 0 * OPSIZ;
99 len -= 1;
100 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
101 goto do0;
102 goto do8; /* No-op. */
103 }
104
105 do
106 {
107 do8:
108 a0 = ((op_t *) srcp)[0];
109 /* Compiling with -O1 may warn that 'a1' may be used uninitialized.
110 There are only two ways to arrive at label 'do8' and they are via a
111 do-while loop iteration or directly via the earlier switch 'case 1:'
112 case. The switch case always sets 'a1' and all previous loop
113 iterations will also have set 'a1' before the use. */
114 DIAG_PUSH_NEEDS_COMMENT;
115 DIAG_IGNORE_NEEDS_COMMENT (6, "-Wmaybe-uninitialized");
116 ((op_t *) dstp)[0] = a1;
117 DIAG_POP_NEEDS_COMMENT;
118 do7:
119 a1 = ((op_t *) srcp)[1];
120 ((op_t *) dstp)[1] = a0;
121 do6:
122 a0 = ((op_t *) srcp)[2];
123 ((op_t *) dstp)[2] = a1;
124 do5:
125 a1 = ((op_t *) srcp)[3];
126 ((op_t *) dstp)[3] = a0;
127 do4:
128 a0 = ((op_t *) srcp)[4];
129 ((op_t *) dstp)[4] = a1;
130 do3:
131 a1 = ((op_t *) srcp)[5];
132 ((op_t *) dstp)[5] = a0;
133 do2:
134 a0 = ((op_t *) srcp)[6];
135 ((op_t *) dstp)[6] = a1;
136 do1:
137 a1 = ((op_t *) srcp)[7];
138 ((op_t *) dstp)[7] = a0;
139
140 srcp += 8 * OPSIZ;
141 dstp += 8 * OPSIZ;
142 len -= 8;
143 }
144 while (len != 0);
145
146 /* This is the right position for do0. Please don't move
147 it into the loop. */
148 do0:
149 ((op_t *) dstp)[0] = a1;
150}
151
152/* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to
153 block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
154 DSTP should be aligned for memory operations on `op_t's, but SRCP must
155 *not* be aligned. */
156
157#ifndef WORDCOPY_FWD_DEST_ALIGNED
158# define WORDCOPY_FWD_DEST_ALIGNED _wordcopy_fwd_dest_aligned
159#endif
160
161void
162WORDCOPY_FWD_DEST_ALIGNED (long int dstp, long int srcp, size_t len)
163{
164 op_t a0, a1, a2, a3;
165 int sh_1, sh_2;
166
167 /* Calculate how to shift a word read at the memory operation
168 aligned srcp to make it aligned for copy. */
169
170 sh_1 = 8 * (srcp % OPSIZ);
171 sh_2 = 8 * OPSIZ - sh_1;
172
173 /* Make SRCP aligned by rounding it down to the beginning of the `op_t'
174 it points in the middle of. */
175 srcp &= -OPSIZ;
176
177 switch (len % 4)
178 {
179 case 2:
180 a1 = ((op_t *) srcp)[0];
181 a2 = ((op_t *) srcp)[1];
182 srcp -= 1 * OPSIZ;
183 dstp -= 3 * OPSIZ;
184 len += 2;
185 goto do1;
186 case 3:
187 a0 = ((op_t *) srcp)[0];
188 a1 = ((op_t *) srcp)[1];
189 srcp -= 0 * OPSIZ;
190 dstp -= 2 * OPSIZ;
191 len += 1;
192 goto do2;
193 case 0:
194 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
195 return;
196 a3 = ((op_t *) srcp)[0];
197 a0 = ((op_t *) srcp)[1];
198 srcp -=-1 * OPSIZ;
199 dstp -= 1 * OPSIZ;
200 len += 0;
201 goto do3;
202 case 1:
203 a2 = ((op_t *) srcp)[0];
204 a3 = ((op_t *) srcp)[1];
205 srcp -=-2 * OPSIZ;
206 dstp -= 0 * OPSIZ;
207 len -= 1;
208 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
209 goto do0;
210 goto do4; /* No-op. */
211 }
212
213 do
214 {
215 do4:
216 a0 = ((op_t *) srcp)[0];
217 ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
218 do3:
219 a1 = ((op_t *) srcp)[1];
220 ((op_t *) dstp)[1] = MERGE (a3, sh_1, a0, sh_2);
221 do2:
222 a2 = ((op_t *) srcp)[2];
223 ((op_t *) dstp)[2] = MERGE (a0, sh_1, a1, sh_2);
224 do1:
225 a3 = ((op_t *) srcp)[3];
226 ((op_t *) dstp)[3] = MERGE (a1, sh_1, a2, sh_2);
227
228 srcp += 4 * OPSIZ;
229 dstp += 4 * OPSIZ;
230 len -= 4;
231 }
232 while (len != 0);
233
234 /* This is the right position for do0. Please don't move
235 it into the loop. */
236 do0:
237 ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
238}
239
240/* _wordcopy_bwd_aligned -- Copy block finishing right before
241 SRCP to block finishing right before DSTP with LEN `op_t' words
242 (not LEN bytes!). Both SRCP and DSTP should be aligned for memory
243 operations on `op_t's. */
244
245#ifndef WORDCOPY_BWD_ALIGNED
246# define WORDCOPY_BWD_ALIGNED _wordcopy_bwd_aligned
247#endif
248
249void
250WORDCOPY_BWD_ALIGNED (long int dstp, long int srcp, size_t len)
251{
252 op_t a0, a1;
253
254 switch (len % 8)
255 {
256 case 2:
257 srcp -= 2 * OPSIZ;
258 dstp -= 1 * OPSIZ;
259 a0 = ((op_t *) srcp)[1];
260 len += 6;
261 goto do1;
262 case 3:
263 srcp -= 3 * OPSIZ;
264 dstp -= 2 * OPSIZ;
265 a1 = ((op_t *) srcp)[2];
266 len += 5;
267 goto do2;
268 case 4:
269 srcp -= 4 * OPSIZ;
270 dstp -= 3 * OPSIZ;
271 a0 = ((op_t *) srcp)[3];
272 len += 4;
273 goto do3;
274 case 5:
275 srcp -= 5 * OPSIZ;
276 dstp -= 4 * OPSIZ;
277 a1 = ((op_t *) srcp)[4];
278 len += 3;
279 goto do4;
280 case 6:
281 srcp -= 6 * OPSIZ;
282 dstp -= 5 * OPSIZ;
283 a0 = ((op_t *) srcp)[5];
284 len += 2;
285 goto do5;
286 case 7:
287 srcp -= 7 * OPSIZ;
288 dstp -= 6 * OPSIZ;
289 a1 = ((op_t *) srcp)[6];
290 len += 1;
291 goto do6;
292
293 case 0:
294 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
295 return;
296 srcp -= 8 * OPSIZ;
297 dstp -= 7 * OPSIZ;
298 a0 = ((op_t *) srcp)[7];
299 goto do7;
300 case 1:
301 srcp -= 9 * OPSIZ;
302 dstp -= 8 * OPSIZ;
303 a1 = ((op_t *) srcp)[8];
304 len -= 1;
305 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
306 goto do0;
307 goto do8; /* No-op. */
308 }
309
310 do
311 {
312 do8:
313 a0 = ((op_t *) srcp)[7];
314 /* Check the comment on WORDCOPY_FWD_ALIGNED. */
315 DIAG_PUSH_NEEDS_COMMENT;
316 DIAG_IGNORE_NEEDS_COMMENT (6, "-Wmaybe-uninitialized");
317 ((op_t *) dstp)[7] = a1;
318 DIAG_POP_NEEDS_COMMENT;
319 do7:
320 a1 = ((op_t *) srcp)[6];
321 ((op_t *) dstp)[6] = a0;
322 do6:
323 a0 = ((op_t *) srcp)[5];
324 ((op_t *) dstp)[5] = a1;
325 do5:
326 a1 = ((op_t *) srcp)[4];
327 ((op_t *) dstp)[4] = a0;
328 do4:
329 a0 = ((op_t *) srcp)[3];
330 ((op_t *) dstp)[3] = a1;
331 do3:
332 a1 = ((op_t *) srcp)[2];
333 ((op_t *) dstp)[2] = a0;
334 do2:
335 a0 = ((op_t *) srcp)[1];
336 ((op_t *) dstp)[1] = a1;
337 do1:
338 a1 = ((op_t *) srcp)[0];
339 ((op_t *) dstp)[0] = a0;
340
341 srcp -= 8 * OPSIZ;
342 dstp -= 8 * OPSIZ;
343 len -= 8;
344 }
345 while (len != 0);
346
347 /* This is the right position for do0. Please don't move
348 it into the loop. */
349 do0:
350 ((op_t *) dstp)[7] = a1;
351}
352
353/* _wordcopy_bwd_dest_aligned -- Copy block finishing right
354 before SRCP to block finishing right before DSTP with LEN `op_t'
355 words (not LEN bytes!). DSTP should be aligned for memory
356 operations on `op_t', but SRCP must *not* be aligned. */
357
358#ifndef WORDCOPY_BWD_DEST_ALIGNED
359# define WORDCOPY_BWD_DEST_ALIGNED _wordcopy_bwd_dest_aligned
360#endif
361
362void
363WORDCOPY_BWD_DEST_ALIGNED (long int dstp, long int srcp, size_t len)
364{
365 op_t a0, a1, a2, a3;
366 int sh_1, sh_2;
367
368 /* Calculate how to shift a word read at the memory operation
369 aligned srcp to make it aligned for copy. */
370
371 sh_1 = 8 * (srcp % OPSIZ);
372 sh_2 = 8 * OPSIZ - sh_1;
373
374 /* Make srcp aligned by rounding it down to the beginning of the op_t
375 it points in the middle of. */
376 srcp &= -OPSIZ;
377 srcp += OPSIZ;
378
379 switch (len % 4)
380 {
381 case 2:
382 srcp -= 3 * OPSIZ;
383 dstp -= 1 * OPSIZ;
384 a2 = ((op_t *) srcp)[2];
385 a1 = ((op_t *) srcp)[1];
386 len += 2;
387 goto do1;
388 case 3:
389 srcp -= 4 * OPSIZ;
390 dstp -= 2 * OPSIZ;
391 a3 = ((op_t *) srcp)[3];
392 a2 = ((op_t *) srcp)[2];
393 len += 1;
394 goto do2;
395 case 0:
396 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
397 return;
398 srcp -= 5 * OPSIZ;
399 dstp -= 3 * OPSIZ;
400 a0 = ((op_t *) srcp)[4];
401 a3 = ((op_t *) srcp)[3];
402 goto do3;
403 case 1:
404 srcp -= 6 * OPSIZ;
405 dstp -= 4 * OPSIZ;
406 a1 = ((op_t *) srcp)[5];
407 a0 = ((op_t *) srcp)[4];
408 len -= 1;
409 if (OP_T_THRES <= 3 * OPSIZ && len == 0)
410 goto do0;
411 goto do4; /* No-op. */
412 }
413
414 do
415 {
416 do4:
417 a3 = ((op_t *) srcp)[3];
418 ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2);
419 do3:
420 a2 = ((op_t *) srcp)[2];
421 ((op_t *) dstp)[2] = MERGE (a3, sh_1, a0, sh_2);
422 do2:
423 a1 = ((op_t *) srcp)[1];
424 ((op_t *) dstp)[1] = MERGE (a2, sh_1, a3, sh_2);
425 do1:
426 a0 = ((op_t *) srcp)[0];
427 ((op_t *) dstp)[0] = MERGE (a1, sh_1, a2, sh_2);
428
429 srcp -= 4 * OPSIZ;
430 dstp -= 4 * OPSIZ;
431 len -= 4;
432 }
433 while (len != 0);
434
435 /* This is the right position for do0. Please don't move
436 it into the loop. */
437 do0:
438 ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2);
439}
440

source code of glibc/string/wordcopy.c