xref: /titanic_51/usr/src/lib/libc/sparc/gen/memmove.s (revision 1c9de0c9325f9f5d3540e19a4ad3691e6d50c0f8)
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#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29	.file	"%M%"
30
31#include <sys/asm_linkage.h>
32
33	ANSI_PRAGMA_WEAK(memmove,function)
34
35/*
36 * memmove(s1, s2, len)
37 * Copy s2 to s1, always copy n bytes.
38 * For overlapped copies it does the right thing.
39 */
40	ENTRY(memmove)
41	save	%sp, -SA(MINFRAME), %sp		! not a leaf routine any more
42	mov	%i0, %l6	! Save pointer to destination
43	cmp	%i1, %i0	! if from address is >= to use forward copy
44	bgeu,a	2f		! else use backward if ...
45	cmp	%i2, 17		! delay slot, for small counts copy bytes
46
47	sub	%i0, %i1, %i4	! get difference of two addresses
48	cmp	%i2, %i4	! compare size and difference of addresses
49	bgu	ovbc		! if size is bigger, have do overlapped copy
50	cmp	%i2, 17		! delay slot, for small counts copy bytes
51	!
52	! normal, copy forwards
53	!
542:	ble	dbytecp
55	andcc	%i1, 3, %i5		! is src word aligned
56	bz	aldst
57	cmp	%i5, 2			! is src half-word aligned
58	be	s2algn
59	cmp	%i5, 3			! src is byte aligned
60s1algn:	ldub	[%i1], %i3		! move 1 or 3 bytes to align it
61	inc	1, %i1
62	stb	%i3, [%i0]		! move a byte to align src
63	inc	1, %i0
64	bne	s2algn
65	dec	%i2
66	b	ald			! now go align dest
67	andcc	%i0, 3, %i5
68
69s2algn:	lduh	[%i1], %i3		! know src is 2 byte alinged
70	inc	2, %i1
71	srl	%i3, 8, %i4
72	stb	%i4, [%i0]		! have to do bytes,
73	stb	%i3, [%i0 + 1]		! don't know dst alingment
74	inc	2, %i0
75	dec	2, %i2
76
77aldst:	andcc	%i0, 3, %i5		! align the destination address
78ald:	bz	w4cp
79	cmp	%i5, 2
80	bz	w2cp
81	cmp	%i5, 3
82w3cp:	ld	[%i1], %i4
83	inc	4, %i1
84	srl	%i4, 24, %i5
85	stb	%i5, [%i0]
86	bne	w1cp
87	inc	%i0
88	dec	1, %i2
89	andn	%i2, 3, %i3		! i3 is aligned word count
90	dec	4, %i3			! avoid reading beyond tail of src
91	sub	%i1, %i0, %i1		! i1 gets the difference
92
931:	sll	%i4, 8, %g1		! save residual bytes
94	ld	[%i1+%i0], %i4
95	deccc	4, %i3
96	srl	%i4, 24, %i5		! merge with residual
97	or	%i5, %g1, %g1
98	st	%g1, [%i0]
99	bnz	1b
100	inc	4, %i0
101	sub	%i1, 3, %i1		! used one byte of last word read
102	and	%i2, 3, %i2
103	b	7f
104	inc	4, %i2
105
106w1cp:	srl	%i4, 8, %i5
107	sth	%i5, [%i0]
108	inc	2, %i0
109	dec	3, %i2
110	andn	%i2, 3, %i3
111	dec	4, %i3			! avoid reading beyond tail of src
112	sub	%i1, %i0, %i1		! i1 gets the difference
113
1142:	sll	%i4, 24, %g1		! save residual bytes
115	ld	[%i1+%i0], %i4
116	deccc	4, %i3
117	srl	%i4, 8, %i5		! merge with residual
118	or	%i5, %g1, %g1
119	st	%g1, [%i0]
120	bnz	2b
121	inc	4, %i0
122	sub	%i1, 1, %i1		! used three bytes of last word read
123	and	%i2, 3, %i2
124	b	7f
125	inc	4, %i2
126
127w2cp:	ld	[%i1], %i4
128	inc	4, %i1
129	srl	%i4, 16, %i5
130	sth	%i5, [%i0]
131	inc	2, %i0
132	dec	2, %i2
133	andn	%i2, 3, %i3		! i3 is aligned word count
134	dec	4, %i3			! avoid reading beyond tail of src
135	sub	%i1, %i0, %i1		! i1 gets the difference
136
1373:	sll	%i4, 16, %g1		! save residual bytes
138	ld	[%i1+%i0], %i4
139	deccc	4, %i3
140	srl	%i4, 16, %i5		! merge with residual
141	or	%i5, %g1, %g1
142	st	%g1, [%i0]
143	bnz	3b
144	inc	4, %i0
145	sub	%i1, 2, %i1		! used two bytes of last word read
146	and	%i2, 3, %i2
147	b	7f
148	inc	4, %i2
149
150w4cp:	andn	%i2, 3, %i3		! i3 is aligned word count
151	sub	%i1, %i0, %i1		! i1 gets the difference
152
1531:	ld	[%i1+%i0], %i4		! read from address
154	deccc	4, %i3			! decrement count
155	st	%i4, [%i0]		! write at destination address
156	bg	1b
157	inc	4, %i0			! increment to address
158	b	7f
159	and	%i2, 3, %i2		! number of leftover bytes, if any
160
161	!
162	! differenced byte copy, works with any alignment
163	!
164dbytecp:
165	b	7f
166	sub	%i1, %i0, %i1		! i1 gets the difference
167
1684:	stb	%i4, [%i0]		! write to address
169	inc	%i0			! inc to address
1707:	deccc	%i2			! decrement count
171	bge,a	4b			! loop till done
172	ldub	[%i1+%i0], %i4		! read from address
173	ret
174	restore %l6, %g0, %o0		! return pointer to destination
175
176	!
177	! an overlapped copy that must be done "backwards"
178	!
179ovbc:	add	%i1, %i2, %i1		! get to end of source space
180	add	%i0, %i2, %i0		! get to end of destination space
181	sub	%i1, %i0, %i1		! i1 gets the difference
182
1835:	dec	%i0			! decrement to address
184	ldub	[%i1+%i0], %i3		! read a byte
185	deccc	%i2			! decrement count
186	bg	5b			! loop until done
187	stb	%i3, [%i0]		! write byte
188	ret
189	restore %l6, %g0, %o0		! return pointer to destination
190
191	SET_SIZE(memmove)
192