1/* Copy memory to memory until the specified number of bytes
2   has been copied.  Overlap is handled correctly.
3   For SPARC V9.
4   Copyright (C) 2017-2022 Free Software Foundation, Inc.
5   This file is part of the GNU C Library.
6
7   The GNU C Library is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Lesser General Public
9   License as published by the Free Software Foundation; either
10   version 2.1 of the License, or (at your option) any later version.
11
12   The GNU C Library is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public
18   License along with the GNU C Library; if not, see
19   <https://www.gnu.org/licenses/>.  */
20
21#include <sysdep.h>
22
23#ifndef XCC
24# define XCC    xcc
25	.register	%g2, #scratch
26#endif
27
28ENTRY(memmove)
29	mov	%o0, %g2	/* Save pointer to destination  */
30	cmp	%o1, %o0	/* if from address is >= to use forward copy  */
31	bgeu,a	%XCC, 2f	/* else use backward if ...  */
32	 cmp	%o2, 17		/* delay slot, for small counts copy bytes  */
33
34	sub	%o0, %o1, %o4	/* get difference of two addresses  */
35	cmp	%o2, %o4	/* compare size and difference of addresses  */
36	bgu	%XCC, .Lovbc	/* if size is bigger, have to do overlapped copy  */
37	 cmp	%o2, 17		/* delay slot, for small counts copy bytes  */
38/*
39 * normal, copy forwards
40 */
412:	ble	%XCC, .Ldbytecp
42	 andcc	%o1, 3, %o5	/* is src word aligned  */
43	bz,pn	%icc, .Laldst
44	 cmp	%o5, 2		/* is src half-word aligned  */
45	be,pn	%icc, .Ls2alg
46	 cmp	%o5, 3		/* src is byte aligned  */
47	ldub	[%o1], %o3	/* move 1 or 3 bytes to align it  */
48	inc	1, %o1
49	stb	%o3, [%o0]	/* move a byte to align src  */
50	inc	1, %o0
51	bne,pn	%icc, .Ls2alg
52	 dec	%o2
53	b	.Lald		/* now go align dest  */
54	 andcc	%o0, 3, %o5
55
56.Ls2alg:
57	lduh	[%o1], %o3	/* know src is 2 byte aligned  */
58	inc	2, %o1
59	srl	%o3, 8, %o4
60	stb	%o4, [%o0]	/* have to do bytes,  */
61	stb	%o3, [%o0 + 1]	/* don't know dst alingment  */
62	inc	2, %o0
63	dec	2, %o2
64
65.Laldst:
66	andcc	%o0, 3, %o5	/* align the destination address  */
67.Lald:	bz,pn	%icc, .Lw4cp
68	 cmp	%o5, 2
69	bz,pn	%icc, .Lw2cp
70	 cmp	%o5, 3
71.Lw3cp:
72	lduw	[%o1], %o4
73	inc	4, %o1
74	srl	%o4, 24, %o5
75	stb	%o5, [%o0]
76	bne,pt	%icc, .Lw1cp
77	 inc	%o0
78	dec	1, %o2
79	andn	%o2, 3, %o3	/* i3 is aligned word count  */
80	dec	4, %o3		/* avoid reading beyond tail of src  */
81	sub	%o1, %o0, %o1	/* i1 gets the difference  */
82
831:	sll	%o4, 8, %g1	/* save residual bytes  */
84	lduw	[%o1+%o0], %o4
85	deccc	4, %o3
86	srl	%o4, 24, %o5	/* merge with residual  */
87	or	%o5, %g1, %g1
88	st	%g1, [%o0]
89	bnz,pt	%XCC, 1b
90	 inc	4, %o0
91	sub	%o1, 3, %o1	/* used one byte of last word read  */
92	and	%o2, 3, %o2
93	b	7f
94	 inc	4, %o2
95
96.Lw1cp:
97	srl	%o4, 8, %o5
98	sth	%o5, [%o0]
99	inc	2, %o0
100	dec	3, %o2
101	andn	%o2, 3, %o3
102	dec	4, %o3		/* avoid reading beyond tail of src  */
103	sub	%o1, %o0, %o1	/* i1 gets the difference  */
104
1052:	sll	%o4, 24, %g1	/* save residual bytes  */
106	lduw	[%o1+%o0], %o4
107	deccc	4, %o3
108	srl	%o4, 8, %o5	/* merge with residual  */
109	or	%o5, %g1, %g1
110	st	%g1, [%o0]
111	bnz,pt	%XCC, 2b
112	 inc	4, %o0
113	sub	%o1, 1, %o1	/* used three bytes of last word read  */
114	and	%o2, 3, %o2
115	b	7f
116	inc	4, %o2
117
118.Lw2cp:
119	lduw	[%o1], %o4
120	inc	4, %o1
121	srl	%o4, 16, %o5
122	sth	%o5, [%o0]
123	inc	2, %o0
124	dec	2, %o2
125	andn	%o2, 3, %o3	/* i3 is aligned word count  */
126	dec	4, %o3		/* avoid reading beyond tail of src  */
127	sub	%o1, %o0, %o1	/* i1 gets the difference  */
128
1293:	sll	%o4, 16, %g1	/* save residual bytes  */
130	lduw	[%o1+%o0], %o4
131	deccc	4, %o3
132	srl	%o4, 16, %o5	/* merge with residual  */
133	or	%o5, %g1, %g1
134	st	%g1, [%o0]
135	bnz,pt	%XCC, 3b
136	 inc	4, %o0
137	sub	%o1, 2, %o1	/* used two bytes of last word read  */
138	and	%o2, 3, %o2
139	b	7f
140	 inc	4, %o2
141
142.Lw4cp:
143	andn	%o2, 3, %o3	/* i3 is aligned word count  */
144	sub	%o1, %o0, %o1	/* i1 gets the difference  */
145
1461:	lduw	[%o1+%o0], %o4	/* read from address  */
147	deccc	4, %o3		/* decrement count  */
148	st	%o4, [%o0]	/* write at destination address  */
149	bg,pt	%XCC, 1b
150	 inc	4, %o0		/* increment to address  */
151	b	7f
152	 and	%o2, 3, %o2	/* number of leftover bytes, if any  */
153
154/*
155 * differenced byte copy, works with any alignment
156 */
157.Ldbytecp:
158	b	7f
159	 sub	%o1, %o0, %o1	/* i1 gets the difference  */
160
1614:	stb	%o4, [%o0]	/* write to address  */
162	inc	%o0		/* inc to address  */
1637:	deccc	%o2		/* decrement count  */
164	bge,a	%XCC, 4b	/* loop till done  */
165	 ldub	[%o1+%o0], %o4	/* read from address  */
166	retl
167	 mov	%g2, %o0	/* return pointer to destination  */
168
169/*
170 * an overlapped copy that must be done "backwards"
171 */
172.Lovbc:
173	add	%o1, %o2, %o1	/* get to end of source space  */
174	add	%o0, %o2, %o0	/* get to end of destination space  */
175	sub	%o1, %o0, %o1	/* i1 gets the difference  */
176
1775:	dec	%o0		/* decrement to address  */
178	ldub	[%o1+%o0], %o3	/* read a byte  */
179	deccc	%o2		/* decrement count  */
180	bg,pt	%XCC, 5b 	/* loop until done  */
181	 stb	%o3, [%o0]	/* write byte  */
182	retl
183	 mov	%g2, %o0	/* return pointer to destination  */
184END(memmove)
185
186libc_hidden_builtin_def (memmove)
187