Blame sysdeps/sparc/sparc64/memmove.S

Packit 6c4009
/* Copy memory to memory until the specified number of bytes
Packit 6c4009
   has been copied.  Overlap is handled correctly.
Packit 6c4009
   For SPARC V9.
Packit 6c4009
   Copyright (C) 2017-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
Packit 6c4009
#ifndef XCC
Packit 6c4009
# define XCC    xcc
Packit 6c4009
	.register	%g2, #scratch
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
ENTRY(memmove)
Packit 6c4009
	mov	%o0, %g2	/* Save pointer to destination  */
Packit 6c4009
	cmp	%o1, %o0	/* if from address is >= to use forward copy  */
Packit 6c4009
	bgeu,a	%XCC, 2f	/* else use backward if ...  */
Packit 6c4009
	 cmp	%o2, 17		/* delay slot, for small counts copy bytes  */
Packit 6c4009
Packit 6c4009
	sub	%o0, %o1, %o4	/* get difference of two addresses  */
Packit 6c4009
	cmp	%o2, %o4	/* compare size and difference of addresses  */
Packit 6c4009
	bgu	%XCC, .Lovbc	/* if size is bigger, have to do overlapped copy  */
Packit 6c4009
	 cmp	%o2, 17		/* delay slot, for small counts copy bytes  */
Packit 6c4009
/*
Packit 6c4009
 * normal, copy forwards
Packit 6c4009
 */
Packit 6c4009
2:	ble	%XCC, .Ldbytecp
Packit 6c4009
	 andcc	%o1, 3, %o5	/* is src word aligned  */
Packit 6c4009
	bz,pn	%icc, .Laldst
Packit 6c4009
	 cmp	%o5, 2		/* is src half-word aligned  */
Packit 6c4009
	be,pn	%icc, .Ls2alg
Packit 6c4009
	 cmp	%o5, 3		/* src is byte aligned  */
Packit 6c4009
	ldub	[%o1], %o3	/* move 1 or 3 bytes to align it  */
Packit 6c4009
	inc	1, %o1
Packit 6c4009
	stb	%o3, [%o0]	/* move a byte to align src  */
Packit 6c4009
	inc	1, %o0
Packit 6c4009
	bne,pn	%icc, .Ls2alg
Packit 6c4009
	 dec	%o2
Packit 6c4009
	b	.Lald		/* now go align dest  */
Packit 6c4009
	 andcc	%o0, 3, %o5
Packit 6c4009
Packit 6c4009
.Ls2alg:
Packit 6c4009
	lduh	[%o1], %o3	/* know src is 2 byte aligned  */
Packit 6c4009
	inc	2, %o1
Packit 6c4009
	srl	%o3, 8, %o4
Packit 6c4009
	stb	%o4, [%o0]	/* have to do bytes,  */
Packit 6c4009
	stb	%o3, [%o0 + 1]	/* don't know dst alingment  */
Packit 6c4009
	inc	2, %o0
Packit 6c4009
	dec	2, %o2
Packit 6c4009
Packit 6c4009
.Laldst:
Packit 6c4009
	andcc	%o0, 3, %o5	/* align the destination address  */
Packit 6c4009
.Lald:	bz,pn	%icc, .Lw4cp
Packit 6c4009
	 cmp	%o5, 2
Packit 6c4009
	bz,pn	%icc, .Lw2cp
Packit 6c4009
	 cmp	%o5, 3
Packit 6c4009
.Lw3cp:
Packit 6c4009
	lduw	[%o1], %o4
Packit 6c4009
	inc	4, %o1
Packit 6c4009
	srl	%o4, 24, %o5
Packit 6c4009
	stb	%o5, [%o0]
Packit 6c4009
	bne,pt	%icc, .Lw1cp
Packit 6c4009
	 inc	%o0
Packit 6c4009
	dec	1, %o2
Packit 6c4009
	andn	%o2, 3, %o3	/* i3 is aligned word count  */
Packit 6c4009
	dec	4, %o3		/* avoid reading beyond tail of src  */
Packit 6c4009
	sub	%o1, %o0, %o1	/* i1 gets the difference  */
Packit 6c4009
Packit 6c4009
1:	sll	%o4, 8, %g1	/* save residual bytes  */
Packit 6c4009
	lduw	[%o1+%o0], %o4
Packit 6c4009
	deccc	4, %o3
Packit 6c4009
	srl	%o4, 24, %o5	/* merge with residual  */
Packit 6c4009
	or	%o5, %g1, %g1
Packit 6c4009
	st	%g1, [%o0]
Packit 6c4009
	bnz,pt	%XCC, 1b
Packit 6c4009
	 inc	4, %o0
Packit 6c4009
	sub	%o1, 3, %o1	/* used one byte of last word read  */
Packit 6c4009
	and	%o2, 3, %o2
Packit 6c4009
	b	7f
Packit 6c4009
	 inc	4, %o2
Packit 6c4009
Packit 6c4009
.Lw1cp:
Packit 6c4009
	srl	%o4, 8, %o5
Packit 6c4009
	sth	%o5, [%o0]
Packit 6c4009
	inc	2, %o0
Packit 6c4009
	dec	3, %o2
