xref: /illumos-gate/usr/src/lib/libc/sparcv9/gen/memmove.S (revision f37b3cbb6f67aaea5eec1c335bdc7bf432867d64)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27	.file	"memmove.s"
28
29#include <sys/asm_linkage.h>
30
31	ANSI_PRAGMA_WEAK(memmove,function)
32
33/*
34 * memmove(s1, s2, len)
35 * Copy s2 to s1, always copy n bytes.
36 * For overlapped copies it does the right thing.
37 */
38	ENTRY(memmove)
39	save	%sp, -SA(MINFRAME), %sp		! not a leaf routine any more
40	mov	%i0, %l6	! Save pointer to destination
41	cmp	%i1, %i0	! if from address is >= to use forward copy
42	bgeu,a	%xcc, 2f	! else use backward if ...
43	cmp	%i2, 17		! delay slot, for small counts copy bytes
44
45	sub	%i0, %i1, %i4	! get difference of two addresses
46	cmp	%i2, %i4	! compare size and difference of addresses
47	bgu	%xcc, ovbc	! if size is bigger, have to do overlapped copy
48	cmp	%i2, 17		! delay slot, for small counts copy bytes
49	!
50	! normal, copy forwards
51	!
522:	ble	%xcc, dbytecp
53	andcc	%i1, 3, %i5		! is src word aligned
54	bz,pn	%icc, aldst
55	cmp	%i5, 2			! is src half-word aligned
56	be,pn	%icc, s2algn
57	cmp	%i5, 3			! src is byte aligned
58s1algn:	ldub	[%i1], %i3		! move 1 or 3 bytes to align it
59	inc	1, %i1
60	stb	%i3, [%i0]		! move a byte to align src
61	inc	1, %i0
62	bne,pn	%icc, s2algn
63	dec	%i2
64	b	ald			! now go align dest
65	andcc	%i0, 3, %i5
66
67s2algn:	lduh	[%i1], %i3		! know src is 2 byte alinged
68	inc	2, %i1
69	srl	%i3, 8, %i4
70	stb	%i4, [%i0]		! have to do bytes,
71	stb	%i3, [%i0 + 1]		! don't know dst alingment
72	inc	2, %i0
73	dec	2, %i2
74
75aldst:	andcc	%i0, 3, %i5		! align the destination address
76ald:	bz,pn	%icc, w4cp
77	cmp	%i5, 2
78	bz,pn	%icc, w2cp
79	cmp	%i5, 3
80w3cp:	lduw	[%i1], %i4
81	inc	4, %i1
82	srl	%i4, 24, %i5
83	stb	%i5, [%i0]
84	bne,pt	%icc, w1cp
85	inc	%i0
86	dec	1, %i2
87	andn	%i2, 3, %i3		! i3 is aligned word count
88	dec	4, %i3			! avoid reading beyond tail of src
89	sub	%i1, %i0, %i1		! i1 gets the difference
90
911:	sll	%i4, 8, %g1		! save residual bytes
92	lduw	[%i1+%i0], %i4
93	deccc	4, %i3
94	srl	%i4, 24, %i5		! merge with residual
95	or	%i5, %g1, %g1
96	st	%g1, [%i0]
97	bnz,pt	%xcc, 1b
98	inc	4, %i0
99	sub	%i1, 3, %i1		! used one byte of last word read
100	and	%i2, 3, %i2
101	b	7f
102	inc	4, %i2
103
104w1cp:	srl	%i4, 8, %i5
105	sth	%i5, [%i0]
106	inc	2, %i0
107	dec	3, %i2
108	andn	%i2, 3, %i3
109	dec	4, %i3			! avoid reading beyond tail of src
110	sub	%i1, %i0, %i1		! i1 gets the difference
111
1122:	sll	%i4, 24, %g1		! save residual bytes
113	lduw	[%i1+%i0], %i4
114	deccc	4, %i3
115	srl	%i4, 8, %i5		! merge with residual
116	or	%i5, %g1, %g1
117	st	%g1, [%i0]
118	bnz,pt	%xcc, 2b
119	inc	4, %i0
120	sub	%i1, 1, %i1		! used three bytes of last word read
121	and	%i2, 3, %i2
122	b	7f
123	inc	4, %i2
124
125w2cp:	lduw	[%i1], %i4
126	inc	4, %i1
127	srl	%i4, 16, %i5
128	sth	%i5, [%i0]
129	inc	2, %i0
130	dec	2, %i2
131	andn	%i2, 3, %i3		! i3 is aligned word count
132	dec	4, %i3			! avoid reading beyond tail of src
133	sub	%i1, %i0, %i1		! i1 gets the difference
134
1353:	sll	%i4, 16, %g1		! save residual bytes
136	lduw	[%i1+%i0], %i4
137	deccc	4, %i3
138	srl	%i4, 16, %i5		! merge with residual
139	or	%i5, %g1, %g1
140	st	%g1, [%i0]
141	bnz,pt	%xcc, 3b
142	inc	4, %i0
143	sub	%i1, 2, %i1		! used two bytes of last word read
144	and	%i2, 3, %i2
145	b	7f
146	inc	4, %i2
147
148w4cp:	andn	%i2, 3, %i3		! i3 is aligned word count
149	sub	%i1, %i0, %i1		! i1 gets the difference
150
1511:	lduw	[%i1+%i0], %i4		! read from address
152	deccc	4, %i3			! decrement count
153	st	%i4, [%i0]		! write at destination address
154	bg,pt	%xcc, 1b
155	inc	4, %i0			! increment to address
156	b	7f
157	and	%i2, 3, %i2		! number of leftover bytes, if any
158
159	!
160	! differenced byte copy, works with any alignment
161	!
162dbytecp:
163	b	7f
164	sub	%i1, %i0, %i1		! i1 gets the difference
165
1664:	stb	%i4, [%i0]		! write to address
167	inc	%i0			! inc to address
1687:	deccc	%i2			! decrement count
169	bge,a	%xcc, 4b		! loop till done
170	ldub	[%i1+%i0], %i4		! read from address
171	ret
172	restore %l6, %g0, %o0		! return pointer to destination
173
174	!
175	! an overlapped copy that must be done "backwards"
176	!
177ovbc:	add	%i1, %i2, %i1		! get to end of source space
178	add	%i0, %i2, %i0		! get to end of destination space
179	sub	%i1, %i0, %i1		! i1 gets the difference
180
1815:	dec	%i0			! decrement to address
182	ldub	[%i1+%i0], %i3		! read a byte
183	deccc	%i2			! decrement count
184	bg,pt	%xcc, 5b		! loop until done
185	stb	%i3, [%i0]		! write byte
186	ret
187	restore %l6, %g0, %o0		! return pointer to destination
188
189	SET_SIZE(memmove)
190