arm: Implement armv6 optimized string routines
[glibc.git] / ports / sysdeps / arm / armv6 / strcpy.S
blob41f6443319361c97c671788fa34af6ae66816ef3
1 /* strcpy -- copy a nul-terminated string.
2    Copyright (C) 2013 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 /* Endian independent macros for shifting bytes within registers.  */
22 #ifdef __ARMEB__
23 #define lsh_gt          lsr
24 #define lsh_ls          lsl
25 #else
26 #define lsh_gt          lsl
27 #define lsh_ls          lsr
28 #endif
30         .syntax unified
31         .text
33 ENTRY (__stpcpy)
34         @ Signal stpcpy with NULL in IP.
35         mov     ip, #0
36         b       0f
37 END (__stpcpy)
39 weak_alias (__stpcpy, stpcpy)
40 libc_hidden_def (__stpcpy)
41 libc_hidden_builtin_def (stpcpy)
43 ENTRY (strcpy)
44         @ Signal strcpy with DEST in IP.
45         mov     ip, r0
47         pld     [r0]
48         pld     [r1]
50         @ To cater to long strings, we want 8 byte alignment in the source.
51         @ To cater to small strings, we don't want to start that right away.
52         @ Loop up to 16 times, less whatever it takes to reach alignment.
53         and     r3, r1, #7
54         rsb     r3, r3, #16
56         @ Loop until we find ...
57 1:      ldrb    r2, [r1], #1
58         subs    r3, r3, #1              @ ... the alignment point
59         strb    r2, [r0], #1
60         it      ne
61         cmpne   r2, #0                  @ ... or EOS
62         bne     1b
64         @ Disambiguate the exit possibilites above
65         cmp     r2, #0                  @ Found EOS
66         beq     .Lreturn
68         @ Load the next two words asap
69         ldrd    r2, r3, [r1], #8
70         pld     [r0, #64]
71         pld     [r1, #64]
73         @ For longer strings, we actaully need a stack frame.
74         push    { r4, r5, r6, r7 }
75         cfi_adjust_cfa_offset (16)
76         cfi_rel_offset (r4, 0)
77         cfi_rel_offset (r5, 4)
78         cfi_rel_offset (r6, 8)
79         cfi_rel_offset (r7, 12)
81         @ Subtracting (unsigned saturating) from 1 for any byte means result
82         @ of 1 for any byte that was originally zero and 0 otherwise.
83         @ Therefore we consider the lsb of each byte the "found" bit.
84 #ifdef ARCH_HAS_T2
85         movw    r7, #0x0101
86         tst     r0, #3                  @ Test alignment of DEST
87         movt    r7, #0x0101
88 #else
89         ldr     ip, =0x01010101
90         tst     r0, #3
91 #endif
92         bne     .Lunaligned
94         @ So now source (r1) is aligned to 8, and dest (r0) is aligned to 4.
95         @ Loop, reading 8 bytes at a time, searching for EOS.
96         .balign 16
97 2:      uqsub8  r4, r7, r2              @ Find EOS
98         uqsub8  r5, r7, r3
99         pld     [r1, #128]
100         cmp     r4, #0                  @ EOS in first word?
101         pld     [r0, #128]
102         bne     3f
103         str     r2, [r0], #4
104         cmp     r5, #0                  @ EOS in second word?
105         bne     4f
106         str     r3, [r0], #4
107         ldrd    r2, r3, [r1], #8
108         b       2b
110 3:      sub     r1, r1, #4              @ backup to first word
111 4:      sub     r1, r1, #4              @ backup to second word
113         @ ... then finish up any tail a byte at a time.
114         @ Note that we generally back up and re-read source bytes,
115         @ but we'll not re-write dest bytes.
116 .Lbyte_loop:
117         ldrb    r2, [r1], #1
118         cmp     r2, #0
119         strb    r2, [r0], #1
120         bne     .Lbyte_loop
122         pop     { r4, r5, r6, r7 }
123         cfi_remember_state
124         cfi_adjust_cfa_offset (-16)
125         cfi_restore (r4)
126         cfi_restore (r5)
127         cfi_restore (r6)
128         cfi_restore (r7)
130 .Lreturn:
131         cmp     ip, #0                  @ Was this strcpy or stpcpy?
132         ite     eq
133         subeq   r0, r0, #1              @ stpcpy: undo post-inc from store
134         movne   r0, ip                  @ strcpy: return original dest
135         bx      lr
137 .Lunaligned:
138         cfi_restore_state
139         @ Here, source is aligned to 8, but the destination is not word
140         @ aligned.  Therefore we have to shift the data in order to be
141         @ able to perform aligned word stores.
143         @ Find out which misalignment we're dealing with.
144         tst     r0, #1
145         beq     .Lunaligned2
146         tst     r0, #2
147         bne     .Lunaligned3
148         @ Fallthru to .Lunaligned1.
150 .macro unaligned_copy   unalign
151         @ Prologue to unaligned loop.  Seed shifted non-zero bytes.
152         uqsub8  r4, r7, r2              @ Find EOS
153         uqsub8  r5, r7, r3
154         mvns    r4, r4                  @ EOS in first word?
155         it      ne
156         subne   r1, r1, #8
157         bne     .Lbyte_loop
158 #ifdef __ARMEB__
159         rev     r2, r2                  @ Byte stores below need LE data
160 #endif
161         @ Store a few bytes from the first word.
162         @ At the same time we align r0 and shift out bytes from r2.
163 .rept   4-\unalign
164         strb    r2, [r0], #1
165         lsr     r2, r2, #8
166 .endr
167 #ifdef __ARMEB__
168         rev     r2, r2                  @ Undo previous rev
169 #endif
170         @ Rotated unaligned copy loop.  The tail of the prologue is
171         @ shared with the loop itself.
172         .balign 8
173 1:      mvns    r5, r5                  @ EOS in second word?
174         bne     4f
175         @ Combine first and second words
176         orr     r2, r2, r3, lsh_gt #(\unalign*8)
177         @ Save leftover bytes from the two words
178         lsh_ls  r6, r3, #((4-\unalign)*8)
179         str     r2, [r0], #4
180         @ The "real" start of the unaligned copy loop.
181         ldrd    r2, r3, [r1], #8        @ Load 8 more bytes
182         uqsub8  r4, r7, r2              @ Find EOS
183         pld     [r1, #128]
184         uqsub8  r5, r7, r3
185         pld     [r0, #128]
186         mvns    r4, r4                  @ EOS in first word?
187         bne     3f
188         @ Combine the leftover and the first word
189         orr     r6, r6, r2, lsh_gt #(\unalign*8)
190         @ Discard used bytes from the first word.
191         lsh_ls  r2, r2, #((4-\unalign)*8)
192         str     r6, [r0], #4
193         b       1b
194         @ Found EOS in one of the words; adjust backward
195 3:      sub     r1, r1, #4
196         mov     r2, r6
197 4:      sub     r1, r1, #4
198         @ And store the remaining bytes from the leftover
199 #ifdef __ARMEB__
200         rev     r2, r2
201 #endif
202 .rept   \unalign
203         strb    r2, [r0], #1
204         lsr     r2, r2, #8
205 .endr
206         b       .Lbyte_loop
207 .endm
209 .Lunaligned1:
210         unaligned_copy  1
211 .Lunaligned2:
212         unaligned_copy  2
213 .Lunaligned3:
214         unaligned_copy  3
216 END (strcpy)
218 libc_hidden_builtin_def (strcpy)