1 /* Copyright (C) 2006-2023 Free Software Foundation, Inc.
2 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 <https://www.gnu.org/licenses/>. */
19 /* Thumb requires excessive IT insns here. */
22 #include <arm-features.h>
25 * Data preload for architectures that support it (ARM V5TE and above)
27 #if (!defined (__ARM_ARCH_2__) && !defined (__ARM_ARCH_3__) \
28 && !defined (__ARM_ARCH_3M__) && !defined (__ARM_ARCH_4__) \
29 && !defined (__ARM_ARCH_4T__) && !defined (__ARM_ARCH_5__) \
30 && !defined (__ARM_ARCH_5T__))
31 #define PLD(code...) code
37 * This can be used to enable code to cacheline align the source pointer.
38 * Experiments on tested architectures (StrongARM and XScale) didn't show
39 * this a worthwhile thing to do. That might be different in the future.
41 //#define CALGN(code...) code
42 #define CALGN(code...)
45 * Endian independent macros for shifting bytes within registers.
59 * Prototype: void *memmove(void *dest, const void *src, size_t n);
63 * If the memory regions don't overlap, we simply branch to memcpy which is
64 * normally a bit faster. Otherwise the copy is done going downwards.
74 bls HIDDEN_JUMPTARGET(memcpy)
78 cfi_adjust_cfa_offset (12)
79 cfi_rel_offset (r4, 4)
80 cfi_rel_offset (lr, 8)
96 cfi_adjust_cfa_offset (16)
97 cfi_rel_offset (r5, 0)
98 cfi_rel_offset (r6, 4)
99 cfi_rel_offset (r7, 8)
100 cfi_rel_offset (r8, 12)
103 CALGN( ands ip, r1, #31 )
104 CALGN( sbcsne r4, ip, r2 ) @ C is always set here
107 CALGN( subs r2, r2, ip ) @ C is set here
108 #ifndef ARM_ALWAYS_BX
109 CALGN( add pc, r4, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2))
111 CALGN( add r4, r4, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2))
116 2: PLD( cmp r2, #96 )
117 PLD( pld [r1, #-32] )
119 PLD( pld [r1, #-64] )
120 PLD( pld [r1, #-96] )
122 3: PLD( pld [r1, #-128] )
123 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
125 stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
130 #ifndef ARM_ALWAYS_BX
131 /* C is always clear here. */
132 addne pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
137 cfi_adjust_cfa_offset (4)
138 cfi_rel_offset (r10, 0)
139 0: add r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
140 /* If alignment is not perfect, then there will be some
141 padding (nop) instructions between this BX and label 6.
142 The computation above assumed that two instructions
143 later is exactly the right spot. */
144 add r10, #(6f - (0b + PC_OFS))
147 .p2align ARM_BX_ALIGN_LOG2
149 .p2align ARM_BX_ALIGN_LOG2
151 .p2align ARM_BX_ALIGN_LOG2
153 .p2align ARM_BX_ALIGN_LOG2
155 .p2align ARM_BX_ALIGN_LOG2
157 .p2align ARM_BX_ALIGN_LOG2
159 .p2align ARM_BX_ALIGN_LOG2
161 .p2align ARM_BX_ALIGN_LOG2
164 #ifndef ARM_ALWAYS_BX
165 add pc, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
168 0: add r10, pc, ip, lsl #(ARM_BX_ALIGN_LOG2 - 2)
169 /* If alignment is not perfect, then there will be some
170 padding (nop) instructions between this BX and label 66.
171 The computation above assumed that two instructions
172 later is exactly the right spot. */
173 add r10, #(66f - (0b + PC_OFS))
176 .p2align ARM_BX_ALIGN_LOG2
178 .p2align ARM_BX_ALIGN_LOG2
180 .p2align ARM_BX_ALIGN_LOG2
182 .p2align ARM_BX_ALIGN_LOG2
184 .p2align ARM_BX_ALIGN_LOG2
186 .p2align ARM_BX_ALIGN_LOG2
188 .p2align ARM_BX_ALIGN_LOG2
190 .p2align ARM_BX_ALIGN_LOG2
195 cfi_adjust_cfa_offset (-4)
202 cfi_adjust_cfa_offset (-16)
208 8: movs r2, r2, lsl #31
209 ldrbne r3, [r1, #-1]!
210 ldrbcs r4, [r1, #-1]!
212 strbne r3, [r0, #-1]!
213 strbcs r4, [r0, #-1]!
216 #if ((defined (__ARM_ARCH_4T__) && defined (__THUMB_INTERWORK__)) \
217 || defined (ARM_ALWAYS_BX))
219 cfi_adjust_cfa_offset (-12)
230 ldrbgt r3, [r1, #-1]!
231 ldrbge r4, [r1, #-1]!
233 strbgt r3, [r0, #-1]!
234 strbge r4, [r0, #-1]!
248 .macro backward_copy_shift push pull
253 CALGN( ands ip, r1, #31 )
254 CALGN( rsb ip, ip, #32 )
255 CALGN( sbcsne r4, ip, r2 ) @ C is always set here
256 CALGN( subcc r2, r2, ip )
259 11: push {r5 - r8, r10}
260 cfi_adjust_cfa_offset (20)
261 cfi_rel_offset (r5, 0)
262 cfi_rel_offset (r6, 4)
263 cfi_rel_offset (r7, 8)
264 cfi_rel_offset (r8, 12)
265 cfi_rel_offset (r10, 16)
269 PLD( pld [r1, #-32] )
271 PLD( pld [r1, #-64] )
272 PLD( pld [r1, #-96] )
274 12: PLD( pld [r1, #-128] )
275 13: ldmdb r1!, {r7, r8, r10, ip}
276 mov lr, r3, PUSH #\push
278 ldmdb r1!, {r3, r4, r5, r6}
279 orr lr, lr, ip, PULL #\pull
280 mov ip, ip, PUSH #\push
281 orr ip, ip, r10, PULL #\pull
282 mov r10, r10, PUSH #\push
283 orr r10, r10, r8, PULL #\pull
284 mov r8, r8, PUSH #\push
285 orr r8, r8, r7, PULL #\pull
286 mov r7, r7, PUSH #\push
287 orr r7, r7, r6, PULL #\pull
288 mov r6, r6, PUSH #\push
289 orr r6, r6, r5, PULL #\pull
290 mov r5, r5, PUSH #\push
291 orr r5, r5, r4, PULL #\pull
292 mov r4, r4, PUSH #\push
293 orr r4, r4, r3, PULL #\pull
294 stmdb r0!, {r4 - r8, r10, ip, lr}
298 cfi_adjust_cfa_offset (-20)
308 15: mov lr, r3, PUSH #\push
311 orr lr, lr, r3, PULL #\pull
317 16: add r1, r1, #(\pull / 8)
323 backward_copy_shift push=8 pull=24
325 17: backward_copy_shift push=16 pull=16
327 18: backward_copy_shift push=24 pull=8
331 libc_hidden_builtin_def (memmove)