powerpc: PPCA2/A2 optimized memcpy function
[glibc.git] / sysdeps / powerpc / powerpc32 / a2 / memcpy.S
blob472f7a393b79e3cdba5df765ef577c02944c6781
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         .machine  a2
29 EALIGN (BP_SYM (memcpy), 5, 0)
30         CALL_MCOUNT
32         dcbt    0,r4            /* Prefetch ONE SRC cacheline  */
33         cmplwi  cr1,r5,16       /* is size < 16 ?  */
34         mr      r6,r3           /* Copy dest reg to r6; */
35         blt+    cr1,L(shortcopy)
38         /* Big copy (16 bytes or more)
40            Figure out how far to the nearest quadword boundary, or if we are
41            on one already.
43            r3 - return value (always)
44            r4 - current source addr
45            r5 - copy length
46            r6 - current dest addr
47         */
49         neg     r8,r3           /* LS 4 bits = # bytes to 8-byte dest bdry  */
50         clrlwi  r8,r8,32-4      /* align to 16byte boundary  */
51         sub     r7,r4,r3        /* compute offset to src from dest */
52         cmplwi  cr0,r8,0        /* Were we aligned on a 16 byte bdy? */
53         beq+    L(dst_aligned)
57         /* Destination is not aligned on quadword boundary.  Get us to one.
59            r3 - return value (always)
60            r4 - current source addr
61            r5 - copy length
62            r6 - current dest addr
63            r7 - offset to src from dest
64            r8 - number of bytes to quadword boundary
65         */
67         mtcrf   0x01,r8         /* put #bytes to boundary into cr7  */
68         subf    r5,r8,r5        /* adjust remaining len */
70         bf      cr7*4+3,1f
71         lbzx    r0,r7,r6        /* copy 1 byte addr */
72         stb     r0,0(r6)
73         addi    r6,r6,1
75         bf      cr7*4+2,2f
76         lhzx    r0,r7,r6        /* copy 2 byte addr */
77         sth     r0,0(r6)
78         addi    r6,r6,2
80         bf      cr7*4+1,4f
81         lwzx    r0,r7,r6        /* copy 4 byte addr */
82         stw     r0,0(r6)
83         addi    r6,r6,4
85         bf      cr7*4+0,8f
86         lfdx    r0,r7,r6        /* copy 8 byte addr */
87         stfd    r0,0(r6)
88         addi    r6,r6,8
90         add     r4,r7,r6        /* update src addr */
94         /* Dest is quadword aligned now.
96            Lots of decisions to make.  If we are copying less than a cache
97            line we won't be here long.  If we are not on a cache line
98            boundary we need to get there.  And then we need to figure out
99            how many cache lines ahead to pre-touch.
101            r3 - return value (always)
102            r4 - current source addr
103            r5 - copy length
104            r6 - current dest addr
105         */
108         .align  4
109 L(dst_aligned):
112 #ifdef SHARED
113         mflr    r0
114 /* Establishes GOT addressability so we can load __cache_line_size
115    from static. This value was set from the aux vector during startup.  */
116         bcl     20,31,1f
118         mflr    r9
119         addis   r9,r9,__cache_line_size-1b@ha
120         lwz     r9,__cache_line_size-1b@l(r9)
121         mtlr    r0
122 #else
123 /* Load __cache_line_size from static. This value was set from the
124    aux vector during startup.  */
125         lis     r9,__cache_line_size@ha
126         lwz     r9,__cache_line_size@l(r9)
127 #endif
129         cmplwi  cr5, r9, 0
130         bne+    cr5,L(cachelineset)
131         li      r9,64
135 L(cachelineset):
137         addi   r10,r9,-1
139         cmpw   cr5,r5,r10       /* Less than a cacheline to go? */
141         neg     r7,r6           /* How far to next cacheline bdy? */
143         addi    r6,r6,-8        /* prepare for stdu  */
144         cmpwi   cr0,r9,128
145         addi    r4,r4,-8        /* prepare for ldu  */
148         ble+    cr5,L(lessthancacheline)
150         beq-    cr0,L(big_lines) /* 128 byte line code */
155         /* More than a cacheline left to go, and using 64 byte cachelines */
157         clrlwi  r7,r7,32-6      /* How far to next cacheline bdy? */
159         cmplwi  cr6,r7,0        /* Are we on a cacheline bdy already? */
161         /* Reduce total len by what it takes to get to the next cache line */
162         subf    r5,r7,r5
163         srwi    r7,r7,4         /* How many qws to get to the line bdy? */
165         /* How many full cache lines to copy after getting to a line bdy? */
166         srwi    r10,r5,6
168         cmplwi  r10,0           /* If no full cache lines to copy ... */
169         li      r11,0           /* number cachelines to copy with prefetch  */
170         beq     L(nocacheprefetch)
173         /* We are here because we have at least one full cache line to copy,
174            and therefore some pre-touching to do. */
176         cmplwi  r10,PREFETCH_AHEAD
177         li      r12,64+8        /* prefetch distance  */
178         ble     L(lessthanmaxprefetch)
180         /* We can only do so much pre-fetching.  R11 will have the count of
181            lines left to prefetch after the initial batch of prefetches
182            are executed. */
184         subi    r11,r10,PREFETCH_AHEAD
185         li      r10,PREFETCH_AHEAD
187 L(lessthanmaxprefetch):
188         mtctr   r10
190         /* At this point r10/ctr hold the number of lines to prefetch in this
191            initial batch, and r11 holds any remainder. */
193 L(prefetchSRC):
194         dcbt    r12,r4
195         addi    r12,r12,64
196         bdnz    L(prefetchSRC)
199         /* Prefetching is done, or was not needed.
201            cr6 - are we on a cacheline boundary already?
202            r7  - number of quadwords to the next cacheline boundary
203         */
205 L(nocacheprefetch):
206         mtctr   r7
208         cmplwi  cr1,r5,64   /* Less than a cache line to copy? */
210         /* How many bytes are left after we copy whatever full
211            cache lines we can get? */
212         clrlwi  r5,r5,32-6
214         beq     cr6,L(cachelinealigned)
217         /* Copy quadwords up to the next cacheline boundary */
219 L(aligntocacheline):
220         lfd     fp9,0x08(r4)
221         lfdu    fp10,0x10(r4)
222         stfd    fp9,0x08(r6)
223         stfdu   fp10,0x10(r6)
224         bdnz    L(aligntocacheline)
227         .align 4
228 L(cachelinealigned):            /* copy while cache lines  */
230         blt-    cr1,L(lessthancacheline) /* size <64  */
232 L(outerloop):
233         cmpwi   r11,0
234         mtctr   r11
235         beq-    L(endloop)
237         li      r11,64*ZERO_AHEAD +8    /* DCBZ dist  */
239         .align  4
240         /* Copy whole cachelines, optimized by prefetching SRC cacheline  */
241 L(loop):                        /* Copy aligned body  */
242         dcbt    r12,r4          /* PREFETCH SOURCE some cache lines ahead  */
243         lfd     fp9,  0x08(r4)
244         dcbz    r11,r6
245         lfd     fp10, 0x10(r4)
246         lfd     fp11, 0x18(r4)
247         lfd     fp12, 0x20(r4)
248         stfd    fp9,  0x08(r6)
249         stfd    fp10, 0x10(r6)
250         stfd    fp11, 0x18(r6)
251         stfd    fp12, 0x20(r6)
252         lfd     fp9,  0x28(r4)
253         lfd     fp10, 0x30(r4)
254         lfd     fp11, 0x38(r4)
255         lfdu    fp12, 0x40(r4)
256         stfd    fp9,  0x28(r6)
257         stfd    fp10, 0x30(r6)
258         stfd    fp11, 0x38(r6)
259         stfdu   fp12, 0x40(r6)
261         bdnz    L(loop)
264 L(endloop):
265         cmpwi   r10,0
266         beq-    L(endloop2)
267         mtctr   r10
269 L(loop2):                       /* Copy aligned body  */
270         lfd     fp9,  0x08(r4)
271         lfd     fp10, 0x10(r4)
272         lfd     fp11, 0x18(r4)
273         lfd     fp12, 0x20(r4)
274         stfd    fp9,  0x08(r6)
275         stfd    fp10, 0x10(r6)
276         stfd    fp11, 0x18(r6)
277         stfd    fp12, 0x20(r6)
278         lfd     fp9,  0x28(r4)
279         lfd     fp10, 0x30(r4)
280         lfd     fp11, 0x38(r4)
281         lfdu    fp12, 0x40(r4)
282         stfd    fp9,  0x28(r6)
283         stfd    fp10, 0x30(r6)
284         stfd    fp11, 0x38(r6)
285         stfdu   fp12, 0x40(r6)
287         bdnz    L(loop2)
288 L(endloop2):
291         .align  4
292 L(lessthancacheline):           /* Was there less than cache to do ?  */
293         cmplwi  cr0,r5,16
294         srwi    r7,r5,4         /* divide size by 16  */
295         blt-    L(do_lt16)
296         mtctr   r7
298 L(copy_remaining):
299         lfd     fp9,  0x08(r4)
300         lfdu    fp10, 0x10(r4)
301         stfd    fp9,  0x08(r6)
302         stfdu   fp10, 0x10(r6)
303         bdnz    L(copy_remaining)
305 L(do_lt16):                     /* less than 16 ?  */
306         cmplwi  cr0,r5,0        /* copy remaining bytes (0-15)  */
307         beqlr+                  /* no rest to copy  */
308         addi    r4,r4,8
309         addi    r6,r6,8
311 L(shortcopy):                   /* SIMPLE COPY to handle size =< 15 bytes  */
312         mtcrf   0x01,r5
313         sub     r7,r4,r6
314         bf-     cr7*4+0,8f
315         lfdx    fp9,r7,r6       /* copy 8 byte  */
316         stfd    fp9,0(r6)
317         addi    r6,r6,8
319         bf      cr7*4+1,4f
320         lwzx    r0,r7,r6        /* copy 4 byte  */
321         stw     r0,0(r6)
322         addi    r6,r6,4
324         bf      cr7*4+2,2f
325         lhzx    r0,r7,r6        /* copy 2 byte  */
326         sth     r0,0(r6)
327         addi    r6,r6,2
329         bf      cr7*4+3,1f
330         lbzx    r0,r7,r6        /* copy 1 byte  */
331         stb     r0,0(r6)
333         blr
339         /* Similar to above, but for use with 128 byte lines. */
342 L(big_lines):
344         clrlwi  r7,r7,32-7      /* How far to next cacheline bdy? */
346         cmplwi  cr6,r7,0        /* Are we on a cacheline bdy already? */
348         /* Reduce total len by what it takes to get to the next cache line */
349         subf    r5,r7,r5
350         srwi    r7,r7,4         /* How many qw to get to the line bdy? */
352         /* How many full cache lines to copy after getting to a line bdy? */
353         srwi    r10,r5,7
355         cmplwi  r10,0           /* If no full cache lines to copy ... */
356         li      r11,0           /* number cachelines to copy with prefetch  */
357         beq     L(nocacheprefetch_128)
360         /* We are here because we have at least one full cache line to copy,
361            and therefore some pre-touching to do. */
363         cmplwi  r10,PREFETCH_AHEAD
364         li      r12,128+8       /* prefetch distance  */
365         ble     L(lessthanmaxprefetch_128)
367         /* We can only do so much pre-fetching.  R11 will have the count of
368            lines left to prefetch after the initial batch of prefetches
369            are executed. */
371         subi    r11,r10,PREFETCH_AHEAD
372         li      r10,PREFETCH_AHEAD
374 L(lessthanmaxprefetch_128):
375         mtctr   r10
377         /* At this point r10/ctr hold the number of lines to prefetch in this
378            initial batch, and r11 holds any remainder. */
380 L(prefetchSRC_128):
381         dcbt    r12,r4
382         addi    r12,r12,128
383         bdnz    L(prefetchSRC_128)
386         /* Prefetching is done, or was not needed.
388            cr6 - are we on a cacheline boundary already?
389            r7  - number of quadwords to the next cacheline boundary
390         */
392 L(nocacheprefetch_128):
393         mtctr   r7
395         cmplwi  cr1,r5,128  /* Less than a cache line to copy? */
397         /* How many bytes are left after we copy whatever full
398            cache lines we can get? */
399         clrlwi  r5,r5,32-7
401         beq     cr6,L(cachelinealigned_128)
404         /* Copy quadwords up to the next cacheline boundary */
406 L(aligntocacheline_128):
407         lfd     fp9,0x08(r4)
408         lfdu    fp10,0x10(r4)
409         stfd    fp9,0x08(r6)
410         stfdu   fp10,0x10(r6)
411         bdnz    L(aligntocacheline_128)
414 L(cachelinealigned_128):        /* copy while cache lines  */
416         blt-    cr1,L(lessthancacheline) /* size <128  */
418 L(outerloop_128):
419         cmpwi   r11,0
420         mtctr   r11
421         beq-    L(endloop_128)
423         li      r11,128*ZERO_AHEAD +8    /* DCBZ dist  */
425         .align  4
426         /* Copy whole cachelines, optimized by prefetching SRC cacheline  */
427 L(loop_128):                    /* Copy aligned body  */
428         dcbt    r12,r4          /* PREFETCH SOURCE some cache lines ahead  */
429         lfd     fp9,  0x08(r4)
430         dcbz    r11,r6
431         lfd     fp10, 0x10(r4)
432         lfd     fp11, 0x18(r4)
433         lfd     fp12, 0x20(r4)
434         stfd    fp9,  0x08(r6)
435         stfd    fp10, 0x10(r6)
436         stfd    fp11, 0x18(r6)
437         stfd    fp12, 0x20(r6)
438         lfd     fp9,  0x28(r4)
439         lfd     fp10, 0x30(r4)
440         lfd     fp11, 0x38(r4)
441         lfd     fp12, 0x40(r4)
442         stfd    fp9,  0x28(r6)
443         stfd    fp10, 0x30(r6)
444         stfd    fp11, 0x38(r6)
445         stfd    fp12, 0x40(r6)
446         lfd     fp9,  0x48(r4)
447         lfd     fp10, 0x50(r4)
448         lfd     fp11, 0x58(r4)
449         lfd     fp12, 0x60(r4)
450         stfd    fp9,  0x48(r6)
451         stfd    fp10, 0x50(r6)
452         stfd    fp11, 0x58(r6)
453         stfd    fp12, 0x60(r6)
454         lfd     fp9,  0x68(r4)
455         lfd     fp10, 0x70(r4)
456         lfd     fp11, 0x78(r4)
457         lfdu    fp12, 0x80(r4)
458         stfd    fp9,  0x68(r6)
459         stfd    fp10, 0x70(r6)
460         stfd    fp11, 0x78(r6)
461         stfdu   fp12, 0x80(r6)
463         bdnz    L(loop_128)
466 L(endloop_128):
467         cmpwi   r10,0
468         beq-    L(endloop2_128)
469         mtctr   r10
471 L(loop2_128):                   /* Copy aligned body  */
472         lfd     fp9,  0x08(r4)
473         lfd     fp10, 0x10(r4)
474         lfd     fp11, 0x18(r4)
475         lfd     fp12, 0x20(r4)
476         stfd    fp9,  0x08(r6)
477         stfd    fp10, 0x10(r6)
478         stfd    fp11, 0x18(r6)
479         stfd    fp12, 0x20(r6)
480         lfd     fp9,  0x28(r4)
481         lfd     fp10, 0x30(r4)
482         lfd     fp11, 0x38(r4)
483         lfd     fp12, 0x40(r4)
484         stfd    fp9,  0x28(r6)
485         stfd    fp10, 0x30(r6)
486         stfd    fp11, 0x38(r6)
487         stfd    fp12, 0x40(r6)
488         lfd     fp9,  0x48(r4)
489         lfd     fp10, 0x50(r4)
490         lfd     fp11, 0x58(r4)
491         lfd     fp12, 0x60(r4)
492         stfd    fp9,  0x48(r6)
493         stfd    fp10, 0x50(r6)
494         stfd    fp11, 0x58(r6)
495         stfd    fp12, 0x60(r6)
496         lfd     fp9,  0x68(r4)
497         lfd     fp10, 0x70(r4)
498         lfd     fp11, 0x78(r4)
499         lfdu    fp12, 0x80(r4)
500         stfd    fp9,  0x68(r6)
501         stfd    fp10, 0x70(r6)
502         stfd    fp11, 0x78(r6)
503         stfdu   fp12, 0x80(r6)
504         bdnz    L(loop2_128)
505 L(endloop2_128):
507         b       L(lessthancacheline)
510 END (BP_SYM (memcpy))
511 libc_hidden_builtin_def (memcpy)