Packit 6c4009
	andn	%o2, 3, %o3
Packit 6c4009
	dec	4, %o3		/* avoid reading beyond tail of src  */
Packit 6c4009
	sub	%o1, %o0, %o1	/* i1 gets the difference  */
Packit 6c4009
Packit 6c4009
2:	sll	%o4, 24, %g1	/* save residual bytes  */
Packit 6c4009
	lduw	[%o1+%o0], %o4
Packit 6c4009
	deccc	4, %o3
Packit 6c4009
	srl	%o4, 8, %o5	/* merge with residual  */
Packit 6c4009
	or	%o5, %g1, %g1
Packit 6c4009
	st	%g1, [%o0]
Packit 6c4009
	bnz,pt	%XCC, 2b
Packit 6c4009
	 inc	4, %o0
Packit 6c4009
	sub	%o1, 1, %o1	/* used three bytes of last word read  */
Packit 6c4009
	and	%o2, 3, %o2
Packit 6c4009
	b	7f
Packit 6c4009
	inc	4, %o2
Packit 6c4009
Packit 6c4009
.Lw2cp:
Packit 6c4009
	lduw	[%o1], %o4
Packit 6c4009
	inc	4, %o1
Packit 6c4009
	srl	%o4, 16, %o5
Packit 6c4009
	sth	%o5, [%o0]
Packit 6c4009
	inc	2, %o0
Packit 6c4009
	dec	2, %o2
Packit 6c4009
	andn	%o2, 3, %o3	/* i3 is aligned word count  */
Packit 6c4009
	dec	4, %o3		/* avoid reading beyond tail of src  */
Packit 6c4009
	sub	%o1, %o0, %o1	/* i1 gets the difference  */
Packit 6c4009
Packit 6c4009
3:	sll	%o4, 16, %g1	/* save residual bytes  */
Packit 6c4009
	lduw	[%o1+%o0], %o4
Packit 6c4009
	deccc	4, %o3
Packit 6c4009
	srl	%o4, 16, %o5	/* merge with residual  */
Packit 6c4009
	or	%o5, %g1, %g1
Packit 6c4009
	st	%g1, [%o0]
Packit 6c4009
	bnz,pt	%XCC, 3b
Packit 6c4009
	 inc	4, %o0
Packit 6c4009
	sub	%o1, 2, %o1	/* used two bytes of last word read  */
Packit 6c4009
	and	%o2, 3, %o2
Packit 6c4009
	b	7f
Packit 6c4009
	 inc	4, %o2
Packit 6c4009
Packit 6c4009
.Lw4cp:
Packit 6c4009
	andn	%o2, 3, %o3	/* i3 is aligned word count  */
Packit 6c4009
	sub	%o1, %o0, %o1	/* i1 gets the difference  */
Packit 6c4009
Packit 6c4009
1:	lduw	[%o1+%o0], %o4	/* read from address  */
Packit 6c4009
	deccc	4, %o3		/* decrement count  */
Packit 6c4009
	st	%o4, [%o0]	/* write at destination address  */
Packit 6c4009
	bg,pt	%XCC, 1b
Packit 6c4009
	 inc	4, %o0		/* increment to address  */
Packit 6c4009
	b	7f
Packit 6c4009
	 and	%o2, 3, %o2	/* number of leftover bytes, if any  */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * differenced byte copy, works with any alignment
Packit 6c4009
 */
Packit 6c4009
.Ldbytecp:
Packit 6c4009
	b	7f
Packit 6c4009
	 sub	%o1, %o0, %o1	/* i1 gets the difference  */
Packit 6c4009
Packit 6c4009
4:	stb	%o4, [%o0]	/* write to address  */
Packit 6c4009
	inc	%o0		/* inc to address  */
Packit 6c4009
7:	deccc	%o2		/* decrement count  */
Packit 6c4009
	bge,a	%XCC, 4b	/* loop till done  */
Packit 6c4009
	 ldub	[%o1+%o0], %o4	/* read from address  */
Packit 6c4009
	retl
Packit 6c4009
	 mov	%g2, %o0	/* return pointer to destination  */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * an overlapped copy that must be done "backwards"
Packit 6c4009
 */
Packit 6c4009
.Lovbc:
Packit 6c4009
	add	%o1, %o2, %o1	/* get to end of source space  */
Packit 6c4009
	add	%o0, %o2, %o0	/* get to end of destination space  */
Packit 6c4009
	sub	%o1, %o0, %o1	/* i1 gets the difference  */
Packit 6c4009
Packit 6c4009
5:	dec	%o0		/* decrement to address  */
Packit 6c4009
	ldub	[%o1+%o0], %o3	/* read a byte  */
Packit 6c4009
	deccc	%o2		/* decrement count  */
Packit 6c4009
	bg,pt	%XCC, 5b 	/* loop until done  */
Packit 6c4009
	 stb	%o3, [%o0]	/* write byte  */
Packit 6c4009
	retl
Packit 6c4009
	 mov	%g2, %o0	/* return pointer to destination  */
Packit 6c4009
END(memmove)
Packit 6c4009
Packit 6c4009
libc_hidden_builtin_def (memmove)