Update copyright dates with scripts/update-copyrights.
[glibc.git] / sysdeps / powerpc / powerpc64 / power7 / strcpy.S
blob70f2987181db4f63dd4c71fdd20d3507c412ab57
1 /* Optimized strcpy/stpcpy implementation for PowerPC64/POWER7.
2    Copyright (C) 2013-2015 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
19 #include <sysdep.h>
21 /* Implements the function
23    char * [r3] strcpy (char *dest [r3], const char *src [r4])
25    or
27    char * [r3] strcpy (char *dest [r3], const char *src [r4])
29    if USE_AS_STPCPY is defined. It tries to use aligned memory accesses
30    when possible using the following algorithm:
32    if (((((uintptr_t)dst & 0x7UL) == 0) && ((uintptr_t)src & 0x7UL) == 0))
33      goto aligned_doubleword_copy;
34    if (((uintptr_t)dst & 0x7UL) == ((uintptr_t)src & 0x7UL))
35      goto same_alignment;
36    goto unaligned;
38    The aligned comparison are made using cmpb instructions.  */
40 #ifdef USE_AS_STPCPY
41 # define FUNC_NAME __stpcpy
42 #else
43 # define FUNC_NAME strcpy
44 #endif
46         .machine  power7
47 EALIGN (FUNC_NAME, 4, 0)
48         CALL_MCOUNT 2
50 #define rTMP    r0
51 #ifdef USE_AS_STPCPY
52 #define rRTN    r3      /* pointer to previous word/doubleword in dest */
53 #else
54 #define rRTN    r12     /* pointer to previous word/doubleword in dest */
55 #endif
56 #define rSRC    r4      /* pointer to previous word/doubleword in src */
57 #define rMASK   r5      /* mask 0xffffffff | 0xffffffffffffffff */
58 #define rWORD   r6      /* current word from src */
59 #define rALT    r7      /* alternate word from src */
60 #define rRTNAL  r8      /* alignment of return pointer */
61 #define rSRCAL  r9      /* alignment of source pointer */
62 #define rALCNT  r10     /* bytes to read to reach 8 bytes alignment */
63 #define rSUBAL  r11     /* doubleword minus unaligned displacement */
65 #ifndef USE_AS_STPCPY
66 /* Save the dst pointer to use as return value.  */
67         mr      rRTN, r3
68 #endif
69         or      rTMP, rSRC, rRTN
70         clrldi. rTMP, rTMP, 61
71         bne     L(check_alignment)
72         b       L(aligned_doubleword_copy)
74         .align 4
75 L(check_alignment):
76         rldicl  rRTNAL, rRTN, 0, 61
77         rldicl  rSRCAL, rSRC, 0, 61
78         cmpld   cr7, rSRCAL, rRTNAL
79         beq     cr7, L(same_alignment)
80         b       L(unaligned)
82         .align 4
83 L(same_alignment):
84 /* Src and dst with same alignment: align both to doubleword.  */
85         mr      rALCNT, rRTN
86         lbz     rWORD, 0(rSRC)
87         subfic  rSUBAL, rRTNAL, 8
88         addi    rRTN, rRTN, 1
89         addi    rSRC, rSRC, 1
90         cmpdi   cr7, rWORD, 0
91         stb     rWORD, 0(rALCNT)
92         beq     cr7, L(s2)
94         add     rALCNT, rALCNT, rSUBAL
95         subf    rALCNT, rRTN, rALCNT
96         addi    rALCNT, rALCNT, 1
97         mtctr   rALCNT
98         b       L(s1)
100         .align 4
101 L(s0):
102         addi    rSRC, rSRC, 1
103         lbz     rWORD, -1(rSRC)
104         cmpdi   cr7, rWORD, 0
105         stb     rWORD, -1(rALCNT)
106         beqlr   cr7
107         mr      rRTN, rALCNT
108 L(s1):
109         addi    rALCNT, rRTN,1
110         bdnz    L(s0)
111         b L(aligned_doubleword_copy)
112         .align 4
113 L(s2):
114         mr      rRTN, rALCNT
115         blr
117 /* For doubleword aligned memory, operate using doubleword load and stores.  */
118         .align 4
119 L(aligned_doubleword_copy):
120         li      rMASK, 0
121         addi    rRTN, rRTN, -8
122         ld      rWORD, 0(rSRC)
123         b       L(g2)
125         .align 4
126 L(g0):  ldu     rALT, 8(rSRC)
127         stdu    rWORD, 8(rRTN)
128         cmpb    rTMP, rALT, rMASK
129         cmpdi   rTMP, 0
130         bne     L(g1)
131         ldu     rWORD, 8(rSRC)
132         stdu    rALT, 8(rRTN)
133 L(g2):  cmpb    rTMP, rWORD, rMASK
134         cmpdi   rTMP, 0         /* If rTMP is 0, no null's have been found.  */
135         beq     L(g0)
137         mr      rALT, rWORD
138 /* We've hit the end of the string.  Do the rest byte-by-byte.  */
139 L(g1):
140 #ifdef __LITTLE_ENDIAN__
141         extrdi. rTMP, rALT, 8, 56
142         stbu    rALT, 8(rRTN)
143         beqlr-
144         extrdi. rTMP, rALT, 8, 48
145         stbu    rTMP, 1(rRTN)
146         beqlr-
147         extrdi. rTMP, rALT, 8, 40
148         stbu    rTMP, 1(rRTN)
149         beqlr-
150         extrdi. rTMP, rALT, 8, 32
151         stbu    rTMP, 1(rRTN)
152         beqlr-
153         extrdi. rTMP, rALT, 8, 24
154         stbu    rTMP, 1(rRTN)
155         beqlr-
156         extrdi. rTMP, rALT, 8, 16
157         stbu    rTMP, 1(rRTN)
158         beqlr-
159         extrdi. rTMP, rALT, 8, 8
160         stbu    rTMP, 1(rRTN)
161         beqlr-
162         extrdi  rTMP, rALT, 8, 0
163         stbu    rTMP, 1(rRTN)
164 #else
165         extrdi. rTMP, rALT, 8, 0
166         stbu    rTMP, 8(rRTN)
167         beqlr
168         extrdi. rTMP, rALT, 8, 8
169         stbu    rTMP, 1(rRTN)
170         beqlr
171         extrdi. rTMP, rALT, 8, 16
172         stbu    rTMP, 1(rRTN)
173         beqlr
174         extrdi. rTMP, rALT, 8, 24
175         stbu    rTMP, 1(rRTN)
176         beqlr
177         extrdi. rTMP, rALT, 8, 32
178         stbu    rTMP, 1(rRTN)
179         beqlr
180         extrdi. rTMP, rALT, 8, 40
181         stbu    rTMP, 1(rRTN)
182         beqlr
183         extrdi. rTMP, rALT, 8, 48
184         stbu    rTMP, 1(rRTN)
185         beqlr
186         stbu    rALT, 1(rRTN)
187 #endif
188         blr
190         .align  4
191 L(unaligned):
192         cmpdi   rSRCAL, 0               /* Check src alignment */
193         beq     L(srcaligndstunalign)
194         /* src is unaligned */
195         rlwinm  r10, rSRC, 3,26,28      /* Calculate padding.  */
196         clrrdi  rSRC, rSRC, 3           /* Align the addr to dw boundary */
197         ld      rWORD, 0(rSRC)          /* Load doubleword from memory.  */
198         li      rTMP, 0
199         /* Discard bits not part of the string */
200 #ifdef __LITTLE_ENDIAN__
201         srd     rALT, rWORD, r10
202 #else
203         sld     rALT, rWORD, r10
204 #endif
205         cmpb    rTMP, rALT, rTMP        /* Compare each byte against null */
206         /* Discard bits not part of the string */
207 #ifdef __LITTLE_ENDIAN__
208         sld     rTMP, rTMP, r10
209 #else
210         srd     rTMP, rTMP, r10
211 #endif
212         cmpdi   rTMP, 0
213         bne     L(bytebybyte)           /* if it has null, copy byte by byte */
214         subfic  r8, r9, 8
215         rlwinm  r5, rRTN, 3,26,28       /* Calculate padding in bits.  */
216         rldicl  r9, rRTN, 0, 61         /* Calculate padding in bytes. */
217         addi    rRTN, rRTN, -1
219         cmpdi   r5, 0                   /* check dest alignment */
220         beq     L(srcunaligndstalign)
222         /* both src and dst unaligned */
223 #ifdef __LITTLE_ENDIAN__
224         sld     rWORD, rALT, r10
225         mr      r11, r10
226         addi    r11, r11, -8            /* Adjust byte pointer on loaded dw */
227 #else
228         srd     rWORD, rALT, r10
229         subfic  r11, r10, 64
230 #endif
231         /* dst alignment is greater then src alignment? */
232         cmpd    cr7, r5, r10
233         blt     cr7, L(dst_align_small)
234         /* src alignment is less than dst */
236         /* Calculate the dst alignment differnce */
237         subfic  rALT, r9, 8
238         mtctr   rALT
240         /* Write till dst is aligned */
241         cmpdi   rTMP, rALT, 4
242         blt     L(storebyte1)           /* less than 4, store byte by byte */
243         beq     L(equal1)               /* if its 4, store word */
244         addi    rTMP, rALT, -4          /* greater than 4, so stb and stw */
245         mtctr   rTMP
246 L(storebyte1):
247 #ifdef __LITTLE_ENDIAN__
248         addi    r11, r11, 8             /* Adjust byte pointer on loaded dw */
249 #else
250         addi    r11, r11, -8
251 #endif
252         srd     rALT, rWORD, r11
253         stbu    rALT, 1(rRTN)
254         bdnz    L(storebyte1)
256         subfic  rALT, r9, 8             /* Check the remaining bytes */
257         cmpdi   rTMP, rALT, 4
258         blt     L(proceed)
260         .align 4
261 L(equal1):
262 #ifdef __LITTLE_ENDIAN__
263         addi    r11, r11, 8             /* Adjust byte pointer on loaded dw */
264         srd     rALT, rWORD, r11
265 #else
266         subfic  r11, r11, 64
267         sld     rALT, rWORD, r11
268         srdi    rALT, rALT, 32
269 #endif
270         stw     rALT, 1(rRTN)
271         addi    rRTN, rRTN, 4
273 L(proceed):
274         mr      rALT, rWORD
275         /* calculate the Left over bytes to be written */
276         subfic  r11, r10, 64
277         subfic  r5, r5, 64
278         subf    r5, r5, r11             /* remaining bytes on second dw */
279         subfic  r10, r5, 64             /* remaining bytes on first dw */
280         subfic  r9, r9, 8
281         subf    r8, r9, r8              /* recalculate padding */
282 L(srcunaligndstalign):
283         addi    rRTN, rRTN, 1
284         subfic  r5, r10, 64             /* remaining bytes on second dw */
285         addi    rSRC, rSRC, 8
286         li      rTMP,0
287         b       L(storedouble)
289         .align 4
290 L(dst_align_small):
291         mtctr   r8
292         /* Write till src is aligned */
293 L(storebyte2):
294 #ifdef __LITTLE_ENDIAN__
295         addi    r11, r11, 8             /* Adjust byte pointer on dw */
296 #else
297         addi    r11, r11, -8
298 #endif
299         srd     rALT, rWORD, r11
300         stbu    rALT, 1(rRTN)
301         bdnz    L(storebyte2)
303         addi    rSRC, rSRC, 8           /* Increment src pointer */
304         addi    rRTN, rRTN, 1           /* Increment dst pointer */
305         rldicl  r8, rRTN, 0, 61         /* Recalculate padding */
307         /* src is aligned */
308 L(srcaligndstunalign):
309         ld      rWORD, 0(rSRC)
310         mr      rALT, rWORD
311         li      rTMP, 0                 /* Check null */
312         cmpb    rTMP, rWORD, rTMP
313         cmpdi   rTMP, 0
314         bne     L(bytebybyte)           /* Do byte by byte if there is NULL */
315         rlwinm  r5, rRTN, 3,26,28       /* Calculate padding */
316         addi    rRTN, rRTN, -1
317         subfic  r10, r8, 8
318         /* write byte by byte till aligned */
319 #ifdef __LITTLE_ENDIAN__
320         li      r11, -8
321 #else
322         li      r11, 64
323 #endif
324         mtctr   r10
325         cmpdi   rTMP, r10, 4
326         blt     L(storebyte)
327         beq     L(equal)
328         addi    rTMP, r10, -4
329         mtctr   rTMP
330 L(storebyte):
331 #ifdef __LITTLE_ENDIAN__
332         addi    r11, r11, 8             /* Adjust byte pointer on  dw */
333 #else
334         addi    r11, r11, -8
335 #endif
336         srd     rALT, rWORD, r11
337         stbu    rALT, 1(rRTN)
338         bdnz    L(storebyte)
340         cmpdi   rTMP, r10, 4
341         blt     L(align)
343         .align 4
344 L(equal):
345 #ifdef __LITTLE_ENDIAN__
346         addi    r11, r11, 8
347         srd     rALT, rWORD, r11
348 #else
349         subfic  r11, r11, 64
350         sld     rALT, rWORD, r11
351         srdi    rALT, rALT, 32
352 #endif
353         stw     rALT, 1(rRTN)
354         addi    rRTN, rRTN, 4
355 L(align):
356         addi    rRTN, rRTN, 1
357         addi    rSRC, rSRC, 8           /* Increment src pointer */
358         subfic  r10, r5, 64
359         li      rTMP, 0
360         /* dst addr aligned to 8 */
361 L(storedouble):
362         ld      rALT, 0(rSRC)           /* load next dw */
363         cmpb    rTMP, rALT, rTMP
364         cmpdi   rTMP, 0                 /* check for null on each new dw */
365         bne     L(null)
366 #ifdef __LITTLE_ENDIAN__
367         srd     r9, rWORD, r10          /* bytes from first dw */
368         sld     r11, rALT, r5           /* bytes from second dw */
369 #else
370         sld     r9, rWORD, r10
371         srd     r11, rALT, r5
372 #endif
373         or      r11, r9, r11            /* make as a single dw */
374         std     r11, 0(rRTN)            /* store as std on aligned addr */
375         mr      rWORD, rALT             /* still few bytes left to be written */
376         addi    rRTN, rRTN, 8           /* increment dst addr */
377         addi    rSRC, rSRC, 8           /* increment src addr */
378         b       L(storedouble)          /* Loop till NULL */
380         .align 4
382 /* We've hit the end of the string.  Do the rest byte-by-byte.  */
383 L(null):
384         addi    rRTN, rRTN, -1
385         mr      r10, r5
386         mtctr   r8
387 #ifdef __LITTLE_ENDIAN__
388         subfic  r10, r10, 64
389         addi    r10, r10, -8
390 #endif
391         cmpdi   rTMP, r8, 4
392         blt     L(loop)
394         /* we can still use stw if leftover >= 4*/
395 #ifdef __LITTLE_ENDIAN__
396         addi    r10, r10, 8
397         srd     r11, rWORD, r10
398 #else
399         subfic  r10, r10, 64
400         sld     r11, rWORD, r10
401         srdi    r11, r11, 32
402 #endif
403         stw     r11, 1(rRTN)
404         addi    rRTN, rRTN, 4
406         beq     L(bytebybyte1)
407         addi    r10, r10, 32
408 #ifdef __LITTLE_ENDIAN__
409         addi    r10, r10, -8
410 #else
411         subfic  r10, r10, 64
412 #endif
413         addi    rTMP, r8, -4
414         mtctr   rTMP
415         /* remaining byte by byte part of first dw */
416 L(loop):
417 #ifdef __LITTLE_ENDIAN__
418         addi    r10, r10, 8
419 #else
420         addi    r10, r10, -8
421 #endif
422         srd     rTMP, rWORD, r10
423         stbu    rTMP, 1(rRTN)
424         bdnz    L(loop)
426 L(bytebybyte1):
427         addi    rRTN, rRTN, 1
428         /* remaining byte by byte part of second dw */
429 L(bytebybyte):
430         addi    rRTN, rRTN, -8
431         b       L(g1)
433 END (FUNC_NAME)
435 #ifndef USE_AS_STPCPY
436 libc_hidden_builtin_def (strcpy)
437 #endif