44dabf6e0053e84eade4d71db46a6a064abe18ba
[platform/upstream/glibc.git] / sysdeps / generic / wordcopy.c
1 /* _memcopy.c -- subroutines for memory copy functions.
2    Copyright (C) 1991 Free Software Foundation, Inc.
3    Contributed by Torbjorn Granlund (tege@sics.se).
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 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 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 /* BE VERY CAREFUL IF YOU CHANGE THIS CODE...!  */
21
22 #include <ansidecl.h>
23 #include <stddef.h>
24 #include <memcopy.h>
25
26 /* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to
27    block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
28    Both SRCP and DSTP should be aligned for memory operations on `op_t's.  */
29
30 void
31 DEFUN(_wordcopy_fwd_aligned, (dstp, srcp, len),
32       long int dstp AND long int srcp AND size_t len)
33 {
34   op_t a0, a1;
35
36   switch (len % 8)
37     {
38     case 2:
39       a0 = ((op_t *) srcp)[0];
40       srcp -= 6 * OPSIZ;
41       dstp -= 7 * OPSIZ;
42       len += 6;
43       goto do1;
44     case 3:
45       a1 = ((op_t *) srcp)[0];
46       srcp -= 5 * OPSIZ;
47       dstp -= 6 * OPSIZ;
48       len += 5;
49       goto do2;
50     case 4:
51       a0 = ((op_t *) srcp)[0];
52       srcp -= 4 * OPSIZ;
53       dstp -= 5 * OPSIZ;
54       len += 4;
55       goto do3;
56     case 5:
57       a1 = ((op_t *) srcp)[0];
58       srcp -= 3 * OPSIZ;
59       dstp -= 4 * OPSIZ;
60       len += 3;
61       goto do4;
62     case 6:
63       a0 = ((op_t *) srcp)[0];
64       srcp -= 2 * OPSIZ;
65       dstp -= 3 * OPSIZ;
66       len += 2;
67       goto do5;
68     case 7:
69       a1 = ((op_t *) srcp)[0];
70       srcp -= 1 * OPSIZ;
71       dstp -= 2 * OPSIZ;
72       len += 1;
73       goto do6;
74       
75     case 0:
76       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
77         return;
78       a0 = ((op_t *) srcp)[0];
79       srcp -= 0 * OPSIZ;
80       dstp -= 1 * OPSIZ;
81       goto do7;
82     case 1:
83       a1 = ((op_t *) srcp)[0];
84       srcp -=-1 * OPSIZ;
85       dstp -= 0 * OPSIZ;
86       len -= 1;
87       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
88         goto do0;
89       goto do8;                 /* No-op.  */
90     }
91
92   do
93     {
94     do8:
95       a0 = ((op_t *) srcp)[0];
96       ((op_t *) dstp)[0] = a1;
97     do7:
98       a1 = ((op_t *) srcp)[1];
99       ((op_t *) dstp)[1] = a0;
100     do6:
101       a0 = ((op_t *) srcp)[2];
102       ((op_t *) dstp)[2] = a1;
103     do5:
104       a1 = ((op_t *) srcp)[3];
105       ((op_t *) dstp)[3] = a0;
106     do4:
107       a0 = ((op_t *) srcp)[4];
108       ((op_t *) dstp)[4] = a1;
109     do3:
110       a1 = ((op_t *) srcp)[5];
111       ((op_t *) dstp)[5] = a0;
112     do2:
113       a0 = ((op_t *) srcp)[6];
114       ((op_t *) dstp)[6] = a1;
115     do1:
116       a1 = ((op_t *) srcp)[7];
117       ((op_t *) dstp)[7] = a0;
118
119       srcp += 8 * OPSIZ;
120       dstp += 8 * OPSIZ;
121       len -= 8;
122     }
123   while (len != 0);
124
125   /* This is the right position for do0.  Please don't move
126      it into the loop.  */
127  do0:
128   ((op_t *) dstp)[0] = a1;
129 }
130
131 /* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to
132    block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
133    DSTP should be aligned for memory operations on `op_t's, but SRCP must
134    *not* be aligned.  */
135
136 void
137 DEFUN(_wordcopy_fwd_dest_aligned, (dstp, srcp, len),
138       long int dstp AND long int srcp AND size_t len)
139 {
140   op_t a0, a1, a2, a3;
141   int sh_1, sh_2;
142
143   /* Calculate how to shift a word read at the memory operation
144      aligned srcp to make it aligned for copy.  */
145
146   sh_1 = 8 * (srcp % OPSIZ);
147   sh_2 = 8 * OPSIZ - sh_1;
148
149   /* Make SRCP aligned by rounding it down to the beginning of the `op_t'
150      it points in the middle of.  */
151   srcp &= -OPSIZ;
152
153   switch (len % 4)
154     {
155     case 2:
156       a1 = ((op_t *) srcp)[0];
157       a2 = ((op_t *) srcp)[1];
158       srcp -= 1 * OPSIZ;
159       dstp -= 3 * OPSIZ;
160       len += 2;
161       goto do1;
162     case 3:
163       a0 = ((op_t *) srcp)[0];
164       a1 = ((op_t *) srcp)[1];
165       srcp -= 0 * OPSIZ;
166       dstp -= 2 * OPSIZ;
167       len += 1;
168       goto do2;
169     case 0:
170       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
171         return;
172       a3 = ((op_t *) srcp)[0];
173       a0 = ((op_t *) srcp)[1];
174       srcp -=-1 * OPSIZ;
175       dstp -= 1 * OPSIZ;
176       len += 0;
177       goto do3;
178     case 1:
179       a2 = ((op_t *) srcp)[0];
180       a3 = ((op_t *) srcp)[1];
181       srcp -=-2 * OPSIZ;
182       dstp -= 0 * OPSIZ;
183       len -= 1;
184       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
185         goto do0;
186       goto do4;                 /* No-op.  */
187     }
188
189   do
190     {
191     do4:
192       a0 = ((op_t *) srcp)[0];
193       ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
194     do3:
195       a1 = ((op_t *) srcp)[1];
196       ((op_t *) dstp)[1] = MERGE (a3, sh_1, a0, sh_2);
197     do2:
198       a2 = ((op_t *) srcp)[2];
199       ((op_t *) dstp)[2] = MERGE (a0, sh_1, a1, sh_2);
200     do1:
201       a3 = ((op_t *) srcp)[3];
202       ((op_t *) dstp)[3] = MERGE (a1, sh_1, a2, sh_2);
203
204       srcp += 4 * OPSIZ;
205       dstp += 4 * OPSIZ;
206       len -= 4;
207     }
208   while (len != 0);
209
210   /* This is the right position for do0.  Please don't move
211      it into the loop.  */
212  do0:
213   ((op_t *) dstp)[0] = MERGE (a2, sh_1, a3, sh_2);
214 }
215
216 /* _wordcopy_bwd_aligned -- Copy block finishing right before
217    SRCP to block finishing right before DSTP with LEN `op_t' words
218    (not LEN bytes!).  Both SRCP and DSTP should be aligned for memory
219    operations on `op_t's.  */
220
221 void
222 DEFUN(_wordcopy_bwd_aligned, (dstp, srcp, len),
223       long int dstp AND long int srcp AND size_t len)
224 {
225   op_t a0, a1;
226
227   switch (len % 8)
228     {
229     case 2:
230       srcp -= 2 * OPSIZ;
231       dstp -= 1 * OPSIZ;
232       a0 = ((op_t *) srcp)[1];
233       len += 6;
234       goto do1;
235     case 3:
236       srcp -= 3 * OPSIZ;
237       dstp -= 2 * OPSIZ;
238       a1 = ((op_t *) srcp)[2];
239       len += 5;
240       goto do2;
241     case 4:
242       srcp -= 4 * OPSIZ;
243       dstp -= 3 * OPSIZ;
244       a0 = ((op_t *) srcp)[3];
245       len += 4;
246       goto do3;
247     case 5:
248       srcp -= 5 * OPSIZ;
249       dstp -= 4 * OPSIZ;
250       a1 = ((op_t *) srcp)[4];
251       len += 3;
252       goto do4;
253     case 6:
254       srcp -= 6 * OPSIZ;
255       dstp -= 5 * OPSIZ;
256       a0 = ((op_t *) srcp)[5];
257       len += 2;
258       goto do5;
259     case 7:
260       srcp -= 7 * OPSIZ;
261       dstp -= 6 * OPSIZ;
262       a1 = ((op_t *) srcp)[6];
263       len += 1;
264       goto do6;
265       
266     case 0:
267       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
268         return;
269       srcp -= 8 * OPSIZ;
270       dstp -= 7 * OPSIZ;
271       a0 = ((op_t *) srcp)[7];
272       goto do7;
273     case 1:
274       srcp -= 9 * OPSIZ;
275       dstp -= 8 * OPSIZ;
276       a1 = ((op_t *) srcp)[8];
277       len -= 1;
278       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
279         goto do0;
280       goto do8;                 /* No-op.  */
281     }
282
283   do
284     {
285     do8:
286       a0 = ((op_t *) srcp)[7];
287       ((op_t *) dstp)[7] = a1;
288     do7:
289       a1 = ((op_t *) srcp)[6];
290       ((op_t *) dstp)[6] = a0;
291     do6:
292       a0 = ((op_t *) srcp)[5];
293       ((op_t *) dstp)[5] = a1;
294     do5:
295       a1 = ((op_t *) srcp)[4];
296       ((op_t *) dstp)[4] = a0;
297     do4:
298       a0 = ((op_t *) srcp)[3];
299       ((op_t *) dstp)[3] = a1;
300     do3:
301       a1 = ((op_t *) srcp)[2];
302       ((op_t *) dstp)[2] = a0;
303     do2:
304       a0 = ((op_t *) srcp)[1];
305       ((op_t *) dstp)[1] = a1;
306     do1:
307       a1 = ((op_t *) srcp)[0];
308       ((op_t *) dstp)[0] = a0;
309
310       srcp -= 8 * OPSIZ;
311       dstp -= 8 * OPSIZ;
312       len -= 8;
313     }
314   while (len != 0);
315
316   /* This is the right position for do0.  Please don't move
317      it into the loop.  */
318  do0:
319   ((op_t *) dstp)[7] = a1;
320 }
321
322 /* _wordcopy_bwd_dest_aligned -- Copy block finishing right
323    before SRCP to block finishing right before DSTP with LEN `op_t'
324    words (not LEN bytes!).  DSTP should be aligned for memory
325    operations on `op_t', but SRCP must *not* be aligned.  */
326
327 void
328 DEFUN(_wordcopy_bwd_dest_aligned, (dstp, srcp, len),
329       long int dstp AND long int srcp AND size_t len)
330 {
331   op_t a0, a1, a2, a3;
332   int sh_1, sh_2;
333
334   /* Calculate how to shift a word read at the memory operation
335      aligned srcp to make it aligned for copy.  */
336
337   sh_1 = 8 * (srcp % OPSIZ);
338   sh_2 = 8 * OPSIZ - sh_1;
339
340   /* Make srcp aligned by rounding it down to the beginning of the op_t
341      it points in the middle of.  */
342   srcp &= -OPSIZ;
343   srcp += OPSIZ;
344
345   switch (len % 4)
346     {
347     case 2:
348       srcp -= 3 * OPSIZ;
349       dstp -= 1 * OPSIZ;
350       a2 = ((op_t *) srcp)[2];
351       a1 = ((op_t *) srcp)[1];
352       len += 2;
353       goto do1;
354     case 3:
355       srcp -= 4 * OPSIZ;
356       dstp -= 2 * OPSIZ;
357       a3 = ((op_t *) srcp)[3];
358       a2 = ((op_t *) srcp)[2];
359       len += 1;
360       goto do2;
361     case 0:
362       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
363         return;
364       srcp -= 5 * OPSIZ;
365       dstp -= 3 * OPSIZ;
366       a0 = ((op_t *) srcp)[4];
367       a3 = ((op_t *) srcp)[3];
368       goto do3;
369     case 1:
370       srcp -= 6 * OPSIZ;
371       dstp -= 4 * OPSIZ;
372       a1 = ((op_t *) srcp)[5];
373       a0 = ((op_t *) srcp)[4];
374       len -= 1;
375       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
376         goto do0;
377       goto do4;                 /* No-op.  */
378     }
379
380   do
381     {
382     do4:
383       a3 = ((op_t *) srcp)[3];
384       ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2);
385     do3:
386       a2 = ((op_t *) srcp)[2];
387       ((op_t *) dstp)[2] = MERGE (a3, sh_1, a0, sh_2);
388     do2:
389       a1 = ((op_t *) srcp)[1];
390       ((op_t *) dstp)[1] = MERGE (a2, sh_1, a3, sh_2);
391     do1:
392       a0 = ((op_t *) srcp)[0];
393       ((op_t *) dstp)[0] = MERGE (a1, sh_1, a2, sh_2);
394
395       srcp -= 4 * OPSIZ;
396       dstp -= 4 * OPSIZ;
397       len -= 4;
398     }
399   while (len != 0);
400
401   /* This is the right position for do0.  Please don't move
402      it into the loop.  */
403  do0:
404   ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2);
405 }