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