sparc32: Remove uses of %g7 in memcpy implementation.
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / sparc / lib / memcpy.S
blob90a598846babc55f5e898805901b489c10889e6b
1 /* memcpy.S: Sparc optimized memcpy and memmove code
2  * Hand optimized from GNU libc's memcpy and memmove
3  * Copyright (C) 1991,1996 Free Software Foundation
4  * Copyright (C) 1995 Linus Torvalds (Linus.Torvalds@helsinki.fi)
5  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
6  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
7  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
8  */
10 #define FUNC(x)                 \
11         .globl  x;              \
12         .type   x,@function;    \
13         .align  4;              \
17 /* In kernel these functions don't return a value.
18  * One should use macros in asm/string.h for that purpose.
19  * We return 0, so that bugs are more apparent.
20  */
21 #define SETUP_RETL
22 #define RETL_INSN       clr     %o0
24 /* Both these macros have to start with exactly the same insn */
25 #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
26         ldd     [%src + (offset) + 0x00], %t0; \
27         ldd     [%src + (offset) + 0x08], %t2; \
28         ldd     [%src + (offset) + 0x10], %t4; \
29         ldd     [%src + (offset) + 0x18], %t6; \
30         st      %t0, [%dst + (offset) + 0x00]; \
31         st      %t1, [%dst + (offset) + 0x04]; \
32         st      %t2, [%dst + (offset) + 0x08]; \
33         st      %t3, [%dst + (offset) + 0x0c]; \
34         st      %t4, [%dst + (offset) + 0x10]; \
35         st      %t5, [%dst + (offset) + 0x14]; \
36         st      %t6, [%dst + (offset) + 0x18]; \
37         st      %t7, [%dst + (offset) + 0x1c];
39 #define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
40         ldd     [%src + (offset) + 0x00], %t0; \
41         ldd     [%src + (offset) + 0x08], %t2; \
42         ldd     [%src + (offset) + 0x10], %t4; \
43         ldd     [%src + (offset) + 0x18], %t6; \
44         std     %t0, [%dst + (offset) + 0x00]; \
45         std     %t2, [%dst + (offset) + 0x08]; \
46         std     %t4, [%dst + (offset) + 0x10]; \
47         std     %t6, [%dst + (offset) + 0x18];
49 #define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
50         ldd     [%src - (offset) - 0x10], %t0; \
51         ldd     [%src - (offset) - 0x08], %t2; \
52         st      %t0, [%dst - (offset) - 0x10]; \
53         st      %t1, [%dst - (offset) - 0x0c]; \
54         st      %t2, [%dst - (offset) - 0x08]; \
55         st      %t3, [%dst - (offset) - 0x04];
57 #define MOVE_LASTALIGNCHUNK(src, dst, offset, t0, t1, t2, t3) \
58         ldd     [%src - (offset) - 0x10], %t0; \
59         ldd     [%src - (offset) - 0x08], %t2; \
60         std     %t0, [%dst - (offset) - 0x10]; \
61         std     %t2, [%dst - (offset) - 0x08];
63 #define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
64         ldub    [%src - (offset) - 0x02], %t0; \
65         ldub    [%src - (offset) - 0x01], %t1; \
66         stb     %t0, [%dst - (offset) - 0x02]; \
67         stb     %t1, [%dst - (offset) - 0x01];
69 /* Both these macros have to start with exactly the same insn */
70 #define RMOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
71         ldd     [%src - (offset) - 0x20], %t0; \
72         ldd     [%src - (offset) - 0x18], %t2; \
73         ldd     [%src - (offset) - 0x10], %t4; \
74         ldd     [%src - (offset) - 0x08], %t6; \
75         st      %t0, [%dst - (offset) - 0x20]; \
76         st      %t1, [%dst - (offset) - 0x1c]; \
77         st      %t2, [%dst - (offset) - 0x18]; \
78         st      %t3, [%dst - (offset) - 0x14]; \
79         st      %t4, [%dst - (offset) - 0x10]; \
80         st      %t5, [%dst - (offset) - 0x0c]; \
81         st      %t6, [%dst - (offset) - 0x08]; \
82         st      %t7, [%dst - (offset) - 0x04];
84 #define RMOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
85         ldd     [%src - (offset) - 0x20], %t0; \
86         ldd     [%src - (offset) - 0x18], %t2; \
87         ldd     [%src - (offset) - 0x10], %t4; \
88         ldd     [%src - (offset) - 0x08], %t6; \
89         std     %t0, [%dst - (offset) - 0x20]; \
90         std     %t2, [%dst - (offset) - 0x18]; \
91         std     %t4, [%dst - (offset) - 0x10]; \
92         std     %t6, [%dst - (offset) - 0x08];
94 #define RMOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
95         ldd     [%src + (offset) + 0x00], %t0; \
96         ldd     [%src + (offset) + 0x08], %t2; \
97         st      %t0, [%dst + (offset) + 0x00]; \
98         st      %t1, [%dst + (offset) + 0x04]; \
99         st      %t2, [%dst + (offset) + 0x08]; \
100         st      %t3, [%dst + (offset) + 0x0c];
102 #define RMOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
103         ldub    [%src + (offset) + 0x00], %t0; \
104         ldub    [%src + (offset) + 0x01], %t1; \
105         stb     %t0, [%dst + (offset) + 0x00]; \
106         stb     %t1, [%dst + (offset) + 0x01];
108 #define SMOVE_CHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) \
109         ldd     [%src + (offset) + 0x00], %t0; \
110         ldd     [%src + (offset) + 0x08], %t2; \
111         srl     %t0, shir, %t5; \
112         srl     %t1, shir, %t6; \
113         sll     %t0, shil, %t0; \
114         or      %t5, %prev, %t5; \
115         sll     %t1, shil, %prev; \
116         or      %t6, %t0, %t0; \
117         srl     %t2, shir, %t1; \
118         srl     %t3, shir, %t6; \
119         sll     %t2, shil, %t2; \
120         or      %t1, %prev, %t1; \
121         std     %t4, [%dst + (offset) + (offset2) - 0x04]; \
122         std     %t0, [%dst + (offset) + (offset2) + 0x04]; \
123         sll     %t3, shil, %prev; \
124         or      %t6, %t2, %t4;
126 #define SMOVE_ALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, prev, shil, shir, offset2) \
127         ldd     [%src + (offset) + 0x00], %t0; \
128         ldd     [%src + (offset) + 0x08], %t2; \
129         srl     %t0, shir, %t4; \
130         srl     %t1, shir, %t5; \
131         sll     %t0, shil, %t6; \
132         or      %t4, %prev, %t0; \
133         sll     %t1, shil, %prev; \
134         or      %t5, %t6, %t1; \
135         srl     %t2, shir, %t4; \
136         srl     %t3, shir, %t5; \
137         sll     %t2, shil, %t6; \
138         or      %t4, %prev, %t2; \
139         sll     %t3, shil, %prev; \
140         or      %t5, %t6, %t3; \
141         std     %t0, [%dst + (offset) + (offset2) + 0x00]; \
142         std     %t2, [%dst + (offset) + (offset2) + 0x08];
144         .text
145         .align  4
148         retl
149          nop            ! Only bcopy returns here and it retuns void...
151 #ifdef __KERNEL__
152 FUNC(amemmove)
153 FUNC(__memmove)
154 #endif
155 FUNC(memmove)
156         cmp             %o0, %o1
157         SETUP_RETL
158         bleu            9f
159          sub            %o0, %o1, %o4
161         add             %o1, %o2, %o3
162         cmp             %o3, %o0
163         bleu            0f
164          andcc          %o4, 3, %o5
166         add             %o1, %o2, %o1
167         add             %o0, %o2, %o0
168         sub             %o1, 1, %o1
169         sub             %o0, 1, %o0
170         
171 1:      /* reverse_bytes */
173         ldub            [%o1], %o4
174         subcc           %o2, 1, %o2
175         stb             %o4, [%o0]
176         sub             %o1, 1, %o1
177         bne             1b
178          sub            %o0, 1, %o0
180         retl
181          RETL_INSN
183 /* NOTE: This code is executed just for the cases,
184          where %src (=%o1) & 3 is != 0.
185          We need to align it to 4. So, for (%src & 3)
186          1 we need to do ldub,lduh
187          2 lduh
188          3 just ldub
189          so even if it looks weird, the branches
190          are correct here. -jj
191  */
192 78:     /* dword_align */
194         andcc           %o1, 1, %g0
195         be              4f
196          andcc          %o1, 2, %g0
198         ldub            [%o1], %g2
199         add             %o1, 1, %o1
200         stb             %g2, [%o0]
201         sub             %o2, 1, %o2
202         bne             3f
203          add            %o0, 1, %o0
205         lduh            [%o1], %g2
206         add             %o1, 2, %o1
207         sth             %g2, [%o0]
208         sub             %o2, 2, %o2
209         b               3f
210          add            %o0, 2, %o0
212 FUNC(memcpy)    /* %o0=dst %o1=src %o2=len */
214         sub             %o0, %o1, %o4
215         SETUP_RETL
217         andcc           %o4, 3, %o5
219         bne             86f
220          cmp            %o2, 15
222         bleu            90f
223          andcc          %o1, 3, %g0
225         bne             78b
227          andcc          %o1, 4, %g0
229         be              2f
230          mov            %o2, %g1
232         ld              [%o1], %o4
233         sub             %g1, 4, %g1
234         st              %o4, [%o0]
235         add             %o1, 4, %o1
236         add             %o0, 4, %o0
238         andcc           %g1, 0xffffff80, %g0
239         be              3f
240          andcc          %o0, 4, %g0
242         be              82f + 4
244         MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
245         MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
246         MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
247         MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
248         sub             %g1, 128, %g1
249         add             %o1, 128, %o1
250         cmp             %g1, 128
251         bge             5b
252          add            %o0, 128, %o0
254         andcc           %g1, 0x70, %g4
255         be              80f
256          andcc          %g1, 8, %g0
258         sethi           %hi(80f), %o5
259         srl             %g4, 1, %o4
260         add             %g4, %o4, %o4
261         add             %o1, %g4, %o1
262         sub             %o5, %o4, %o5
263         jmpl            %o5 + %lo(80f), %g0
264          add            %o0, %g4, %o0
266 79:     /* memcpy_table */
268         MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
269         MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
270         MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
271         MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
272         MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
273         MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
274         MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
276 80:     /* memcpy_table_end */
277         be              81f
278          andcc          %g1, 4, %g0
280         ldd             [%o1], %g2
281         add             %o0, 8, %o0
282         st              %g2, [%o0 - 0x08]
283         add             %o1, 8, %o1
284         st              %g3, [%o0 - 0x04]
286 81:     /* memcpy_last7 */
288         be              1f
289          andcc          %g1, 2, %g0
291         ld              [%o1], %g2
292         add             %o1, 4, %o1
293         st              %g2, [%o0]
294         add             %o0, 4, %o0
296         be              1f
297          andcc          %g1, 1, %g0
299         lduh            [%o1], %g2
300         add             %o1, 2, %o1
301         sth             %g2, [%o0]
302         add             %o0, 2, %o0
304         be              1f
305          nop
307         ldub            [%o1], %g2
308         stb             %g2, [%o0]
310         retl
311          RETL_INSN
313 82:     /* ldd_std */
314         MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
315         MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
316         MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
317         MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
318         subcc           %g1, 128, %g1
319         add             %o1, 128, %o1
320         cmp             %g1, 128
321         bge             82b
322          add            %o0, 128, %o0
324         andcc           %g1, 0x70, %g4
325         be              84f
326          andcc          %g1, 8, %g0
328         sethi           %hi(84f), %o5
329         add             %o1, %g4, %o1
330         sub             %o5, %g4, %o5
331         jmpl            %o5 + %lo(84f), %g0
332          add            %o0, %g4, %o0
334 83:     /* amemcpy_table */
336         MOVE_LASTALIGNCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
337         MOVE_LASTALIGNCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
338         MOVE_LASTALIGNCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
339         MOVE_LASTALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
340         MOVE_LASTALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
341         MOVE_LASTALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
342         MOVE_LASTALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
344 84:     /* amemcpy_table_end */
345         be              85f
346          andcc          %g1, 4, %g0
348         ldd             [%o1], %g2
349         add             %o0, 8, %o0
350         std             %g2, [%o0 - 0x08]
351         add             %o1, 8, %o1
352 85:     /* amemcpy_last7 */
353         be              1f
354          andcc          %g1, 2, %g0
356         ld              [%o1], %g2
357         add             %o1, 4, %o1
358         st              %g2, [%o0]
359         add             %o0, 4, %o0
361         be              1f
362          andcc          %g1, 1, %g0
364         lduh            [%o1], %g2
365         add             %o1, 2, %o1
366         sth             %g2, [%o0]
367         add             %o0, 2, %o0
369         be              1f
370          nop
372         ldub            [%o1], %g2
373         stb             %g2, [%o0]
375         retl
376          RETL_INSN
378 86:     /* non_aligned */
379         cmp             %o2, 6
380         bleu            88f
381          nop
383         save            %sp, -96, %sp
384         andcc           %i0, 3, %g0
385         be              61f
386          andcc          %i0, 1, %g0
387         be              60f
388          andcc          %i0, 2, %g0
390         ldub            [%i1], %g5
391         add             %i1, 1, %i1
392         stb             %g5, [%i0]
393         sub             %i2, 1, %i2
394         bne             61f
395          add            %i0, 1, %i0
397         ldub            [%i1], %g3
398         add             %i1, 2, %i1
399         stb             %g3, [%i0]
400         sub             %i2, 2, %i2
401         ldub            [%i1 - 1], %g3
402         add             %i0, 2, %i0
403         stb             %g3, [%i0 - 1]
405         and             %i1, 3, %g2
406         and             %i2, 0xc, %g3
407         and             %i1, -4, %i1
408         cmp             %g3, 4
409         sll             %g2, 3, %g4
410         mov             32, %g2
411         be              4f
412          sub            %g2, %g4, %l0
413         
414         blu             3f
415          cmp            %g3, 0x8
417         be              2f
418          srl            %i2, 2, %g3
420         ld              [%i1], %i3
421         add             %i0, -8, %i0
422         ld              [%i1 + 4], %i4
423         b               8f
424          add            %g3, 1, %g3
426         ld              [%i1], %i4
427         add             %i0, -12, %i0
428         ld              [%i1 + 4], %i5
429         add             %g3, 2, %g3
430         b               9f
431          add            %i1, -4, %i1
433         ld              [%i1], %g1
434         add             %i0, -4, %i0
435         ld              [%i1 + 4], %i3
436         srl             %i2, 2, %g3
437         b               7f
438          add            %i1, 4, %i1
440         ld              [%i1], %i5
441         cmp             %i2, 7
442         ld              [%i1 + 4], %g1
443         srl             %i2, 2, %g3
444         bleu            10f
445          add            %i1, 8, %i1
447         ld              [%i1], %i3
448         add             %g3, -1, %g3
450         sll             %i5, %g4, %g2
451         srl             %g1, %l0, %g5
452         or              %g2, %g5, %g2
453         st              %g2, [%i0]
455         ld              [%i1 + 4], %i4
456         sll             %g1, %g4, %g2
457         srl             %i3, %l0, %g5
458         or              %g2, %g5, %g2
459         st              %g2, [%i0 + 4]
461         ld              [%i1 + 8], %i5
462         sll             %i3, %g4, %g2
463         srl             %i4, %l0, %g5
464         or              %g2, %g5, %g2
465         st              %g2, [%i0 + 8]
467         ld              [%i1 + 12], %g1
468         sll             %i4, %g4, %g2
469         srl             %i5, %l0, %g5
470         addcc           %g3, -4, %g3
471         or              %g2, %g5, %g2
472         add             %i1, 16, %i1
473         st              %g2, [%i0 + 12]
474         add             %i0, 16, %i0
475         bne,a           5b
476          ld             [%i1], %i3
478         sll             %i5, %g4, %g2
479         srl             %g1, %l0, %g5
480         srl             %l0, 3, %g3
481         or              %g2, %g5, %g2
482         sub             %i1, %g3, %i1
483         andcc           %i2, 2, %g0
484         st              %g2, [%i0]
485         be              1f
486          andcc          %i2, 1, %g0
488         ldub            [%i1], %g2
489         add             %i1, 2, %i1
490         stb             %g2, [%i0 + 4]
491         add             %i0, 2, %i0
492         ldub            [%i1 - 1], %g2
493         stb             %g2, [%i0 + 3]
495         be              1f
496          nop
497         ldub            [%i1], %g2
498         stb             %g2, [%i0 + 4]
500         ret
501          restore        %g0, %g0, %o0
503 88:     /* short_end */
505         and             %o2, 0xe, %o3
507         sethi           %hi(89f), %o5
508         sll             %o3, 3, %o4
509         add             %o0, %o3, %o0
510         sub             %o5, %o4, %o5
511         add             %o1, %o3, %o1
512         jmpl            %o5 + %lo(89f), %g0
513          andcc          %o2, 1, %g0
515         MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
516         MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
517         MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
518         MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
519         MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
520         MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
521         MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
523 89:     /* short_table_end */
525         be              1f
526          nop
528         ldub            [%o1], %g2
529         stb             %g2, [%o0]
531         retl
532          RETL_INSN
534 90:     /* short_aligned_end */
535         bne             88b
536          andcc          %o2, 8, %g0
538         be              1f
539          andcc          %o2, 4, %g0
541         ld              [%o1 + 0x00], %g2
542         ld              [%o1 + 0x04], %g3
543         add             %o1, 8, %o1
544         st              %g2, [%o0 + 0x00]
545         st              %g3, [%o0 + 0x04]
546         add             %o0, 8, %o0
548         b               81b
549          mov            %o2, %g1