OSDN Git Service

Replace FSF snail mail address with URLs
[uclinux-h8/uClibc.git] / libc / string / generic / memmove.c
1 /* Copy memory to memory until the specified number of bytes
2    has been copied.  Overlap is handled correctly.
3    Copyright (C) 1991, 1995, 1996, 1997, 2003 Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Contributed by Torbjorn Granlund (tege@sics.se).
6
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20
21 #include <string.h>
22
23 #include "memcopy.h"
24 #include "pagecopy.h"
25
26 #ifdef __ARCH_HAS_BWD_MEMCPY__
27 /* generic-opt memmove assumes memcpy does forward copying! */
28 #include "_memcpy_fwd.c"
29 #endif
30
31
32 static void _wordcopy_bwd_aligned (long int dstp, long int srcp, size_t len)
33 {
34   op_t a0 = 0;
35   op_t a1 = 0;
36
37   switch (len % 8)
38     {
39     case 2:
40       srcp -= 2 * OPSIZ;
41       dstp -= 1 * OPSIZ;
42       a0 = ((op_t *) srcp)[1];
43       len += 6;
44       goto do1;
45     case 3:
46       srcp -= 3 * OPSIZ;
47       dstp -= 2 * OPSIZ;
48       a1 = ((op_t *) srcp)[2];
49       len += 5;
50       goto do2;
51     case 4:
52       srcp -= 4 * OPSIZ;
53       dstp -= 3 * OPSIZ;
54       a0 = ((op_t *) srcp)[3];
55       len += 4;
56       goto do3;
57     case 5:
58       srcp -= 5 * OPSIZ;
59       dstp -= 4 * OPSIZ;
60       a1 = ((op_t *) srcp)[4];
61       len += 3;
62       goto do4;
63     case 6:
64       srcp -= 6 * OPSIZ;
65       dstp -= 5 * OPSIZ;
66       a0 = ((op_t *) srcp)[5];
67       len += 2;
68       goto do5;
69     case 7:
70       srcp -= 7 * OPSIZ;
71       dstp -= 6 * OPSIZ;
72       a1 = ((op_t *) srcp)[6];
73       len += 1;
74       goto do6;
75
76     case 0:
77       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
78         return;
79       srcp -= 8 * OPSIZ;
80       dstp -= 7 * OPSIZ;
81       a0 = ((op_t *) srcp)[7];
82       goto do7;
83     case 1:
84       srcp -= 9 * OPSIZ;
85       dstp -= 8 * OPSIZ;
86       a1 = ((op_t *) srcp)[8];
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)[7];
97       ((op_t *) dstp)[7] = a1;
98     do7:
99       a1 = ((op_t *) srcp)[6];
100       ((op_t *) dstp)[6] = a0;
101     do6:
102       a0 = ((op_t *) srcp)[5];
103       ((op_t *) dstp)[5] = a1;
104     do5:
105       a1 = ((op_t *) srcp)[4];
106       ((op_t *) dstp)[4] = a0;
107     do4:
108       a0 = ((op_t *) srcp)[3];
109       ((op_t *) dstp)[3] = a1;
110     do3:
111       a1 = ((op_t *) srcp)[2];
112       ((op_t *) dstp)[2] = a0;
113     do2:
114       a0 = ((op_t *) srcp)[1];
115       ((op_t *) dstp)[1] = a1;
116     do1:
117       a1 = ((op_t *) srcp)[0];
118       ((op_t *) dstp)[0] = 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)[7] = a1;
130 }
131
132 /* _wordcopy_bwd_dest_aligned -- Copy block finishing right
133    before SRCP to block finishing right before DSTP with LEN `op_t'
134    words (not LEN bytes!).  DSTP should be aligned for memory
135    operations on `op_t', but SRCP must *not* be aligned.  */
136
137 static void _wordcopy_bwd_dest_aligned (long int dstp, long int srcp, size_t len)
138 {
139   op_t a0 = 0;
140   op_t a1 = 0;
141   op_t a2 = 0;
142   op_t a3 = 0;
143   int sh_1, sh_2;
144
145   /* Calculate how to shift a word read at the memory operation
146      aligned srcp to make it aligned for copy.  */
147
148   sh_1 = 8 * (srcp % OPSIZ);
149   sh_2 = 8 * OPSIZ - sh_1;
150
151   /* Make srcp aligned by rounding it down to the beginning of the op_t
152      it points in the middle of.  */
153   srcp &= -OPSIZ;
154   srcp += OPSIZ;
155
156   switch (len % 4)
157     {
158     case 2:
159       srcp -= 3 * OPSIZ;
160       dstp -= 1 * OPSIZ;
161       a2 = ((op_t *) srcp)[2];
162       a1 = ((op_t *) srcp)[1];
163       len += 2;
164       goto do1;
165     case 3:
166       srcp -= 4 * OPSIZ;
167       dstp -= 2 * OPSIZ;
168       a3 = ((op_t *) srcp)[3];
169       a2 = ((op_t *) srcp)[2];
170       len += 1;
171       goto do2;
172     case 0:
173       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
174         return;
175       srcp -= 5 * OPSIZ;
176       dstp -= 3 * OPSIZ;
177       a0 = ((op_t *) srcp)[4];
178       a3 = ((op_t *) srcp)[3];
179       goto do3;
180     case 1:
181       srcp -= 6 * OPSIZ;
182       dstp -= 4 * OPSIZ;
183       a1 = ((op_t *) srcp)[5];
184       a0 = ((op_t *) srcp)[4];
185       len -= 1;
186       if (OP_T_THRES <= 3 * OPSIZ && len == 0)
187         goto do0;
188       goto do4;                 /* No-op.  */
189     }
190
191   do
192     {
193     do4:
194       a3 = ((op_t *) srcp)[3];
195       ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2);
196     do3:
197       a2 = ((op_t *) srcp)[2];
198       ((op_t *) dstp)[2] = MERGE (a3, sh_1, a0, sh_2);
199     do2:
200       a1 = ((op_t *) srcp)[1];
201       ((op_t *) dstp)[1] = MERGE (a2, sh_1, a3, sh_2);
202     do1:
203       a0 = ((op_t *) srcp)[0];
204       ((op_t *) dstp)[0] = MERGE (a1, sh_1, a2, sh_2);
205
206       srcp -= 4 * OPSIZ;
207       dstp -= 4 * OPSIZ;
208       len -= 4;
209     }
210   while (len != 0);
211
212   /* This is the right position for do0.  Please don't move
213      it into the loop.  */
214  do0:
215   ((op_t *) dstp)[3] = MERGE (a0, sh_1, a1, sh_2);
216 }
217
218 void *memmove (void *dest, const void *src, size_t len)
219 {
220   unsigned long int dstp = (long int) dest;
221   unsigned long int srcp = (long int) src;
222
223   /* This test makes the forward copying code be used whenever possible.
224      Reduces the working set.  */
225   if (dstp - srcp >= len)       /* *Unsigned* compare!  */
226     {
227 #ifndef __ARCH_HAS_BWD_MEMCPY__
228       /* Backward memcpy implementation cannot be used */
229       memcpy(dest, src, len);
230 #else
231       /* Copy from the beginning to the end.  */
232
233       /* If there not too few bytes to copy, use word copy.  */
234       if (len >= OP_T_THRES)
235         {
236           /* Copy just a few bytes to make DSTP aligned.  */
237           len -= (-dstp) % OPSIZ;
238           BYTE_COPY_FWD (dstp, srcp, (-dstp) % OPSIZ);
239
240           /* Copy whole pages from SRCP to DSTP by virtual address
241              manipulation, as much as possible.  */
242
243           PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len);
244
245           /* Copy from SRCP to DSTP taking advantage of the known
246              alignment of DSTP.  Number of bytes remaining is put
247              in the third argument, i.e. in LEN.  This number may
248              vary from machine to machine.  */
249
250           WORD_COPY_FWD (dstp, srcp, len, len);
251
252           /* Fall out and copy the tail.  */
253         }
254
255       /* There are just a few bytes to copy.  Use byte memory operations.  */
256       BYTE_COPY_FWD (dstp, srcp, len);
257 #endif
258     }
259   else
260     {
261       /* Copy from the end to the beginning.  */
262       srcp += len;
263       dstp += len;
264
265       /* If there not too few bytes to copy, use word copy.  */
266       if (len >= OP_T_THRES)
267         {
268           /* Copy just a few bytes to make DSTP aligned.  */
269           len -= dstp % OPSIZ;
270           BYTE_COPY_BWD (dstp, srcp, dstp % OPSIZ);
271
272           /* Copy from SRCP to DSTP taking advantage of the known
273              alignment of DSTP.  Number of bytes remaining is put
274              in the third argument, i.e. in LEN.  This number may
275              vary from machine to machine.  */
276
277           WORD_COPY_BWD (dstp, srcp, len, len);
278
279           /* Fall out and copy the tail.  */
280         }
281
282       /* There are just a few bytes to copy.  Use byte memory operations.  */
283       BYTE_COPY_BWD (dstp, srcp, len);
284     }
285
286   return (dest);
287 }
288 libc_hidden_weak(memmove)