ARM_BX_ALIGN_LOG2
[jlayton/glibc.git] / ports / sysdeps / arm / memmove.S
1 /* Copyright (C) 2006-2013 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    Contributed by MontaVista Software, Inc. (written by Nicolas Pitre)
5
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.
10
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.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library.  If not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 /* Thumb requires excessive IT insns here.  */
21 #define NO_THUMB
22 #include <sysdep.h>
23 #include <arm-features.h>
24
25 /*
26  * Data preload for architectures that support it (ARM V5TE and above)
27  */
28 #if (!defined (__ARM_ARCH_2__) && !defined (__ARM_ARCH_3__) \
29      && !defined (__ARM_ARCH_3M__) && !defined (__ARM_ARCH_4__) \
30      && !defined (__ARM_ARCH_4T__) && !defined (__ARM_ARCH_5__) \
31      && !defined (__ARM_ARCH_5T__))
32 #define PLD(code...)    code
33 #else
34 #define PLD(code...)
35 #endif
36
37 /*
38  * This can be used to enable code to cacheline align the source pointer.
39  * Experiments on tested architectures (StrongARM and XScale) didn't show
40  * this a worthwhile thing to do.  That might be different in the future.
41  */
42 //#define CALGN(code...)        code
43 #define CALGN(code...)
44
45 /*
46  * Endian independent macros for shifting bytes within registers.
47  */
48 #ifndef __ARMEB__
49 #define PULL            lsr
50 #define PUSH            lsl
51 #else
52 #define PULL            lsl
53 #define PUSH            lsr
54 #endif
55
56                 .text
57                 .syntax unified
58
59 /*
60  * Prototype: void *memmove(void *dest, const void *src, size_t n);
61  *
62  * Note:
63  *
64  * If the memory regions don't overlap, we simply branch to memcpy which is
65  * normally a bit faster. Otherwise the copy is done going downwards.
66  */
67
68 ENTRY(memmove)
69
70                 subs    ip, r0, r1
71                 cmphi   r2, ip
72 #ifdef NOT_IN_libc
73                 bls     memcpy
74 #else
75                 bls     HIDDEN_JUMPTARGET(memcpy)
76 #endif
77
78                 push    {r0, r4, lr}
79                 cfi_adjust_cfa_offset (12)
80                 cfi_rel_offset (r4, 4)
81                 cfi_rel_offset (lr, 8)
82
83                 cfi_remember_state
84
85                 add     r1, r1, r2
86                 add     r0, r0, r2
87                 subs    r2, r2, #4
88                 blt     8f
89                 ands    ip, r0, #3
90         PLD(    pld     [r1, #-4]               )
91                 bne     9f
92                 ands    ip, r1, #3
93                 bne     10f
94
95 1:              subs    r2, r2, #(28)
96                 push    {r5 - r8}
97                 cfi_adjust_cfa_offset (16)
98                 cfi_rel_offset (r5, 0)
99                 cfi_rel_offset (r6, 4)
100                 cfi_rel_offset (r7, 8)
101                 cfi_rel_offset (r8, 12)
102                 blt     5f
103
104         CALGN(  ands    ip, r1, #31             )
105         CALGN(  sbcsne  r4, ip, r2              )  @ C is always set here
106         CALGN(  bcs     2f                      )
107         CALGN(  adr     r4, 6f                  )
108         CALGN(  subs    r2, r2, ip              )  @ C is set here
109 #ifndef ARM_ALWAYS_BX
110         CALGN(  add     pc, r4, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2))
111 #else
112         CALGN(  add     r4, r4, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2))
113         CALGN(  bx      r4                      )
114 #endif
115
116         PLD(    pld     [r1, #-4]               )
117 2:      PLD(    subs    r2, r2, #96             )
118         PLD(    pld     [r1, #-32]              )
119         PLD(    blt     4f                      )
120         PLD(    pld     [r1, #-64]              )
121         PLD(    pld     [r1, #-96]              )
122
123 3:      PLD(    pld     [r1, #-128]             )
124 4:              ldmdb   r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
125                 subs    r2, r2, #32
126                 stmdb   r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
127                 bge     3b
128         PLD(    cmn     r2, #96                 )
129         PLD(    bge     4b                      )
130
131 5:              ands    ip, r2, #28
132                 rsb     ip, ip, #32
133 #ifndef ARM_ALWAYS_BX
134                 /* C is always clear here.  */
135                 addne   pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
136                 b       7f
137 #else
138                 beq     7f
139                 push    {r10}
140                 cfi_adjust_cfa_offset (4)
141                 cfi_rel_offset (r10, 0)
142                 add     r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
143                 bx      r10
144 #endif
145                 .p2align ARM_BX_ALIGN_LOG2
146 6:              nop
147                 .p2align ARM_BX_ALIGN_LOG2
148                 ldr     r3, [r1, #-4]!
149                 .p2align ARM_BX_ALIGN_LOG2
150                 ldr     r4, [r1, #-4]!
151                 .p2align ARM_BX_ALIGN_LOG2
152                 ldr     r5, [r1, #-4]!
153                 .p2align ARM_BX_ALIGN_LOG2
154                 ldr     r6, [r1, #-4]!
155                 .p2align ARM_BX_ALIGN_LOG2
156                 ldr     r7, [r1, #-4]!
157                 .p2align ARM_BX_ALIGN_LOG2
158                 ldr     r8, [r1, #-4]!
159                 .p2align ARM_BX_ALIGN_LOG2
160                 ldr     lr, [r1, #-4]!
161
162 #ifndef ARM_ALWAYS_BX
163                 add     pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
164                 nop
165 #else
166                 add     r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
167                 bx      r10
168 #endif
169                 .p2align ARM_BX_ALIGN_LOG2
170                 nop
171                 .p2align ARM_BX_ALIGN_LOG2
172                 str     r3, [r0, #-4]!
173                 .p2align ARM_BX_ALIGN_LOG2
174                 str     r4, [r0, #-4]!
175                 .p2align ARM_BX_ALIGN_LOG2
176                 str     r5, [r0, #-4]!
177                 .p2align ARM_BX_ALIGN_LOG2
178                 str     r6, [r0, #-4]!
179                 .p2align ARM_BX_ALIGN_LOG2
180                 str     r7, [r0, #-4]!
181                 .p2align ARM_BX_ALIGN_LOG2
182                 str     r8, [r0, #-4]!
183                 .p2align ARM_BX_ALIGN_LOG2
184                 str     lr, [r0, #-4]!
185
186 #ifdef ARM_ALWAYS_BX
187                 pop     {r10}
188                 cfi_adjust_cfa_offset (-4)
189                 cfi_restore (r10)
190 #endif
191
192         CALGN(  bcs     2b                      )
193
194 7:              pop     {r5 - r8}
195                 cfi_adjust_cfa_offset (-16)
196                 cfi_restore (r5)
197                 cfi_restore (r6)
198                 cfi_restore (r7)
199                 cfi_restore (r8)
200
201 8:              movs    r2, r2, lsl #31
202                 ldrbne  r3, [r1, #-1]!
203                 ldrbcs  r4, [r1, #-1]!
204                 ldrbcs  ip, [r1, #-1]
205                 strbne  r3, [r0, #-1]!
206                 strbcs  r4, [r0, #-1]!
207                 strbcs  ip, [r0, #-1]
208
209 #if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \
210      || defined (ARM_ALWAYS_BX))
211                 pop     {r0, r4, lr}
212                 cfi_adjust_cfa_offset (-12)
213                 cfi_restore (r4)
214                 cfi_restore (lr)
215                 bx      lr
216 #else
217                 pop     {r0, r4, pc}
218 #endif
219
220                 cfi_restore_state
221
222 9:              cmp     ip, #2
223                 ldrbgt  r3, [r1, #-1]!
224                 ldrbge  r4, [r1, #-1]!
225                 ldrb    lr, [r1, #-1]!
226                 strbgt  r3, [r0, #-1]!
227                 strbge  r4, [r0, #-1]!
228                 subs    r2, r2, ip
229                 strb    lr, [r0, #-1]!
230                 blt     8b
231                 ands    ip, r1, #3
232                 beq     1b
233
234 10:             bic     r1, r1, #3
235                 cmp     ip, #2
236                 ldr     r3, [r1, #0]
237                 beq     17f
238                 blt     18f
239
240
241                 .macro  backward_copy_shift push pull
242
243                 subs    r2, r2, #28
244                 blt     14f
245
246         CALGN(  ands    ip, r1, #31             )
247         CALGN(  rsb     ip, ip, #32             )
248         CALGN(  sbcsne  r4, ip, r2              )  @ C is always set here
249         CALGN(  subcc   r2, r2, ip              )
250         CALGN(  bcc     15f                     )
251
252 11:             push    {r5 - r8, r10}
253                 cfi_adjust_cfa_offset (20)
254                 cfi_rel_offset (r5, 0)
255                 cfi_rel_offset (r6, 4)
256                 cfi_rel_offset (r7, 8)
257                 cfi_rel_offset (r8, 12)
258                 cfi_rel_offset (r10, 16)
259
260         PLD(    pld     [r1, #-4]               )
261         PLD(    subs    r2, r2, #96             )
262         PLD(    pld     [r1, #-32]              )
263         PLD(    blt     13f                     )
264         PLD(    pld     [r1, #-64]              )
265         PLD(    pld     [r1, #-96]              )
266
267 12:     PLD(    pld     [r1, #-128]             )
268 13:             ldmdb   r1!, {r7, r8, r10, ip}
269                 mov     lr, r3, PUSH #\push
270                 subs    r2, r2, #32
271                 ldmdb   r1!, {r3, r4, r5, r6}
272                 orr     lr, lr, ip, PULL #\pull
273                 mov     ip, ip, PUSH #\push
274                 orr     ip, ip, r10, PULL #\pull
275                 mov     r10, r10, PUSH #\push
276                 orr     r10, r10, r8, PULL #\pull
277                 mov     r8, r8, PUSH #\push
278                 orr     r8, r8, r7, PULL #\pull
279                 mov     r7, r7, PUSH #\push
280                 orr     r7, r7, r6, PULL #\pull
281                 mov     r6, r6, PUSH #\push
282                 orr     r6, r6, r5, PULL #\pull
283                 mov     r5, r5, PUSH #\push
284                 orr     r5, r5, r4, PULL #\pull
285                 mov     r4, r4, PUSH #\push
286                 orr     r4, r4, r3, PULL #\pull
287                 stmdb   r0!, {r4 - r8, r10, ip, lr}
288                 bge     12b
289         PLD(    cmn     r2, #96                 )
290         PLD(    bge     13b                     )
291
292                 pop     {r5 - r8, r10}
293                 cfi_adjust_cfa_offset (-20)
294                 cfi_restore (r5)
295                 cfi_restore (r6)
296                 cfi_restore (r7)
297                 cfi_restore (r8)
298                 cfi_restore (r10)
299
300 14:             ands    ip, r2, #28
301                 beq     16f
302
303 15:             mov     lr, r3, PUSH #\push
304                 ldr     r3, [r1, #-4]!
305                 subs    ip, ip, #4
306                 orr     lr, lr, r3, PULL #\pull
307                 str     lr, [r0, #-4]!
308                 bgt     15b
309         CALGN(  cmp     r2, #0                  )
310         CALGN(  bge     11b                     )
311
312 16:             add     r1, r1, #(\pull / 8)
313                 b       8b
314
315                 .endm
316
317
318                 backward_copy_shift     push=8  pull=24
319
320 17:             backward_copy_shift     push=16 pull=16
321
322 18:             backward_copy_shift     push=24 pull=8
323
324
325 END(memmove)
326 libc_hidden_builtin_def (memmove)