1 /* Copyright (C) 2006-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 Contributed by MontaVista Software, Inc. (written by Nicolas Pitre)
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, see
18 <http://www.gnu.org/licenses/>. */
20 /* Thumb requires excessive IT insns here. */
23 #include <arm-features.h>
26 * Data preload for architectures that support it (ARM V5TE and above)
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
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.
42 //#define CALGN(code...) code
43 #define CALGN(code...)
46 * Endian independent macros for shifting bytes within registers.
60 * Prototype: void *memmove(void *dest, const void *src, size_t n);
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.
75 bls HIDDEN_JUMPTARGET(memcpy)
79 cfi_adjust_cfa_offset (12)
80 cfi_rel_offset (r4, 4)
81 cfi_rel_offset (lr, 8)
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)
104 CALGN( ands ip, r1, #31 )
105 CALGN( sbcsne r4, ip, r2 ) @ C is always set here
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))
112 CALGN( add r4, r4, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2))
117 2: PLD( subs r2, r2, #96 )
118 PLD( pld [r1, #-32] )
120 PLD( pld [r1, #-64] )
121 PLD( pld [r1, #-96] )
123 3: PLD( pld [r1, #-128] )
124 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
126 stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
133 #ifndef ARM_ALWAYS_BX
134 /* C is always clear here. */
135 addne pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
140 cfi_adjust_cfa_offset (4)
141 cfi_rel_offset (r10, 0)
142 0: add r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
143 /* If alignment is not perfect, then there will be some
144 padding (nop) instructions between this BX and label 6.
145 The computation above assumed that two instructions
146 later is exactly the right spot. */
147 add r10, #(6f - (0b + PC_OFS))
150 .p2align ARM_BX_ALIGN_LOG2
152 .p2align ARM_BX_ALIGN_LOG2
154 .p2align ARM_BX_ALIGN_LOG2
156 .p2align ARM_BX_ALIGN_LOG2
158 .p2align ARM_BX_ALIGN_LOG2
160 .p2align ARM_BX_ALIGN_LOG2
162 .p2align ARM_BX_ALIGN_LOG2
164 .p2align ARM_BX_ALIGN_LOG2
167 #ifndef ARM_ALWAYS_BX
168 add pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
171 0: add r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
172 /* If alignment is not perfect, then there will be some
173 padding (nop) instructions between this BX and label 66.
174 The computation above assumed that two instructions
175 later is exactly the right spot. */
176 add r10, #(66f - (0b + PC_OFS))
179 .p2align ARM_BX_ALIGN_LOG2
181 .p2align ARM_BX_ALIGN_LOG2
183 .p2align ARM_BX_ALIGN_LOG2
185 .p2align ARM_BX_ALIGN_LOG2
187 .p2align ARM_BX_ALIGN_LOG2
189 .p2align ARM_BX_ALIGN_LOG2
191 .p2align ARM_BX_ALIGN_LOG2
193 .p2align ARM_BX_ALIGN_LOG2
198 cfi_adjust_cfa_offset (-4)
205 cfi_adjust_cfa_offset (-16)
211 8: movs r2, r2, lsl #31
212 ldrbne r3, [r1, #-1]!
213 ldrbcs r4, [r1, #-1]!
215 strbne r3, [r0, #-1]!
216 strbcs r4, [r0, #-1]!
219 #if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \
220 || defined (ARM_ALWAYS_BX))
222 cfi_adjust_cfa_offset (-12)
233 ldrbgt r3, [r1, #-1]!
234 ldrbge r4, [r1, #-1]!
236 strbgt r3, [r0, #-1]!
237 strbge r4, [r0, #-1]!
251 .macro backward_copy_shift push pull
256 CALGN( ands ip, r1, #31 )
257 CALGN( rsb ip, ip, #32 )
258 CALGN( sbcsne r4, ip, r2 ) @ C is always set here
259 CALGN( subcc r2, r2, ip )
262 11: push {r5 - r8, r10}
263 cfi_adjust_cfa_offset (20)
264 cfi_rel_offset (r5, 0)
265 cfi_rel_offset (r6, 4)
266 cfi_rel_offset (r7, 8)
267 cfi_rel_offset (r8, 12)
268 cfi_rel_offset (r10, 16)
271 PLD( subs r2, r2, #96 )
272 PLD( pld [r1, #-32] )
274 PLD( pld [r1, #-64] )
275 PLD( pld [r1, #-96] )
277 12: PLD( pld [r1, #-128] )
278 13: ldmdb r1!, {r7, r8, r10, ip}
279 mov lr, r3, PUSH #\push
281 ldmdb r1!, {r3, r4, r5, r6}
282 orr lr, lr, ip, PULL #\pull
283 mov ip, ip, PUSH #\push
284 orr ip, ip, r10, PULL #\pull
285 mov r10, r10, PUSH #\push
286 orr r10, r10, r8, PULL #\pull
287 mov r8, r8, PUSH #\push
288 orr r8, r8, r7, PULL #\pull
289 mov r7, r7, PUSH #\push
290 orr r7, r7, r6, PULL #\pull
291 mov r6, r6, PUSH #\push
292 orr r6, r6, r5, PULL #\pull
293 mov r5, r5, PUSH #\push
294 orr r5, r5, r4, PULL #\pull
295 mov r4, r4, PUSH #\push
296 orr r4, r4, r3, PULL #\pull
297 stmdb r0!, {r4 - r8, r10, ip, lr}
303 cfi_adjust_cfa_offset (-20)
313 15: mov lr, r3, PUSH #\push
316 orr lr, lr, r3, PULL #\pull
322 16: add r1, r1, #(\pull / 8)
328 backward_copy_shift push=8 pull=24
330 17: backward_copy_shift push=16 pull=16
332 18: backward_copy_shift push=24 pull=8
336 libc_hidden_builtin_def (memmove)