powerpc: PPCA2/A2 optimized memcpy function
[glibc.git] / sysdeps / powerpc / powerpc64 / a2 / memcpy.S
blobac95171aa8fefe090975144f5ced541cb9498214
1 /* Optimized memcpy implementation for PowerPC A2.
2    Copyright (C) 2010 Free Software Foundation, Inc.
3    Contributed by Michael Brutman <brutman@us.ibm.com>.
4    This file is part of the GNU C Library.
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
21 #include <sysdep.h>
22 #include <bp-sym.h>
23 #include <bp-asm.h>
25 #define PREFETCH_AHEAD 4        /* no cache lines SRC prefetching ahead  */
26 #define ZERO_AHEAD 2            /* no cache lines DST zeroing ahead  */
28         .section        ".toc","aw"
29 .LC0:
30         .tc __cache_line_size[TC],__cache_line_size
31         .section        ".text"
32         .align 2
35         .machine  a2
36 EALIGN (BP_SYM (memcpy), 5, 0)
37         CALL_MCOUNT 3
39         dcbt    0,r4            /* Prefetch ONE SRC cacheline  */
40         cmpldi  cr1,r5,16       /* is size < 16 ?  */
41         mr      r6,r3           /* Copy dest reg to r6; */
42         blt+    cr1,L(shortcopy)
45         /* Big copy (16 bytes or more)
47            Figure out how far to the nearest quadword boundary, or if we are
48            on one already.  Also get the cache line size.
50            r3 - return value (always)
51            r4 - current source addr
52            r5 - copy length
53            r6 - current dest addr
54         */
56         neg     r8,r3           /* LS 4 bits = # bytes to 8-byte dest bdry  */
57         ld      r9,.LC0@toc(r2) /* Get cache line size (part 1) */
58         clrldi  r8,r8,64-4      /* align to 16byte boundary  */
59         sub     r7,r4,r3        /* compute offset to src from dest */
60         lwz     r9,0(r9)        /* Get cache line size (part 2) */
61         cmpldi  cr0,r8,0        /* Were we aligned on a 16 byte bdy? */
62         addi    r10,r9,-1       /* Cache line mask */
63         beq+    L(dst_aligned)
67         /* Destination is not aligned on quadword boundary.  Get us to one.
69            r3 - return value (always)
70            r4 - current source addr
71            r5 - copy length
72            r6 - current dest addr
73            r7 - offset to src from dest
74            r8 - number of bytes to quadword boundary
75         */
77         mtcrf   0x01,r8         /* put #bytes to boundary into cr7  */
78         subf    r5,r8,r5        /* adjust remaining len */
80         bf      cr7*4+3,1f
81         lbzx    r0,r7,r6        /* copy 1 byte addr */
82         stb     r0,0(r6)
83         addi    r6,r6,1
85         bf      cr7*4+2,2f
86         lhzx    r0,r7,r6        /* copy 2 byte addr */
87         sth     r0,0(r6)
88         addi    r6,r6,2
90         bf      cr7*4+1,4f
91         lwzx    r0,r7,r6        /* copy 4 byte addr */
92         stw     r0,0(r6)
93         addi    r6,r6,4
95         bf      cr7*4+0,8f
96         ldx     r0,r7,r6        /* copy 8 byte addr */
97         std     r0,0(r6)
98         addi    r6,r6,8
100         add     r4,r7,r6        /* update src addr */
104         /* Dest is quadword aligned now.
106            Lots of decisions to make.  If we are copying less than a cache
107            line we won't be here long.  If we are not on a cache line
108            boundary we need to get there.  And then we need to figure out
109            how many cache lines ahead to pre-touch.
111            r3 - return value (always)
112            r4 - current source addr
113            r5 - copy length
114            r6 - current dest addr
115         */
118         .align 4
119 L(dst_aligned):
122         cmpd   cr5,r5,r10       /* Less than a cacheline to go? */
124         neg     r7,r6           /* How far to next cacheline bdy? */
126         addi    r6,r6,-8        /* prepare for stdu  */
127         cmpdi   cr0,r9,128
128         addi    r4,r4,-8        /* prepare for ldu  */
131         ble+    cr5,L(lessthancacheline)
133         beq-    cr0,L(big_lines) /* 128 byte line code */
137         /* More than a cacheline left to go, and using 64 byte cachelines */
139         clrldi  r7,r7,64-6      /* How far to next cacheline bdy? */
141         cmpldi  cr6,r7,0        /* Are we on a cacheline bdy already? */
143         /* Reduce total len by what it takes to get to the next cache line */
144         subf    r5,r7,r5
145         srdi    r7,r7,4         /* How many qws to get to the line bdy? */
147         /* How many full cache lines to copy after getting to a line bdy? */
148         srdi    r10,r5,6
150         cmpldi  r10,0           /* If no full cache lines to copy ... */
151         li      r11,0           /* number cachelines to copy with prefetch  */
152         beq     L(nocacheprefetch)
155         /* We are here because we have at least one full cache line to copy,
156            and therefore some pre-touching to do. */
158         cmpldi  r10,PREFETCH_AHEAD
159         li      r12,64+8        /* prefetch distance  */
160         ble     L(lessthanmaxprefetch)
162         /* We can only do so much pre-fetching.  R11 will have the count of
163            lines left to prefetch after the initial batch of prefetches
164            are executed. */
166         subi    r11,r10,PREFETCH_AHEAD
167         li      r10,PREFETCH_AHEAD
169 L(lessthanmaxprefetch):
170         mtctr   r10
172         /* At this point r10/ctr hold the number of lines to prefetch in this
173            initial batch, and r11 holds any remainder. */
175 L(prefetchSRC):
176         dcbt    r12,r4
177         addi    r12,r12,64
178         bdnz    L(prefetchSRC)
181         /* Prefetching is done, or was not needed.
183            cr6 - are we on a cacheline boundary already?
184            r7  - number of quadwords to the next cacheline boundary
185         */
187 L(nocacheprefetch):
188         mtctr   r7
190         cmpldi  cr1,r5,64   /* Less than a cache line to copy? */
192         /* How many bytes are left after we copy whatever full
193            cache lines we can get? */
194         clrldi  r5,r5,64-6
196         beq     cr6,L(cachelinealigned)
199         /* Copy quadwords up to the next cacheline boundary */
201 L(aligntocacheline):
202         ld      r9,0x08(r4)
203         ld      r7,0x10(r4)
204         addi    r4,r4,0x10
205         std     r9,0x08(r6)
206         stdu    r7,0x10(r6)
207         bdnz    L(aligntocacheline)
210         .align 4
211 L(cachelinealigned):            /* copy while cache lines  */
213         blt-    cr1,L(lessthancacheline) /* size <64  */
215 L(outerloop):
216         cmpdi   r11,0
217         mtctr   r11
218         beq-    L(endloop)
220         li      r11,64*ZERO_AHEAD +8    /* DCBZ dist  */
222         .align  4
223         /* Copy whole cachelines, optimized by prefetching SRC cacheline  */
224 L(loop):                        /* Copy aligned body  */
225         dcbt    r12,r4          /* PREFETCH SOURCE some cache lines ahead  */
226         ld      r9, 0x08(r4)
227         dcbz    r11,r6
228         ld      r7, 0x10(r4)
229         ld      r8, 0x18(r4)
230         ld      r0, 0x20(r4)
231         std     r9, 0x08(r6)
232         std     r7, 0x10(r6)
233         std     r8, 0x18(r6)
234         std     r0, 0x20(r6)
235         ld      r9, 0x28(r4)
236         ld      r7, 0x30(r4)
237         ld      r8, 0x38(r4)
238         ld      r0, 0x40(r4)
239         addi    r4, r4,0x40
240         std     r9, 0x28(r6)
241         std     r7, 0x30(r6)
242         std     r8, 0x38(r6)
243         stdu    r0, 0x40(r6)
245         bdnz    L(loop)
248 L(endloop):
249         cmpdi   r10,0
250         beq-    L(endloop2)
251         mtctr   r10
253 L(loop2):                       /* Copy aligned body  */
254         ld      r9, 0x08(r4)
255         ld      r7, 0x10(r4)
256         ld      r8, 0x18(r4)
257         ld      r0, 0x20(r4)
258         std     r9, 0x08(r6)
259         std     r7, 0x10(r6)
260         std     r8, 0x18(r6)
261         std     r0, 0x20(r6)
262         ld      r9, 0x28(r4)
263         ld      r7, 0x30(r4)
264         ld      r8, 0x38(r4)
265         ld      r0, 0x40(r4)
266         addi    r4, r4,0x40
267         std     r9, 0x28(r6)
268         std     r7, 0x30(r6)
269         std     r8, 0x38(r6)
270         stdu    r0, 0x40(r6)
272         bdnz    L(loop2)
273 L(endloop2):
276         .align 4
277 L(lessthancacheline):           /* Was there less than cache to do ?  */
278         cmpldi  cr0,r5,16
279         srdi    r7,r5,4         /* divide size by 16  */
280         blt-    L(do_lt16)
281         mtctr   r7
283 L(copy_remaining):
284         ld      r8,0x08(r4)
285         ld      r7,0x10(r4)
286         addi    r4,r4,0x10
287         std     r8,0x08(r6)
288         stdu    r7,0x10(r6)
289         bdnz    L(copy_remaining)
291 L(do_lt16):                     /* less than 16 ?  */
292         cmpldi  cr0,r5,0        /* copy remaining bytes (0-15)  */
293         beqlr+                  /* no rest to copy  */
294         addi    r4,r4,8
295         addi    r6,r6,8
297 L(shortcopy):                   /* SIMPLE COPY to handle size =< 15 bytes  */
298         mtcrf   0x01,r5
299         sub     r7,r4,r6
300         bf-     cr7*4+0,8f
301         ldx     r0,r7,r6        /* copy 8 byte  */
302         std     r0,0(r6)
303         addi    r6,r6,8
305         bf      cr7*4+1,4f
306         lwzx    r0,r7,r6        /* copy 4 byte  */
307         stw     r0,0(r6)
308         addi    r6,r6,4
310         bf      cr7*4+2,2f
311         lhzx    r0,r7,r6        /* copy 2 byte  */
312         sth     r0,0(r6)
313         addi    r6,r6,2
315         bf      cr7*4+3,1f
316         lbzx    r0,r7,r6        /* copy 1 byte  */
317         stb     r0,0(r6)
319         blr
325         /* Similar to above, but for use with 128 byte lines. */
328 L(big_lines):
330         clrldi  r7,r7,64-7      /* How far to next cacheline bdy? */
332         cmpldi  cr6,r7,0        /* Are we on a cacheline bdy already? */
334         /* Reduce total len by what it takes to get to the next cache line */
335         subf    r5,r7,r5
336         srdi    r7,r7,4         /* How many qws to get to the line bdy? */
338         /* How many full cache lines to copy after getting to a line bdy? */
339         srdi    r10,r5,7
341         cmpldi  r10,0           /* If no full cache lines to copy ... */
342         li      r11,0           /* number cachelines to copy with prefetch  */
343         beq     L(nocacheprefetch_128)
346         /* We are here because we have at least one full cache line to copy,
347            and therefore some pre-touching to do. */
349         cmpldi  r10,PREFETCH_AHEAD
350         li      r12,128+8       /* prefetch distance  */
351         ble     L(lessthanmaxprefetch_128)
353         /* We can only do so much pre-fetching.  R11 will have the count of
354            lines left to prefetch after the initial batch of prefetches
355            are executed. */
357         subi    r11,r10,PREFETCH_AHEAD
358         li      r10,PREFETCH_AHEAD
360 L(lessthanmaxprefetch_128):
361         mtctr   r10
363         /* At this point r10/ctr hold the number of lines to prefetch in this
364            initial batch, and r11 holds any remainder. */
366 L(prefetchSRC_128):
367         dcbt    r12,r4
368         addi    r12,r12,128
369         bdnz    L(prefetchSRC_128)
372         /* Prefetching is done, or was not needed.
374            cr6 - are we on a cacheline boundary already?
375            r7  - number of quadwords to the next cacheline boundary
376         */
378 L(nocacheprefetch_128):
379         mtctr   r7
381         cmpldi  cr1,r5,128  /* Less than a cache line to copy? */
383         /* How many bytes are left after we copy whatever full
384            cache lines we can get? */
385         clrldi  r5,r5,64-7
387         beq     cr6,L(cachelinealigned_128)
390         /* Copy quadwords up to the next cacheline boundary */
392 L(aligntocacheline_128):
393         ld      r9,0x08(r4)
394         ld      r7,0x10(r4)
395         addi    r4,r4,0x10
396         std     r9,0x08(r6)
397         stdu    r7,0x10(r6)
398         bdnz    L(aligntocacheline_128)
401 L(cachelinealigned_128):        /* copy while cache lines  */
403         blt-    cr1,L(lessthancacheline) /* size <128  */
405 L(outerloop_128):
406         cmpdi   r11,0
407         mtctr   r11
408         beq-    L(endloop_128)
410         li      r11,128*ZERO_AHEAD +8    /* DCBZ dist  */
412         .align  4
413         /* Copy whole cachelines, optimized by prefetching SRC cacheline  */
414 L(loop_128):                    /* Copy aligned body  */
415         dcbt    r12,r4          /* PREFETCH SOURCE some cache lines ahead  */
416         ld      r9, 0x08(r4)
417         dcbz    r11,r6
418         ld      r7, 0x10(r4)
419         ld      r8, 0x18(r4)
420         ld      r0, 0x20(r4)
421         std     r9, 0x08(r6)
422         std     r7, 0x10(r6)
423         std     r8, 0x18(r6)
424         std     r0, 0x20(r6)
425         ld      r9, 0x28(r4)
426         ld      r7, 0x30(r4)
427         ld      r8, 0x38(r4)
428         ld      r0, 0x40(r4)
429         std     r9, 0x28(r6)
430         std     r7, 0x30(r6)
431         std     r8, 0x38(r6)
432         std     r0, 0x40(r6)
433         ld      r9, 0x48(r4)
434         ld      r7, 0x50(r4)
435         ld      r8, 0x58(r4)
436         ld      r0, 0x60(r4)
437         std     r9, 0x48(r6)
438         std     r7, 0x50(r6)
439         std     r8, 0x58(r6)
440         std     r0, 0x60(r6)
441         ld      r9, 0x68(r4)
442         ld      r7, 0x70(r4)
443         ld      r8, 0x78(r4)
444         ld      r0, 0x80(r4)
445         addi    r4, r4,0x80
446         std     r9, 0x68(r6)
447         std     r7, 0x70(r6)
448         std     r8, 0x78(r6)
449         stdu    r0, 0x80(r6)
451         bdnz    L(loop_128)
454 L(endloop_128):
455         cmpdi   r10,0
456         beq-    L(endloop2_128)
457         mtctr   r10
459 L(loop2_128):                       /* Copy aligned body  */
460         ld      r9, 0x08(r4)
461         ld      r7, 0x10(r4)
462         ld      r8, 0x18(r4)
463         ld      r0, 0x20(r4)
464         std     r9, 0x08(r6)
465         std     r7, 0x10(r6)
466         std     r8, 0x18(r6)
467         std     r0, 0x20(r6)
468         ld      r9, 0x28(r4)
469         ld      r7, 0x30(r4)
470         ld      r8, 0x38(r4)
471         ld      r0, 0x40(r4)
472         std     r9, 0x28(r6)
473         std     r7, 0x30(r6)
474         std     r8, 0x38(r6)
475         std     r0, 0x40(r6)
476         ld      r9, 0x48(r4)
477         ld      r7, 0x50(r4)
478         ld      r8, 0x58(r4)
479         ld      r0, 0x60(r4)
480         std     r9, 0x48(r6)
481         std     r7, 0x50(r6)
482         std     r8, 0x58(r6)
483         std     r0, 0x60(r6)
484         ld      r9, 0x68(r4)
485         ld      r7, 0x70(r4)
486         ld      r8, 0x78(r4)
487         ld      r0, 0x80(r4)
488         addi    r4, r4,0x80
489         std     r9, 0x68(r6)
490         std     r7, 0x70(r6)
491         std     r8, 0x78(r6)
492         stdu    r0, 0x80(r6)
494         bdnz    L(loop2_128)
495 L(endloop2_128):
497         b       L(lessthancacheline)
500 END_GEN_TB (BP_SYM (memcpy),TB_TOCLESS)
501 libc_hidden_builtin_def (memcpy)