Import 2.3.9pre5
[davej-history.git] / arch / mips / lib / memcpy.S
blob065fc69ee582d3a83110d440cd031b7d0a26f7aa
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * $Id: memcpy.S,v 1.3 1998/07/10 01:14:49 ralf Exp $
7  *
8  * Unified implementation of memcpy, memmove and the __copy_user backend.
9  * For __rmemcpy and memmove an exception is always a kernel bug, therefore
10  * they're not protected.  In order to keep the exception fixup routine
11  * simple all memory accesses in __copy_user to src rsp. dst are stricly
12  * incremental.  The fixup routine depends on $at not being changed.
13  */
14 #include <asm/asm.h>
15 #include <asm/offset.h>
16 #include <asm/regdef.h>
19  * The fixup routine for copy_to_user depends on copying strictly in
20  * increasing order.  Gas expands the ulw/usw macros in the wrong order for
21  * little endian machines, so we cannot depend on them.
22  */
23 #ifdef __MIPSEB__
24 #define uswL    swl
25 #define uswU    swr
26 #define ulwL    lwl
27 #define ulwU    lwr
28 #endif
29 #ifdef __MIPSEL__
30 #define uswL    swr
31 #define uswU    swl
32 #define ulwL    lwr
33 #define ulwU    lwl
34 #endif
36 #define EX(insn,reg,addr,handler)                       \
37 9:      insn    reg, addr;                              \
38         .section __ex_table,"a";                        \
39         PTR     9b, handler;                            \
40         .previous
42 #define UEX(insn,reg,addr,handler)                      \
43 9:      insn ## L reg, addr;                            \
44 10:     insn ## U reg, 3 + addr;                        \
45         .section __ex_table,"a";                        \
46         PTR     9b, handler;                            \
47         PTR     10b, handler;                           \
48         .previous
50 /* ascending order, destination aligned  */
51 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
52         EX(lw, t0, (offset + 0x00)(src), l_fixup); \
53         EX(lw, t1, (offset + 0x04)(src), l_fixup); \
54         EX(lw, t2, (offset + 0x08)(src), l_fixup); \
55         EX(lw, t3, (offset + 0x0c)(src), l_fixup); \
56         EX(sw, t0, (offset + 0x00)(dst), s_fixup); \
57         EX(sw, t1, (offset + 0x04)(dst), s_fixup); \
58         EX(sw, t2, (offset + 0x08)(dst), s_fixup); \
59         EX(sw, t3, (offset + 0x0c)(dst), s_fixup); \
60         EX(lw, t0, (offset + 0x10)(src), l_fixup); \
61         EX(lw, t1, (offset + 0x14)(src), l_fixup); \
62         EX(lw, t2, (offset + 0x18)(src), l_fixup); \
63         EX(lw, t3, (offset + 0x1c)(src), l_fixup); \
64         EX(sw, t0, (offset + 0x10)(dst), s_fixup); \
65         EX(sw, t1, (offset + 0x14)(dst), s_fixup); \
66         EX(sw, t2, (offset + 0x18)(dst), s_fixup); \
67         EX(sw, t3, (offset + 0x1c)(dst), s_fixup)
69 /* ascending order, destination unaligned  */
70 #define UMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
71         EX(lw, t0, (offset + 0x00)(src), l_fixup); \
72         EX(lw, t1, (offset + 0x04)(src), l_fixup); \
73         EX(lw, t2, (offset + 0x08)(src), l_fixup); \
74         EX(lw, t3, (offset + 0x0c)(src), l_fixup); \
75         UEX(usw, t0, (offset + 0x00)(dst), s_fixup); \
76         UEX(usw, t1, (offset + 0x04)(dst), s_fixup); \
77         UEX(usw, t2, (offset + 0x08)(dst), s_fixup); \
78         UEX(usw, t3, (offset + 0x0c)(dst), s_fixup); \
79         EX(lw, t0, (offset + 0x10)(src), l_fixup); \
80         EX(lw, t1, (offset + 0x14)(src), l_fixup); \
81         EX(lw, t2, (offset + 0x18)(src), l_fixup); \
82         EX(lw, t3, (offset + 0x1c)(src), l_fixup); \
83         UEX(usw, t0, (offset + 0x10)(dst), s_fixup); \
84         UEX(usw, t1, (offset + 0x14)(dst), s_fixup); \
85         UEX(usw, t2, (offset + 0x18)(dst), s_fixup); \
86         UEX(usw, t3, (offset + 0x1c)(dst), s_fixup)
88         .text
89         .set    noreorder
90         .set    noat
92         .align  5
93 LEAF(memcpy)                                    /* a0=dst a1=src a2=len */
94         move    v0, a0                          /* return value */
95 __memcpy:
96 EXPORT(__copy_user)
97         xor     t0, a0, a1
98         andi    t0, t0, 0x3
99         move    t7, a0
100         beqz    t0, can_align
101          sltiu  t8, a2, 0x8
103         b       memcpy_u_src                    # bad alignment
104          move   t2, a2
106 can_align:
107         bnez    t8, small_memcpy                # < 8 bytes to copy
108          move   t2, a2
110         beqz    a2, out
111          andi   t8, a1, 0x1
113 hword_align:
114         beqz    t8, word_align
115          andi   t8, a1, 0x2
117         EX(lb, t0, (a1), l_fixup)
118         subu    a2, a2, 0x1
119         EX(sb, t0, (a0), s_fixup)
120         addu    a1, a1, 0x1
121         addu    a0, a0, 0x1
122         andi    t8, a1, 0x2
124 word_align:
125         beqz    t8, dword_align
126          sltiu  t8, a2, 56
127         
128         EX(lh, t0, (a1), l_fixup)
129         subu    a2, a2, 0x2
130         EX(sh, t0, (a0), s_fixup)
131         sltiu   t8, a2, 56
132         addu    a0, a0, 0x2
133         addu    a1, a1, 0x2
135 dword_align:
136         bnez    t8, do_end_words
137          move   t8, a2
139         andi    t8, a1, 0x4
140         beqz    t8, qword_align
141          andi   t8, a1, 0x8
143         EX(lw, t0, 0x00(a1), l_fixup)
144         subu    a2, a2, 0x4
145         EX(sw, t0, 0x00(a0), s_fixup)
146         addu    a1, a1, 0x4
147         addu    a0, a0, 0x4
148         andi    t8, a1, 0x8
150 qword_align:
151         beqz    t8, oword_align
152          andi   t8, a1, 0x10
154         EX(lw, t0, 0x00(a1), l_fixup)
155         EX(lw, t1, 0x04(a1), l_fixup)
156         subu    a2, a2, 0x8
157         EX(sw, t0, 0x00(a0), s_fixup)
158         EX(sw, t1, 0x04(a0), s_fixup)
159         addu    a1, a1, 0x8
160         andi    t8, a1, 0x10
161         addu    a0, a0, 0x8
163 oword_align:
164         beqz    t8, begin_movement
165          srl    t8, a2, 0x7
167         EX(lw, t3, 0x00(a1), l_fixup)
168         EX(lw, t4, 0x04(a1), l_fixup)
169         EX(lw, t0, 0x08(a1), l_fixup)
170         EX(lw, t1, 0x0c(a1), l_fixup)
171         EX(sw, t3, 0x00(a0), s_fixup)
172         EX(sw, t4, 0x04(a0), s_fixup)
173         EX(sw, t0, 0x08(a0), s_fixup)
174         EX(sw, t1, 0x0c(a0), s_fixup)
175         subu    a2, a2, 0x10
176         addu    a1, a1, 0x10
177         srl     t8, a2, 0x7
178         addu    a0, a0, 0x10
180 begin_movement:
181         beqz    t8, 0f
182          andi   t2, a2, 0x40
184 move_128bytes:
185         MOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
186         MOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4)
187         MOVE_BIGCHUNK(a1, a0, 0x40, t0, t1, t3, t4)
188         MOVE_BIGCHUNK(a1, a0, 0x60, t0, t1, t3, t4)
189         subu    t8, t8, 0x01
190         addu    a1, a1, 0x80
191         bnez    t8, move_128bytes
192          addu   a0, a0, 0x80
195         beqz    t2, 1f
196          andi   t2, a2, 0x20
198 move_64bytes:
199         MOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
200         MOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4)
201         addu    a1, a1, 0x40
202         addu    a0, a0, 0x40
205         beqz    t2, do_end_words
206          andi   t8, a2, 0x1c
208 move_32bytes:
209         MOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
210         andi    t8, a2, 0x1c
211         addu    a1, a1, 0x20
212         addu    a0, a0, 0x20
214 do_end_words:
215         beqz    t8, maybe_end_cruft
216          srl    t8, t8, 0x2
218 end_words:
219         EX(lw, t0, (a1), l_fixup)
220         subu    t8, t8, 0x1
221         EX(sw, t0, (a0), s_fixup)
222         addu    a1, a1, 0x4
223         bnez    t8, end_words
224          addu   a0, a0, 0x4
226 maybe_end_cruft:
227         andi    t2, a2, 0x3
229 small_memcpy:
230         beqz    t2, out
231          move   a2, t2
233 end_bytes:
234         EX(lb, t0, (a1), l_fixup)
235         subu    a2, a2, 0x1
236         EX(sb, t0, (a0), s_fixup)
237         addu    a1, a1, 0x1
238         bnez    a2, end_bytes
239          addu   a0, a0, 0x1
241 out:    jr      ra
242          move   a2, zero
244 /* ------------------------------------------------------------------------- */
246 /* Bad, bad.  At least try to align the source  */
248 memcpy_u_src:
249         bnez    t8, small_memcpy                # < 8 bytes?
250          move   t2, a2
252         addiu   t0, a1, 7                       # t0: how much to align
253         ori     t0, 7
254         xori    t0, 7
255         subu    t0, a1
257         UEX(ulw, t1, 0(a1), l_fixup)            # dword alignment
258         UEX(ulw, t2, 4(a1), l_fixup)
259         UEX(usw, t1, 0(a0), s_fixup)
260         UEX(usw, t2, 4(a0), s_fixup)
262         addu    a1, t0                          # src
263         addu    a0, t0                          # dst
264         subu    a2, t0                          # len
266         sltiu   t8, a2, 56
267         bnez    t8, u_do_end_words
268          andi   t8, a2, 0x3c
270         andi    t8, a1, 8                       # now qword aligned?
272 u_qword_align:
273         beqz    t8, u_oword_align
274          andi   t8, a1, 0x10
276         EX(lw, t0, 0x00(a1), l_fixup)
277         EX(lw, t1, 0x04(a1), l_fixup)
278         subu    a2, a2, 0x8
279         UEX(usw, t0, 0x00(a0), s_fixup)
280         UEX(usw, t1, 0x04(a0), s_fixup)
281         addu    a1, a1, 0x8
282         andi    t8, a1, 0x10
283         addu    a0, a0, 0x8
285 u_oword_align:
286         beqz    t8, u_begin_movement
287          srl    t8, a2, 0x7
289         EX(lw, t3, 0x08(a1), l_fixup)
290         EX(lw, t4, 0x0c(a1), l_fixup)
291         EX(lw, t0, 0x00(a1), l_fixup)
292         EX(lw, t1, 0x04(a1), l_fixup)
293         UEX(usw, t3, 0x08(a0), s_fixup)
294         UEX(usw, t4, 0x0c(a0), s_fixup)
295         UEX(usw, t0, 0x00(a0), s_fixup)
296         UEX(usw, t1, 0x04(a0), s_fixup)
297         subu    a2, a2, 0x10
298         addu    a1, a1, 0x10
299         srl     t8, a2, 0x7
300         addu    a0, a0, 0x10
302 u_begin_movement:
303         beqz    t8, 0f
304          andi   t2, a2, 0x40
306 u_move_128bytes:
307         UMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
308         UMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4)
309         UMOVE_BIGCHUNK(a1, a0, 0x40, t0, t1, t3, t4)
310         UMOVE_BIGCHUNK(a1, a0, 0x60, t0, t1, t3, t4)
311         subu    t8, t8, 0x01
312         addu    a1, a1, 0x80
313         bnez    t8, u_move_128bytes
314          addu   a0, a0, 0x80
317         beqz    t2, 1f
318          andi   t2, a2, 0x20
320 u_move_64bytes:
321         UMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
322         UMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4)
323         addu    a1, a1, 0x40
324         addu    a0, a0, 0x40
327         beqz    t2, u_do_end_words
328          andi   t8, a2, 0x1c
330 u_move_32bytes:
331         UMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
332         andi    t8, a2, 0x1c
333         addu    a1, a1, 0x20
334         addu    a0, a0, 0x20
336 u_do_end_words:
337         beqz    t8, u_maybe_end_cruft
338          srl    t8, t8, 0x2
340 u_end_words:
341         EX(lw, t0, 0x00(a1), l_fixup)
342         subu    t8, t8, 0x1
343         UEX(usw, t0, 0x00(a0), s_fixup)
344         addu    a1, a1, 0x4
345         bnez    t8, u_end_words
346          addu   a0, a0, 0x4
348 u_maybe_end_cruft:
349         andi    t2, a2, 0x3
351 u_cannot_optimize:
352         beqz    t2, out
353          move   a2, t2
355 u_end_bytes:
356         EX(lb, t0, (a1), l_fixup)
357         subu    a2, a2, 0x1
358         EX(sb, t0, (a0), s_fixup)
359         addu    a1, a1, 0x1
360         bnez    a2, u_end_bytes
361          addu   a0, a0, 0x1
363         jr      ra
364          move   a2, zero
365         END(memcpy)
367 /* descending order, destination aligned  */
368 #define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
369         lw      t0, (offset + 0x10)(src); \
370         lw      t1, (offset + 0x14)(src); \
371         lw      t2, (offset + 0x18)(src); \
372         lw      t3, (offset + 0x1c)(src); \
373         sw      t0, (offset + 0x10)(dst); \
374         sw      t1, (offset + 0x14)(dst); \
375         sw      t2, (offset + 0x18)(dst); \
376         sw      t3, (offset + 0x1c)(dst); \
377         lw      t0, (offset + 0x00)(src); \
378         lw      t1, (offset + 0x04)(src); \
379         lw      t2, (offset + 0x08)(src); \
380         lw      t3, (offset + 0x0c)(src); \
381         sw      t0, (offset + 0x00)(dst); \
382         sw      t1, (offset + 0x04)(dst); \
383         sw      t2, (offset + 0x08)(dst); \
384         sw      t3, (offset + 0x0c)(dst)
386 /* descending order, destination ununaligned  */
387 #define RUMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3) \
388         lw      t0, (offset + 0x10)(src); \
389         lw      t1, (offset + 0x14)(src); \
390         lw      t2, (offset + 0x18)(src); \
391         lw      t3, (offset + 0x1c)(src); \
392         usw     t0, (offset + 0x10)(dst); \
393         usw     t1, (offset + 0x14)(dst); \
394         usw     t2, (offset + 0x18)(dst); \
395         usw     t3, (offset + 0x1c)(dst); \
396         lw      t0, (offset + 0x00)(src); \
397         lw      t1, (offset + 0x04)(src); \
398         lw      t2, (offset + 0x08)(src); \
399         lw      t3, (offset + 0x0c)(src); \
400         usw     t0, (offset + 0x00)(dst); \
401         usw     t1, (offset + 0x04)(dst); \
402         usw     t2, (offset + 0x08)(dst); \
403         usw     t3, (offset + 0x0c)(dst)
405         .align  5
406 LEAF(memmove)
407         sltu    t0, a0, a1                      # dst < src -> memcpy
408         bnez    t0, memcpy
409          addu   v0, a0, a2
410         sltu    t0, v0, a1                      # dst + len < src -> non-
411         bnez    t0, __memcpy                    # overlapping, can use memcpy
412          move   v0, a0                          /* return value */
413         END(memmove)
415 LEAF(__rmemcpy)                                 /* a0=dst a1=src a2=len */
416         addu    a0, a2                          # dst = dst + len
417         addu    a1, a2                          # src = src + len
419 #if 0 /* Horror fix */
420         xor     t0, a0, a1
421         andi    t0, t0, 0x3
422         move    t7, a0
423         beqz    t0, r_can_align
424          sltiu  t8, a2, 0x8
426         b       r_memcpy_u_src                  # bad alignment
427          move   t2, a2
429 r_can_align:
430         bnez    t8, r_small_memcpy              # < 8 bytes to copy
431          move   t2, a2
433         beqz    a2, r_out
434          andi   t8, a1, 0x1
436 r_hword_align:
437         beqz    t8, r_word_align
438          andi   t8, a1, 0x2
440         lb      t0, -1(a1)
441         subu    a2, a2, 0x1
442         sb      t0, -1(a0)
443         subu    a1, a1, 0x1
444         subu    a0, a0, 0x1
445         andi    t8, a1, 0x2
447 r_word_align:
448         beqz    t8, r_dword_align
449          sltiu  t8, a2, 56
450         
451         lh      t0, -2(a1)
452         subu    a2, a2, 0x2
453         sh      t0, -2(a0)
454         sltiu   t8, a2, 56
455         subu    a0, a0, 0x2
456         subu    a1, a1, 0x2
458 r_dword_align:
459         bnez    t8, r_do_end_words
460          move   t8, a2
462         andi    t8, a1, 0x4
463         beqz    t8, r_qword_align
464          andi   t8, a1, 0x8
466         lw      t0, -4(a1)
467         subu    a2, a2, 0x4
468         sw      t0, -4(a0)
469         subu    a1, a1, 0x4
470         subu    a0, a0, 0x4
471         andi    t8, a1, 0x8
473 r_qword_align:
474         beqz    t8, r_oword_align
475          andi   t8, a1, 0x10
477         subu    a1, a1, 0x8
478         lw      t0, 0x04(a1)
479         lw      t1, 0x00(a1)
480         subu    a0, a0, 0x8
481         sw      t0, 0x04(a0)
482         sw      t1, 0x00(a0)
483         subu    a2, a2, 0x8
485         andi    t8, a1, 0x10
487 r_oword_align:
488         beqz    t8, r_begin_movement
489          srl    t8, a2, 0x7
491         subu    a1, a1, 0x10
492         lw      t3, 0x08(a1)                    # assumes subblock ordering
493         lw      t4, 0x0c(a1)
494         lw      t0, 0x00(a1)
495         lw      t1, 0x04(a1)
496         subu    a0, a0, 0x10
497         sw      t3, 0x08(a0)
498         sw      t4, 0x0c(a0)
499         sw      t0, 0x00(a0)
500         sw      t1, 0x04(a0)
501         subu    a2, a2, 0x10
502         srl     t8, a2, 0x7
504 r_begin_movement:
505         beqz    t8, 0f
506          andi   t2, a2, 0x40
508 r_move_128bytes:
509         RMOVE_BIGCHUNK(a1, a0, -0x80, t0, t1, t3, t4)
510         RMOVE_BIGCHUNK(a1, a0, -0x60, t0, t1, t3, t4)
511         RMOVE_BIGCHUNK(a1, a0, -0x40, t0, t1, t3, t4)
512         RMOVE_BIGCHUNK(a1, a0, -0x20, t0, t1, t3, t4)
513         subu    t8, t8, 0x01
514         subu    a1, a1, 0x80
515         bnez    t8, r_move_128bytes
516          subu   a0, a0, 0x80
519         beqz    t2, 1f
520          andi   t2, a2, 0x20
522 r_move_64bytes:
523         subu    a1, a1, 0x40
524         subu    a0, a0, 0x40
525         RMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4)
526         RMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
529         beqz    t2, r_do_end_words
530          andi   t8, a2, 0x1c
532 r_move_32bytes:
533         subu    a1, a1, 0x20
534         subu    a0, a0, 0x20
535         RMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
536         andi    t8, a2, 0x1c
538 r_do_end_words:
539         beqz    t8, r_maybe_end_cruft
540          srl    t8, t8, 0x2
542 r_end_words:
543         lw      t0, -4(a1)
544         subu    t8, t8, 0x1
545         sw      t0, -4(a0)
546         subu    a1, a1, 0x4
547         bnez    t8, r_end_words
548          subu   a0, a0, 0x4
550 r_maybe_end_cruft:
551         andi    t2, a2, 0x3
553 r_small_memcpy:
554         beqz    t2, r_out
555          move   a2, t2
556 #endif /* Horror fix */
558 r_end_bytes:
559         lb      t0, -1(a1)
560         subu    a2, a2, 0x1
561         sb      t0, -1(a0)
562         subu    a1, a1, 0x1
563         bnez    a2, r_end_bytes
564          subu   a0, a0, 0x1
566 r_out:
567         jr      ra
568          move   a2, zero
570 #if 0 /* Horror fix */
571 /* ------------------------------------------------------------------------- */
573 /* Bad, bad.  At least try to align the source  */
575 r_memcpy_u_src:
576         bnez    t8, r_small_memcpy              # < 8 bytes?
577          move   t2, a2
579         andi    t0, a1, 7                       # t0: how much to align
581         ulw     t1, -8(a1)                      # dword alignment
582         ulw     t2, -4(a1)
583         usw     t1, -8(a0)
584         usw     t2, -4(a0)
586         subu    a1, t0                          # src
587         subu    a0, t0                          # dst
588         subu    a2, t0                          # len
590         sltiu   t8, a2, 56
591         bnez    t8, ru_do_end_words
592          andi   t8, a2, 0x3c
594         andi    t8, a1, 8                       # now qword aligned?
596 ru_qword_align:
597         beqz    t8, ru_oword_align
598          andi   t8, a1, 0x10
600         subu    a1, a1, 0x8
601         lw      t0, 0x00(a1)
602         lw      t1, 0x04(a1)
603         subu    a0, a0, 0x8
604         usw     t0, 0x00(a0)
605         usw     t1, 0x04(a0)
606         subu    a2, a2, 0x8
608         andi    t8, a1, 0x10
610 ru_oword_align:
611         beqz    t8, ru_begin_movement
612          srl    t8, a2, 0x7
614         subu    a1, a1, 0x10
615         lw      t3, 0x08(a1)                    # assumes subblock ordering
616         lw      t4, 0x0c(a1)
617         lw      t0, 0x00(a1)
618         lw      t1, 0x04(a1)
619         subu    a0, a0, 0x10
620         usw     t3, 0x08(a0)
621         usw     t4, 0x0c(a0)
622         usw     t0, 0x00(a0)
623         usw     t1, 0x04(a0)
624         subu    a2, a2, 0x10
626         srl     t8, a2, 0x7
628 ru_begin_movement:
629         beqz    t8, 0f
630          andi   t2, a2, 0x40
632 ru_move_128bytes:
633         RUMOVE_BIGCHUNK(a1, a0, -0x80, t0, t1, t3, t4)
634         RUMOVE_BIGCHUNK(a1, a0, -0x60, t0, t1, t3, t4)
635         RUMOVE_BIGCHUNK(a1, a0, -0x40, t0, t1, t3, t4)
636         RUMOVE_BIGCHUNK(a1, a0, -0x20, t0, t1, t3, t4)
637         subu    t8, t8, 0x01
638         subu    a1, a1, 0x80
639         bnez    t8, ru_move_128bytes
640          subu   a0, a0, 0x80
643         beqz    t2, 1f
644          andi   t2, a2, 0x20
646 ru_move_64bytes:
647         subu    a1, a1, 0x40
648         subu    a0, a0, 0x40
649         RUMOVE_BIGCHUNK(a1, a0, 0x20, t0, t1, t3, t4)
650         RUMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
653         beqz    t2, ru_do_end_words
654          andi   t8, a2, 0x1c
656 ru_move_32bytes:
657         subu    a1, a1, 0x20
658         subu    a0, a0, 0x20
659         RUMOVE_BIGCHUNK(a1, a0, 0x00, t0, t1, t3, t4)
660         andi    t8, a2, 0x1c
662 ru_do_end_words:
663         beqz    t8, ru_maybe_end_cruft
664          srl    t8, t8, 0x2
666 ru_end_words:
667         lw      t0, -4(a1)
668         usw     t0, -4(a0)
669         subu    t8, t8, 0x1
670         subu    a1, a1, 0x4
671         bnez    t8, ru_end_words
672          subu   a0, a0, 0x4
674 ru_maybe_end_cruft:
675         andi    t2, a2, 0x3
677 ru_cannot_optimize:
678         beqz    t2, r_out
679          move   a2, t2
681 ru_end_bytes:
682         lb      t0, -1(a1)
683         subu    a2, a2, 0x1
684         sb      t0, -1(a0)
685         subu    a1, a1, 0x1
686         bnez    a2, ru_end_bytes
687          subu   a0, a0, 0x1
689         jr      ra
690          move   a2, zero
691         END(__rmemcpy)
692 #endif /* Horror fix */
694 l_fixup:                                        # clear the rest of the buffer
695         lw      t0, THREAD_BUADDR($28)
696          nop
697         subu    a2, AT, t0                      # a2 bytes to go
698         addu    a0, t0                          # compute start address in a1
699         subu    a0, a1
700         j       __bzero
701          move   a1, zero
703 s_fixup:
704         jr      ra
705          nop