Update copyright notices with scripts/update-copyrights
[glibc.git] / ports / sysdeps / arm / armv6 / strcpy.S
blob833a83c28fcf9705b31ff0a7c087df4e1f142f8c
1 /* strcpy -- copy a nul-terminated string.
2    Copyright (C) 2013-2014 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         sfi_pld r0
48         sfi_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:      sfi_breg r1, \
58         ldrb    r2, [\B], #1
59         subs    r3, r3, #1              @ ... the alignment point
60         sfi_breg r0, \
61         strb    r2, [\B], #1
62         it      ne
63         cmpne   r2, #0                  @ ... or EOS
64         bne     1b
66         @ Disambiguate the exit possibilites above
67         cmp     r2, #0                  @ Found EOS
68         beq     .Lreturn
70         @ Load the next two words asap
71         sfi_breg r1, \
72         ldrd    r2, r3, [\B], #8
73         sfi_pld r0, #64
74         sfi_pld r1, #64
76         @ For longer strings, we actaully need a stack frame.
77         push    { r4, r5, r6, r7 }
78         cfi_adjust_cfa_offset (16)
79         cfi_rel_offset (r4, 0)
80         cfi_rel_offset (r5, 4)
81         cfi_rel_offset (r6, 8)
82         cfi_rel_offset (r7, 12)
84         @ Subtracting (unsigned saturating) from 1 for any byte means result
85         @ of 1 for any byte that was originally zero and 0 otherwise.
86         @ Therefore we consider the lsb of each byte the "found" bit.
87 #ifdef ARCH_HAS_T2
88         movw    r7, #0x0101
89         tst     r0, #3                  @ Test alignment of DEST
90         movt    r7, #0x0101
91 #else
92         ldr     r7, =0x01010101
93         tst     r0, #3
94 #endif
95         bne     .Lunaligned
97         @ So now source (r1) is aligned to 8, and dest (r0) is aligned to 4.
98         @ Loop, reading 8 bytes at a time, searching for EOS.
99         .balign 16
100 2:      uqsub8  r4, r7, r2              @ Find EOS
101         uqsub8  r5, r7, r3
102         sfi_pld r1, #128
103         cmp     r4, #0                  @ EOS in first word?
104         sfi_pld r0, #128
105         bne     3f
106         sfi_breg r0, \
107         str     r2, [\B], #4
108         cmp     r5, #0                  @ EOS in second word?
109         bne     4f
110         sfi_breg r0, \
111         str     r3, [\B], #4
112         sfi_breg r1, \
113         ldrd    r2, r3, [\B], #8
114         b       2b
116 3:      sub     r1, r1, #4              @ backup to first word
117 4:      sub     r1, r1, #4              @ backup to second word
119         @ ... then finish up any tail a byte at a time.
120         @ Note that we generally back up and re-read source bytes,
121         @ but we'll not re-write dest bytes.
122 .Lbyte_loop:
123         sfi_breg r1, \
124         ldrb    r2, [\B], #1
125         cmp     r2, #0
126         sfi_breg r0, \
127         strb    r2, [\B], #1
128         bne     .Lbyte_loop
130         pop     { r4, r5, r6, r7 }
131         cfi_remember_state
132         cfi_adjust_cfa_offset (-16)
133         cfi_restore (r4)
134         cfi_restore (r5)
135         cfi_restore (r6)
136         cfi_restore (r7)
138 .Lreturn:
139         cmp     ip, #0                  @ Was this strcpy or stpcpy?
140         ite     eq
141         subeq   r0, r0, #1              @ stpcpy: undo post-inc from store
142         movne   r0, ip                  @ strcpy: return original dest
143         bx      lr
145 .Lunaligned:
146         cfi_restore_state
147         @ Here, source is aligned to 8, but the destination is not word
148         @ aligned.  Therefore we have to shift the data in order to be
149         @ able to perform aligned word stores.
151         @ Find out which misalignment we're dealing with.
152         tst     r0, #1
153         beq     .Lunaligned2
154         tst     r0, #2
155         bne     .Lunaligned3
156         @ Fallthru to .Lunaligned1.
158 .macro unaligned_copy   unalign
159         @ Prologue to unaligned loop.  Seed shifted non-zero bytes.
160         uqsub8  r4, r7, r2              @ Find EOS
161         uqsub8  r5, r7, r3
162         mvns    r4, r4                  @ EOS in first word?
163         it      ne
164         subne   r1, r1, #8
165         bne     .Lbyte_loop
166 #ifdef __ARMEB__
167         rev     r2, r2                  @ Byte stores below need LE data
168 #endif
169         @ Store a few bytes from the first word.
170         @ At the same time we align r0 and shift out bytes from r2.
171 .rept   4-\unalign
172         sfi_breg r0, \
173         strb    r2, [\B], #1
174         lsr     r2, r2, #8
175 .endr
176 #ifdef __ARMEB__
177         rev     r2, r2                  @ Undo previous rev
178 #endif
179         @ Rotated unaligned copy loop.  The tail of the prologue is
180         @ shared with the loop itself.
181         .balign 8
182 1:      mvns    r5, r5                  @ EOS in second word?
183         bne     4f
184         @ Combine first and second words
185         orr     r2, r2, r3, lsh_gt #(\unalign*8)
186         @ Save leftover bytes from the two words
187         lsh_ls  r6, r3, #((4-\unalign)*8)
188         sfi_breg r0, \
189         str     r2, [\B], #4
190         @ The "real" start of the unaligned copy loop.
191         sfi_breg r1, \
192         ldrd    r2, r3, [\B], #8        @ Load 8 more bytes
193         uqsub8  r4, r7, r2              @ Find EOS
194         sfi_pld r1, #128
195         uqsub8  r5, r7, r3
196         sfi_pld r0, #128
197         mvns    r4, r4                  @ EOS in first word?
198         bne     3f
199         @ Combine the leftover and the first word
200         orr     r6, r6, r2, lsh_gt #(\unalign*8)
201         @ Discard used bytes from the first word.
202         lsh_ls  r2, r2, #((4-\unalign)*8)
203         sfi_breg r0, \
204         str     r6, [\B], #4
205         b       1b
206         @ Found EOS in one of the words; adjust backward
207 3:      sub     r1, r1, #4
208         mov     r2, r6
209 4:      sub     r1, r1, #4
210         @ And store the remaining bytes from the leftover
211 #ifdef __ARMEB__
212         rev     r2, r2
213 #endif
214 .rept   \unalign
215         sfi_breg r0, \
216         strb    r2, [\B], #1
217         lsr     r2, r2, #8
218 .endr
219         b       .Lbyte_loop
220 .endm
222 .Lunaligned1:
223         unaligned_copy  1
224 .Lunaligned2:
225         unaligned_copy  2
226 .Lunaligned3:
227         unaligned_copy  3
229 END (strcpy)
231 libc_hidden_builtin_def (strcpy)