xref: /freebsd-13-stable/lib/libc/arm/string/memmove.S (revision 3d497e17ebd33fe0f58d773e35ab994d750258d6)
1/*	$NetBSD: memmove.S,v 1.4 2003/10/14 07:51:45 scw Exp $	*/
2
3/*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Neil A. Carson and Mark Brinicombe
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <machine/asm.h>
33.syntax	unified
34
35#ifndef _BCOPY
36/* LINTSTUB: Func: void *memmove(void *, const void *, size_t) */
37ENTRY(memmove)
38#else
39/* bcopy = memcpy/memmove with arguments reversed. */
40/* LINTSTUB: Func: void bcopy(void *, void *, size_t) */
41ENTRY(bcopy)
42	/* switch the source and destination registers */
43	eor     r0, r1, r0
44	eor     r1, r0, r1
45	eor     r0, r1, r0
46#endif
47	/* Do the buffers overlap? */
48	cmp	r0, r1
49	it	eq
50	RETeq		/* Bail now if src/dst are the same */
51	ite	cc
52	subcc	r3, r0, r1	/* if (dst > src) r3 = dst - src */
53	subcs	r3, r1, r0	/* if (src > dsr) r3 = src - dst */
54	cmp	r3, r2		/* if (r3 < len) we have an overlap */
55	bcc	PIC_SYM(_C_LABEL(memcpy), PLT)
56
57	/* Determine copy direction */
58	cmp	r1, r0
59	it	cc
60	bcc	.Lmemmove_backwards
61
62	itt	eq
63	moveq	r0, #0			/* Quick abort for len=0 */
64	RETeq
65
66	stmdb	sp!, {r0, lr}		/* memmove() returns dest addr */
67	subs	r2, r2, #4
68	blt	.Lmemmove_fl4		/* less than 4 bytes */
69	ands	r12, r0, #3
70	bne	.Lmemmove_fdestul	/* oh unaligned destination addr */
71	ands	r12, r1, #3
72	bne	.Lmemmove_fsrcul		/* oh unaligned source addr */
73
74.Lmemmove_ft8:
75	/* We have aligned source and destination */
76	subs	r2, r2, #8
77	blt	.Lmemmove_fl12		/* less than 12 bytes (4 from above) */
78	subs	r2, r2, #0x14
79	blt	.Lmemmove_fl32		/* less than 32 bytes (12 from above) */
80	stmdb	sp!, {r4}		/* borrow r4 */
81
82	/* blat 32 bytes at a time */
83	/* XXX for really big copies perhaps we should use more registers */
84.Lmemmove_floop32:
85	ldmia	r1!, {r3, r4, r12, lr}
86	stmia	r0!, {r3, r4, r12, lr}
87	ldmia	r1!, {r3, r4, r12, lr}
88	stmia	r0!, {r3, r4, r12, lr}
89	subs	r2, r2, #0x20
90	bge	.Lmemmove_floop32
91
92	cmn	r2, #0x10
93	ittt	ge
94	ldmiage	r1!, {r3, r4, r12, lr}	/* blat a remaining 16 bytes */
95	stmiage	r0!, {r3, r4, r12, lr}
96	subge	r2, r2, #0x10
97	ldmia	sp!, {r4}		/* return r4 */
98
99.Lmemmove_fl32:
100	adds	r2, r2, #0x14
101
102	/* blat 12 bytes at a time */
103.Lmemmove_floop12:
104	ittt	ge
105	ldmiage	r1!, {r3, r12, lr}
106	stmiage	r0!, {r3, r12, lr}
107	subsge	r2, r2, #0x0c
108	bge	.Lmemmove_floop12
109
110.Lmemmove_fl12:
111	adds	r2, r2, #8
112	blt	.Lmemmove_fl4
113
114	subs	r2, r2, #4
115	itt	lt
116	ldrlt	r3, [r1], #4
117	strlt	r3, [r0], #4
118	ittt	ge
119	ldmiage	r1!, {r3, r12}
120	stmiage	r0!, {r3, r12}
121	subge	r2, r2, #4
122
123.Lmemmove_fl4:
124	/* less than 4 bytes to go */
125	adds	r2, r2, #4
126	it	eq
127	ldmiaeq	sp!, {r0, pc}		/* done */
128
129	/* copy the crud byte at a time */
130	cmp	r2, #2
131	ldrb	r3, [r1], #1
132	strb	r3, [r0], #1
133	itt	ge
134	ldrbge	r3, [r1], #1
135	strbge	r3, [r0], #1
136	itt	gt
137	ldrbgt	r3, [r1], #1
138	strbgt	r3, [r0], #1
139	ldmia	sp!, {r0, pc}
140
141	/* erg - unaligned destination */
142.Lmemmove_fdestul:
143	rsb	r12, r12, #4
144	cmp	r12, #2
145
146	/* align destination with byte copies */
147	ldrb	r3, [r1], #1
148	strb	r3, [r0], #1
149	itt	ge
150	ldrbge	r3, [r1], #1
151	strbge	r3, [r0], #1
152	itt	gt
153	ldrbgt	r3, [r1], #1
154	strbgt	r3, [r0], #1
155	subs	r2, r2, r12
156	blt	.Lmemmove_fl4		/* less the 4 bytes */
157
158	ands	r12, r1, #3
159	beq	.Lmemmove_ft8		/* we have an aligned source */
160
161	/* erg - unaligned source */
162	/* This is where it gets nasty ... */
163.Lmemmove_fsrcul:
164	bic	r1, r1, #3
165	ldr	lr, [r1], #4
166	cmp	r12, #2
167	bgt	.Lmemmove_fsrcul3
168	beq	.Lmemmove_fsrcul2
169	cmp	r2, #0x0c
170	blt	.Lmemmove_fsrcul1loop4
171	sub	r2, r2, #0x0c
172	stmdb	sp!, {r4, r5}
173
174.Lmemmove_fsrcul1loop16:
175#ifdef __ARMEB__
176	mov	r3, lr, lsl #8
177#else
178	mov	r3, lr, lsr #8
179#endif
180	ldmia	r1!, {r4, r5, r12, lr}
181#ifdef __ARMEB__
182	orr	r3, r3, r4, lsr #24
183	mov	r4, r4, lsl #8
184	orr	r4, r4, r5, lsr #24
185	mov	r5, r5, lsl #8
186	orr	r5, r5, r12, lsr #24
187	mov	r12, r12, lsl #8
188	orr	r12, r12, lr, lsr #24
189#else
190	orr	r3, r3, r4, lsl #24
191	mov	r4, r4, lsr #8
192	orr	r4, r4, r5, lsl #24
193	mov	r5, r5, lsr #8
194	orr	r5, r5, r12, lsl #24
195	mov	r12, r12, lsr #8
196	orr	r12, r12, lr, lsl #24
197#endif
198	stmia	r0!, {r3-r5, r12}
199	subs	r2, r2, #0x10
200	bge	.Lmemmove_fsrcul1loop16
201	ldmia	sp!, {r4, r5}
202	adds	r2, r2, #0x0c
203	blt	.Lmemmove_fsrcul1l4
204
205.Lmemmove_fsrcul1loop4:
206#ifdef __ARMEB__
207	mov	r12, lr, lsl #8
208#else
209	mov	r12, lr, lsr #8
210#endif
211	ldr	lr, [r1], #4
212#ifdef __ARMEB__
213	orr	r12, r12, lr, lsr #24
214#else
215	orr	r12, r12, lr, lsl #24
216#endif
217	str	r12, [r0], #4
218	subs	r2, r2, #4
219	bge	.Lmemmove_fsrcul1loop4
220
221.Lmemmove_fsrcul1l4:
222	sub	r1, r1, #3
223	b	.Lmemmove_fl4
224
225.Lmemmove_fsrcul2:
226	cmp	r2, #0x0c
227	blt	.Lmemmove_fsrcul2loop4
228	sub	r2, r2, #0x0c
229	stmdb	sp!, {r4, r5}
230
231.Lmemmove_fsrcul2loop16:
232#ifdef __ARMEB__
233	mov	r3, lr, lsl #16
234#else
235	mov	r3, lr, lsr #16
236#endif
237	ldmia	r1!, {r4, r5, r12, lr}
238#ifdef __ARMEB__
239	orr	r3, r3, r4, lsr #16
240	mov	r4, r4, lsl #16
241	orr	r4, r4, r5, lsr #16
242	mov	r5, r5, lsl #16
243	orr	r5, r5, r12, lsr #16
244	mov	r12, r12, lsl #16
245	orr	r12, r12, lr, lsr #16
246#else
247	orr	r3, r3, r4, lsl #16
248	mov	r4, r4, lsr #16
249	orr	r4, r4, r5, lsl #16
250	mov	r5, r5, lsr #16
251	orr	r5, r5, r12, lsl #16
252	mov	r12, r12, lsr #16
253	orr	r12, r12, lr, lsl #16
254#endif
255	stmia	r0!, {r3-r5, r12}
256	subs	r2, r2, #0x10
257	bge	.Lmemmove_fsrcul2loop16
258	ldmia	sp!, {r4, r5}
259	adds	r2, r2, #0x0c
260	blt	.Lmemmove_fsrcul2l4
261
262.Lmemmove_fsrcul2loop4:
263#ifdef __ARMEB__
264	mov	r12, lr, lsl #16
265#else
266	mov	r12, lr, lsr #16
267#endif
268	ldr	lr, [r1], #4
269#ifdef __ARMEB__
270	orr	r12, r12, lr, lsr #16
271#else
272	orr	r12, r12, lr, lsl #16
273#endif
274	str	r12, [r0], #4
275	subs	r2, r2, #4
276	bge	.Lmemmove_fsrcul2loop4
277
278.Lmemmove_fsrcul2l4:
279	sub	r1, r1, #2
280	b	.Lmemmove_fl4
281
282.Lmemmove_fsrcul3:
283	cmp	r2, #0x0c
284	blt	.Lmemmove_fsrcul3loop4
285	sub	r2, r2, #0x0c
286	stmdb	sp!, {r4, r5}
287
288.Lmemmove_fsrcul3loop16:
289#ifdef __ARMEB__
290	mov	r3, lr, lsl #24
291#else
292	mov	r3, lr, lsr #24
293#endif
294	ldmia	r1!, {r4, r5, r12, lr}
295#ifdef __ARMEB__
296	orr	r3, r3, r4, lsr #8
297	mov	r4, r4, lsl #24
298	orr	r4, r4, r5, lsr #8
299	mov	r5, r5, lsl #24
300	orr	r5, r5, r12, lsr #8
301	mov	r12, r12, lsl #24
302	orr	r12, r12, lr, lsr #8
303#else
304	orr	r3, r3, r4, lsl #8
305	mov	r4, r4, lsr #24
306	orr	r4, r4, r5, lsl #8
307	mov	r5, r5, lsr #24
308	orr	r5, r5, r12, lsl #8
309	mov	r12, r12, lsr #24
310	orr	r12, r12, lr, lsl #8
311#endif
312	stmia	r0!, {r3-r5, r12}
313	subs	r2, r2, #0x10
314	bge	.Lmemmove_fsrcul3loop16
315	ldmia	sp!, {r4, r5}
316	adds	r2, r2, #0x0c
317	blt	.Lmemmove_fsrcul3l4
318
319.Lmemmove_fsrcul3loop4:
320#ifdef __ARMEB__
321	mov	r12, lr, lsl #24
322#else
323	mov	r12, lr, lsr #24
324#endif
325	ldr	lr, [r1], #4
326#ifdef __ARMEB__
327	orr	r12, r12, lr, lsr #8
328#else
329	orr	r12, r12, lr, lsl #8
330#endif
331	str	r12, [r0], #4
332	subs	r2, r2, #4
333	bge	.Lmemmove_fsrcul3loop4
334
335.Lmemmove_fsrcul3l4:
336	sub	r1, r1, #1
337	b	.Lmemmove_fl4
338
339.Lmemmove_backwards:
340	add	r1, r1, r2
341	add	r0, r0, r2
342	subs	r2, r2, #4
343	blt	.Lmemmove_bl4		/* less than 4 bytes */
344	ands	r12, r0, #3
345	bne	.Lmemmove_bdestul	/* oh unaligned destination addr */
346	ands	r12, r1, #3
347	bne	.Lmemmove_bsrcul		/* oh unaligned source addr */
348
349.Lmemmove_bt8:
350	/* We have aligned source and destination */
351	subs	r2, r2, #8
352	blt	.Lmemmove_bl12		/* less than 12 bytes (4 from above) */
353	stmdb	sp!, {r4, lr}
354	subs	r2, r2, #0x14		/* less than 32 bytes (12 from above) */
355	blt	.Lmemmove_bl32
356
357	/* blat 32 bytes at a time */
358	/* XXX for really big copies perhaps we should use more registers */
359.Lmemmove_bloop32:
360	ldmdb	r1!, {r3, r4, r12, lr}
361	stmdb	r0!, {r3, r4, r12, lr}
362	ldmdb	r1!, {r3, r4, r12, lr}
363	stmdb	r0!, {r3, r4, r12, lr}
364	subs	r2, r2, #0x20
365	bge	.Lmemmove_bloop32
366
367.Lmemmove_bl32:
368	cmn	r2, #0x10
369	ittt	ge
370	ldmdbge	r1!, {r3, r4, r12, lr}	/* blat a remaining 16 bytes */
371	stmdbge	r0!, {r3, r4, r12, lr}
372	subge	r2, r2, #0x10
373	adds	r2, r2, #0x14
374	ittt	ge
375	ldmdbge	r1!, {r3, r12, lr}	/* blat a remaining 12 bytes */
376	stmdbge	r0!, {r3, r12, lr}
377	subge	r2, r2, #0x0c
378	ldmia	sp!, {r4, lr}
379
380.Lmemmove_bl12:
381	adds	r2, r2, #8
382	blt	.Lmemmove_bl4
383	subs	r2, r2, #4
384	itt	lt
385	ldrlt	r3, [r1, #-4]!
386	strlt	r3, [r0, #-4]!
387	ittt	ge
388	ldmdbge	r1!, {r3, r12}
389	stmdbge	r0!, {r3, r12}
390	subge	r2, r2, #4
391
392.Lmemmove_bl4:
393	/* less than 4 bytes to go */
394	adds	r2, r2, #4
395	it	eq
396	RETeq			/* done */
397
398	/* copy the crud byte at a time */
399	cmp	r2, #2
400	ldrb	r3, [r1, #-1]!
401	strb	r3, [r0, #-1]!
402	itt	ge
403	ldrbge	r3, [r1, #-1]!
404	strbge	r3, [r0, #-1]!
405	itt	gt
406	ldrbgt	r3, [r1, #-1]!
407	strbgt	r3, [r0, #-1]!
408	RET
409
410	/* erg - unaligned destination */
411.Lmemmove_bdestul:
412	cmp	r12, #2
413
414	/* align destination with byte copies */
415	ldrb	r3, [r1, #-1]!
416	strb	r3, [r0, #-1]!
417	itt	ge
418	ldrbge	r3, [r1, #-1]!
419	strbge	r3, [r0, #-1]!
420	itt	gt
421	ldrbgt	r3, [r1, #-1]!
422	strbgt	r3, [r0, #-1]!
423	subs	r2, r2, r12
424	blt	.Lmemmove_bl4		/* less than 4 bytes to go */
425	ands	r12, r1, #3
426	beq	.Lmemmove_bt8		/* we have an aligned source */
427
428	/* erg - unaligned source */
429	/* This is where it gets nasty ... */
430.Lmemmove_bsrcul:
431	bic	r1, r1, #3
432	ldr	r3, [r1, #0]
433	cmp	r12, #2
434	blt	.Lmemmove_bsrcul1
435	beq	.Lmemmove_bsrcul2
436	cmp	r2, #0x0c
437	blt	.Lmemmove_bsrcul3loop4
438	sub	r2, r2, #0x0c
439	stmdb	sp!, {r4, r5, lr}
440
441.Lmemmove_bsrcul3loop16:
442#ifdef __ARMEB__
443	mov	lr, r3, lsr #8
444#else
445	mov	lr, r3, lsl #8
446#endif
447	ldmdb	r1!, {r3-r5, r12}
448#ifdef __ARMEB__
449	orr	lr, lr, r12, lsl #24
450	mov	r12, r12, lsr #8
451	orr	r12, r12, r5, lsl #24
452	mov	r5, r5, lsr #8
453	orr	r5, r5, r4, lsl #24
454	mov	r4, r4, lsr #8
455	orr	r4, r4, r3, lsl #24
456#else
457	orr	lr, lr, r12, lsr #24
458	mov	r12, r12, lsl #8
459	orr	r12, r12, r5, lsr #24
460	mov	r5, r5, lsl #8
461	orr	r5, r5, r4, lsr #24
462	mov	r4, r4, lsl #8
463	orr	r4, r4, r3, lsr #24
464#endif
465	stmdb	r0!, {r4, r5, r12, lr}
466	subs	r2, r2, #0x10
467	bge	.Lmemmove_bsrcul3loop16
468	ldmia	sp!, {r4, r5, lr}
469	adds	r2, r2, #0x0c
470	blt	.Lmemmove_bsrcul3l4
471
472.Lmemmove_bsrcul3loop4:
473#ifdef __ARMEB__
474	mov	r12, r3, lsr #8
475#else
476	mov	r12, r3, lsl #8
477#endif
478	ldr	r3, [r1, #-4]!
479#ifdef __ARMEB__
480	orr	r12, r12, r3, lsl #24
481#else
482	orr	r12, r12, r3, lsr #24
483#endif
484	str	r12, [r0, #-4]!
485	subs	r2, r2, #4
486	bge	.Lmemmove_bsrcul3loop4
487
488.Lmemmove_bsrcul3l4:
489	add	r1, r1, #3
490	b	.Lmemmove_bl4
491
492.Lmemmove_bsrcul2:
493	cmp	r2, #0x0c
494	blt	.Lmemmove_bsrcul2loop4
495	sub	r2, r2, #0x0c
496	stmdb	sp!, {r4, r5, lr}
497
498.Lmemmove_bsrcul2loop16:
499#ifdef __ARMEB__
500	mov	lr, r3, lsr #16
501#else
502	mov	lr, r3, lsl #16
503#endif
504	ldmdb	r1!, {r3-r5, r12}
505#ifdef __ARMEB__
506	orr	lr, lr, r12, lsl #16
507	mov	r12, r12, lsr #16
508	orr	r12, r12, r5, lsl #16
509	mov	r5, r5, lsr #16
510	orr	r5, r5, r4, lsl #16
511	mov	r4, r4, lsr #16
512	orr	r4, r4, r3, lsl #16
513#else
514	orr	lr, lr, r12, lsr #16
515	mov	r12, r12, lsl #16
516	orr	r12, r12, r5, lsr #16
517	mov	r5, r5, lsl #16
518	orr	r5, r5, r4, lsr #16
519	mov	r4, r4, lsl #16
520	orr	r4, r4, r3, lsr #16
521#endif
522	stmdb	r0!, {r4, r5, r12, lr}
523	subs	r2, r2, #0x10
524	bge	.Lmemmove_bsrcul2loop16
525	ldmia	sp!, {r4, r5, lr}
526	adds	r2, r2, #0x0c
527	blt	.Lmemmove_bsrcul2l4
528
529.Lmemmove_bsrcul2loop4:
530#ifdef __ARMEB__
531	mov	r12, r3, lsr #16
532#else
533	mov	r12, r3, lsl #16
534#endif
535	ldr	r3, [r1, #-4]!
536#ifdef __ARMEB__
537	orr	r12, r12, r3, lsl #16
538#else
539	orr	r12, r12, r3, lsr #16
540#endif
541	str	r12, [r0, #-4]!
542	subs	r2, r2, #4
543	bge	.Lmemmove_bsrcul2loop4
544
545.Lmemmove_bsrcul2l4:
546	add	r1, r1, #2
547	b	.Lmemmove_bl4
548
549.Lmemmove_bsrcul1:
550	cmp	r2, #0x0c
551	blt	.Lmemmove_bsrcul1loop4
552	sub	r2, r2, #0x0c
553	stmdb	sp!, {r4, r5, lr}
554
555.Lmemmove_bsrcul1loop32:
556#ifdef __ARMEB__
557	mov	lr, r3, lsr #24
558#else
559	mov	lr, r3, lsl #24
560#endif
561	ldmdb	r1!, {r3-r5, r12}
562#ifdef __ARMEB__
563	orr	lr, lr, r12, lsl #8
564	mov	r12, r12, lsr #24
565	orr	r12, r12, r5, lsl #8
566	mov	r5, r5, lsr #24
567	orr	r5, r5, r4, lsl #8
568	mov	r4, r4, lsr #24
569	orr	r4, r4, r3, lsl #8
570#else
571	orr	lr, lr, r12, lsr #8
572	mov	r12, r12, lsl #24
573	orr	r12, r12, r5, lsr #8
574	mov	r5, r5, lsl #24
575	orr	r5, r5, r4, lsr #8
576	mov	r4, r4, lsl #24
577	orr	r4, r4, r3, lsr #8
578#endif
579	stmdb	r0!, {r4, r5, r12, lr}
580	subs	r2, r2, #0x10
581	bge	.Lmemmove_bsrcul1loop32
582	ldmia	sp!, {r4, r5, lr}
583	adds	r2, r2, #0x0c
584	blt	.Lmemmove_bsrcul1l4
585
586.Lmemmove_bsrcul1loop4:
587#ifdef __ARMEB__
588	mov	r12, r3, lsr #24
589#else
590	mov	r12, r3, lsl #24
591#endif
592	ldr	r3, [r1, #-4]!
593#ifdef __ARMEB__
594	orr	r12, r12, r3, lsl #8
595#else
596	orr	r12, r12, r3, lsr #8
597#endif
598	str	r12, [r0, #-4]!
599	subs	r2, r2, #4
600	bge	.Lmemmove_bsrcul1loop4
601
602.Lmemmove_bsrcul1l4:
603	add	r1, r1, #1
604	b	.Lmemmove_bl4
605#ifndef _BCOPY
606END(memmove)
607#else
608END(bcopy)
609#endif
610
611	.section .note.GNU-stack,"",%progbits
612